1
0
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:
smoogipoo 2019-11-06 14:55:05 +09:00
parent 52dba69a64
commit 020b08b450
6 changed files with 52 additions and 22 deletions

View File

@ -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)
{ {
} }
} }

View File

@ -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;
} }

View File

@ -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);
}
} }
} }
} }

View File

@ -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)
{ {
} }

View File

@ -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;

View File

@ -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();
} }