mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 10:52:53 +08:00
Initial implementation of limited distance snap
This commit is contained in:
parent
52dba69a64
commit
020b08b450
@ -153,7 +153,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
public new float DistanceSpacing => base.DistanceSpacing;
|
public new float DistanceSpacing => base.DistanceSpacing;
|
||||||
|
|
||||||
public TestOsuDistanceSnapGrid(OsuHitObject hitObject)
|
public TestOsuDistanceSnapGrid(OsuHitObject hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject, null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
{
|
{
|
||||||
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
|
||||||
{
|
{
|
||||||
public OsuDistanceSnapGrid(OsuHitObject hitObject)
|
public OsuDistanceSnapGrid(OsuHitObject hitObject, OsuHitObject nextHitObject)
|
||||||
: base(hitObject, hitObject.StackedEndPosition)
|
: base(hitObject, nextHitObject, hitObject.StackedEndPosition)
|
||||||
{
|
{
|
||||||
Masking = true;
|
Masking = true;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -60,25 +61,33 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
var objects = selectedHitObjects.ToList();
|
var objects = selectedHitObjects.ToList();
|
||||||
|
|
||||||
if (objects.Count == 0)
|
if (objects.Count == 0)
|
||||||
|
return createGrid(h => h.StartTime <= EditorClock.CurrentTime);
|
||||||
|
|
||||||
|
double minTime = objects.Min(h => h.StartTime);
|
||||||
|
return createGrid(h => h.StartTime < minTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OsuDistanceSnapGrid createGrid(Func<HitObject, bool> hitObjectSelector)
|
||||||
|
{
|
||||||
|
int lastIndex = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < EditorBeatmap.HitObjects.Count; i++)
|
||||||
{
|
{
|
||||||
var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime <= EditorClock.CurrentTime);
|
HitObject hitObject = EditorBeatmap.HitObjects[i];
|
||||||
|
|
||||||
if (lastObject == null)
|
if (!hitObjectSelector(hitObject))
|
||||||
return null;
|
break;
|
||||||
|
|
||||||
return new OsuDistanceSnapGrid(lastObject);
|
lastIndex = i;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
double minTime = objects.Min(h => h.StartTime);
|
|
||||||
|
|
||||||
var lastObject = EditorBeatmap.HitObjects.LastOrDefault(h => h.StartTime < minTime);
|
if (lastIndex == -1)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (lastObject == null)
|
OsuHitObject lastObject = EditorBeatmap.HitObjects[lastIndex];
|
||||||
return null;
|
OsuHitObject nextObject = lastIndex == EditorBeatmap.HitObjects.Count - 1 ? null : EditorBeatmap.HitObjects[lastIndex + 1];
|
||||||
|
|
||||||
return new OsuDistanceSnapGrid(lastObject);
|
return new OsuDistanceSnapGrid(lastObject, nextObject);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ namespace osu.Game.Tests.Visual.Editor
|
|||||||
public new float DistanceSpacing => base.DistanceSpacing;
|
public new float DistanceSpacing => base.DistanceSpacing;
|
||||||
|
|
||||||
public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
|
public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
|
||||||
: base(hitObject, centrePosition)
|
: base(hitObject, null, centrePosition)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
|
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
|
||||||
{
|
{
|
||||||
protected CircularDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
|
protected CircularDistanceSnapGrid(HitObject hitObject, HitObject nextHitObject, Vector2 centrePosition)
|
||||||
: base(hitObject, centrePosition)
|
: base(hitObject, nextHitObject, centrePosition)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X);
|
float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X);
|
||||||
float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y);
|
float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y);
|
||||||
float maxDistance = new Vector2(dx, dy).Length;
|
float maxDistance = new Vector2(dx, dy).Length;
|
||||||
int requiredCircles = (int)(maxDistance / DistanceSpacing);
|
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing));
|
||||||
|
|
||||||
for (int i = 0; i < requiredCircles; i++)
|
for (int i = 0; i < requiredCircles; i++)
|
||||||
{
|
{
|
||||||
@ -65,15 +65,17 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position)
|
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position)
|
||||||
{
|
{
|
||||||
Vector2 direction = position - CentrePosition;
|
if (MaxIntervals == 0)
|
||||||
|
return (CentrePosition, StartTime);
|
||||||
|
|
||||||
|
Vector2 direction = position - CentrePosition;
|
||||||
if (direction == Vector2.Zero)
|
if (direction == Vector2.Zero)
|
||||||
direction = new Vector2(0.001f, 0.001f);
|
direction = new Vector2(0.001f, 0.001f);
|
||||||
|
|
||||||
float distance = direction.Length;
|
float distance = direction.Length;
|
||||||
|
|
||||||
float radius = DistanceSpacing;
|
float radius = DistanceSpacing;
|
||||||
int radialCount = Math.Max(1, (int)Math.Round(distance / radius));
|
int radialCount = MathHelper.Clamp((int)Math.Round(distance / radius), 1, MaxIntervals);
|
||||||
|
|
||||||
Vector2 normalisedDirection = direction * new Vector2(1f / distance);
|
Vector2 normalisedDirection = direction * new Vector2(1f / distance);
|
||||||
Vector2 snappedPosition = CentrePosition + normalisedDirection * radialCount * radius;
|
Vector2 snappedPosition = CentrePosition + normalisedDirection * radialCount * radius;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Caching;
|
using osu.Framework.Caching;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -29,6 +30,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected double StartTime { get; private set; }
|
protected double StartTime { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum number of distance snapping intervals allowed.
|
||||||
|
/// </summary>
|
||||||
|
protected int MaxIntervals { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The position which the grid is centred on.
|
/// The position which the grid is centred on.
|
||||||
/// The first beat snapping tick is located at <see cref="CentrePosition"/> + <see cref="DistanceSpacing"/> in the desired direction.
|
/// The first beat snapping tick is located at <see cref="CentrePosition"/> + <see cref="DistanceSpacing"/> in the desired direction.
|
||||||
@ -49,12 +55,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
private readonly Cached gridCache = new Cached();
|
private readonly Cached gridCache = new Cached();
|
||||||
private readonly HitObject hitObject;
|
private readonly HitObject hitObject;
|
||||||
|
private readonly HitObject nextHitObject;
|
||||||
|
|
||||||
protected DistanceSnapGrid(HitObject hitObject, Vector2 centrePosition)
|
protected DistanceSnapGrid(HitObject hitObject, [CanBeNull] HitObject nextHitObject, Vector2 centrePosition)
|
||||||
{
|
{
|
||||||
this.hitObject = hitObject;
|
this.hitObject = hitObject;
|
||||||
|
this.nextHitObject = nextHitObject;
|
||||||
|
|
||||||
CentrePosition = centrePosition;
|
CentrePosition = centrePosition;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +83,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private void updateSpacing()
|
private void updateSpacing()
|
||||||
{
|
{
|
||||||
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
|
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
|
||||||
|
|
||||||
|
if (nextHitObject == null)
|
||||||
|
MaxIntervals = int.MaxValue;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// +1 is added since a snapped hitobject may have its start time slightly less than the snapped time due to floating point errors
|
||||||
|
double maxDuration = nextHitObject.StartTime - StartTime + 1;
|
||||||
|
MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing));
|
||||||
|
}
|
||||||
|
|
||||||
gridCache.Invalidate();
|
gridCache.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user