Refactor distance snap grid to not require hitobjects

This commit is contained in:
smoogipoo
2019-12-10 16:00:09 +09:00
parent 1ba59d6d5f
commit 94a298a82d
4 changed files with 52 additions and 57 deletions

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.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit.Compose.Components; using osu.Game.Screens.Edit.Compose.Components;
@ -8,8 +9,8 @@ namespace osu.Game.Rulesets.Osu.Edit
{ {
public class OsuDistanceSnapGrid : CircularDistanceSnapGrid public class OsuDistanceSnapGrid : CircularDistanceSnapGrid
{ {
public OsuDistanceSnapGrid(OsuHitObject hitObject, OsuHitObject nextHitObject) public OsuDistanceSnapGrid(OsuHitObject hitObject, [CanBeNull] OsuHitObject nextHitObject = null)
: base(hitObject, nextHitObject, hitObject.StackedEndPosition) : base(hitObject.StackedPosition, hitObject.StartTime, nextHitObject?.StartTime)
{ {
Masking = true; Masking = true;
} }

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.Edit; using osu.Game.Screens.Edit;
@ -44,7 +43,7 @@ namespace osu.Game.Tests.Visual.Editor
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.SlateGray Colour = Color4.SlateGray
}, },
new TestDistanceSnapGrid(new HitObject(), grid_position) new TestDistanceSnapGrid()
}; };
}); });
@ -73,7 +72,7 @@ namespace osu.Game.Tests.Visual.Editor
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.SlateGray Colour = Color4.SlateGray
}, },
new TestDistanceSnapGrid(new HitObject(), grid_position, new HitObject { StartTime = 100 }) new TestDistanceSnapGrid(100)
}; };
}); });
} }
@ -82,68 +81,68 @@ namespace osu.Game.Tests.Visual.Editor
{ {
public new float DistanceSpacing => base.DistanceSpacing; public new float DistanceSpacing => base.DistanceSpacing;
public TestDistanceSnapGrid(HitObject hitObject, Vector2 centrePosition, HitObject nextHitObject = null) public TestDistanceSnapGrid(double? endTime = null)
: base(hitObject, nextHitObject, centrePosition) : base(grid_position, 0, endTime)
{ {
} }
protected override void CreateContent(Vector2 centrePosition) protected override void CreateContent(Vector2 startPosition)
{ {
AddInternal(new Circle AddInternal(new Circle
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(5), Size = new Vector2(5),
Position = centrePosition Position = startPosition
}); });
int beatIndex = 0; int beatIndex = 0;
for (float s = centrePosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++) for (float s = startPosition.X + DistanceSpacing; s <= DrawWidth && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
{ {
AddInternal(new Circle AddInternal(new Circle
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(5, 10), Size = new Vector2(5, 10),
Position = new Vector2(s, centrePosition.Y), Position = new Vector2(s, startPosition.Y),
Colour = GetColourForBeatIndex(beatIndex) Colour = GetColourForBeatIndex(beatIndex)
}); });
} }
beatIndex = 0; beatIndex = 0;
for (float s = centrePosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++) for (float s = startPosition.X - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
{ {
AddInternal(new Circle AddInternal(new Circle
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(5, 10), Size = new Vector2(5, 10),
Position = new Vector2(s, centrePosition.Y), Position = new Vector2(s, startPosition.Y),
Colour = GetColourForBeatIndex(beatIndex) Colour = GetColourForBeatIndex(beatIndex)
}); });
} }
beatIndex = 0; beatIndex = 0;
for (float s = centrePosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++) for (float s = startPosition.Y + DistanceSpacing; s <= DrawHeight && beatIndex < MaxIntervals; s += DistanceSpacing, beatIndex++)
{ {
AddInternal(new Circle AddInternal(new Circle
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(10, 5), Size = new Vector2(10, 5),
Position = new Vector2(centrePosition.X, s), Position = new Vector2(startPosition.X, s),
Colour = GetColourForBeatIndex(beatIndex) Colour = GetColourForBeatIndex(beatIndex)
}); });
} }
beatIndex = 0; beatIndex = 0;
for (float s = centrePosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++) for (float s = startPosition.Y - DistanceSpacing; s >= 0 && beatIndex < MaxIntervals; s -= DistanceSpacing, beatIndex++)
{ {
AddInternal(new Circle AddInternal(new Circle
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(10, 5), Size = new Vector2(10, 5),
Position = new Vector2(centrePosition.X, s), Position = new Vector2(startPosition.X, s),
Colour = GetColourForBeatIndex(beatIndex) Colour = GetColourForBeatIndex(beatIndex)
}); });
} }

View File

@ -5,19 +5,18 @@ using System;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Rulesets.Objects;
using osuTK; using osuTK;
namespace osu.Game.Screens.Edit.Compose.Components namespace osu.Game.Screens.Edit.Compose.Components
{ {
public abstract class CircularDistanceSnapGrid : DistanceSnapGrid public abstract class CircularDistanceSnapGrid : DistanceSnapGrid
{ {
protected CircularDistanceSnapGrid(HitObject hitObject, HitObject nextHitObject, Vector2 centrePosition) protected CircularDistanceSnapGrid(Vector2 startPosition, double startTime, double? endTime = null)
: base(hitObject, nextHitObject, centrePosition) : base(startPosition, startTime, endTime)
{ {
} }
protected override void CreateContent(Vector2 centrePosition) protected override void CreateContent(Vector2 startPosition)
{ {
const float crosshair_thickness = 1; const float crosshair_thickness = 1;
const float crosshair_max_size = 10; const float crosshair_max_size = 10;
@ -27,7 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
new Box new Box
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = centrePosition, Position = startPosition,
Width = crosshair_thickness, Width = crosshair_thickness,
EdgeSmoothness = new Vector2(1), EdgeSmoothness = new Vector2(1),
Height = Math.Min(crosshair_max_size, DistanceSpacing * 2), Height = Math.Min(crosshair_max_size, DistanceSpacing * 2),
@ -35,15 +34,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
new Box new Box
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = centrePosition, Position = startPosition,
EdgeSmoothness = new Vector2(1), EdgeSmoothness = new Vector2(1),
Width = Math.Min(crosshair_max_size, DistanceSpacing * 2), Width = Math.Min(crosshair_max_size, DistanceSpacing * 2),
Height = crosshair_thickness, Height = crosshair_thickness,
} }
}); });
float dx = Math.Max(centrePosition.X, DrawWidth - centrePosition.X); float dx = Math.Max(startPosition.X, DrawWidth - startPosition.X);
float dy = Math.Max(centrePosition.Y, DrawHeight - centrePosition.Y); float dy = Math.Max(startPosition.Y, DrawHeight - startPosition.Y);
float maxDistance = new Vector2(dx, dy).Length; float maxDistance = new Vector2(dx, dy).Length;
int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing)); int requiredCircles = Math.Min(MaxIntervals, (int)(maxDistance / DistanceSpacing));
@ -54,7 +53,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
AddInternal(new CircularProgress AddInternal(new CircularProgress
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Position = centrePosition, Position = startPosition,
Current = { Value = 1 }, Current = { Value = 1 },
Size = new Vector2(radius), Size = new Vector2(radius),
InnerRadius = 4 * 1f / radius, InnerRadius = 4 * 1f / radius,
@ -66,9 +65,9 @@ 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)
{ {
if (MaxIntervals == 0) if (MaxIntervals == 0)
return (CentrePosition, StartTime); return (StartPosition, StartTime);
Vector2 direction = position - CentrePosition; Vector2 direction = position - StartPosition;
if (direction == Vector2.Zero) if (direction == Vector2.Zero)
direction = new Vector2(0.001f, 0.001f); direction = new Vector2(0.001f, 0.001f);
@ -78,9 +77,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
int radialCount = Math.Clamp((int)MathF.Round(distance / radius), 1, MaxIntervals); int radialCount = Math.Clamp((int)MathF.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 = StartPosition + normalisedDirection * radialCount * radius;
return (snappedPosition, StartTime + SnapProvider.GetSnappedDurationFromDistance(StartTime, (snappedPosition - CentrePosition).Length)); return (snappedPosition, StartTime + SnapProvider.GetSnappedDurationFromDistance(StartTime, (snappedPosition - StartPosition).Length));
} }
} }
} }

View File

@ -1,7 +1,6 @@
// 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;
@ -9,7 +8,6 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osuTK; using osuTK;
namespace osu.Game.Screens.Edit.Compose.Components namespace osu.Game.Screens.Edit.Compose.Components
@ -24,21 +22,21 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// </summary> /// </summary>
protected float DistanceSpacing { get; private set; } protected float DistanceSpacing { get; private set; }
/// <summary>
/// The snapping time at <see cref="CentrePosition"/>.
/// </summary>
protected double StartTime { get; private set; }
/// <summary> /// <summary>
/// The maximum number of distance snapping intervals allowed. /// The maximum number of distance snapping intervals allowed.
/// </summary> /// </summary>
protected int MaxIntervals { get; private set; } protected int MaxIntervals { get; private set; }
/// <summary> /// <summary>
/// The position which the grid is centred on. /// The position which the grid should start.
/// 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="StartPosition"/> + <see cref="DistanceSpacing"/> away from this point.
/// </summary> /// </summary>
protected readonly Vector2 CentrePosition; protected readonly Vector2 StartPosition;
/// <summary>
/// The snapping time at <see cref="StartPosition"/>.
/// </summary>
protected readonly double StartTime;
[Resolved] [Resolved]
protected OsuColour Colours { get; private set; } protected OsuColour Colours { get; private set; }
@ -53,25 +51,23 @@ namespace osu.Game.Screens.Edit.Compose.Components
private BindableBeatDivisor beatDivisor { get; set; } private BindableBeatDivisor beatDivisor { get; set; }
private readonly Cached gridCache = new Cached(); private readonly Cached gridCache = new Cached();
private readonly HitObject hitObject; private readonly double? endTime;
private readonly HitObject nextHitObject;
protected DistanceSnapGrid(HitObject hitObject, [CanBeNull] HitObject nextHitObject, Vector2 centrePosition) /// <summary>
/// Creates a new <see cref="DistanceSnapGrid"/>.
/// </summary>
/// <param name="startPosition">The position at which the grid should start. The first tick is located one distance spacing length away from this point.</param>
/// <param name="startTime">The snapping time at <see cref="StartPosition"/>.</param>
/// <param name="endTime">The time at which the snapping grid should end. If null, the grid will continue until the bounds of the screen are exceeded.</param>
protected DistanceSnapGrid(Vector2 startPosition, double startTime, double? endTime = null)
{ {
this.hitObject = hitObject; this.endTime = endTime;
this.nextHitObject = nextHitObject; StartPosition = startPosition;
StartTime = startTime;
CentrePosition = centrePosition;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
} }
[BackgroundDependencyLoader]
private void load()
{
StartTime = hitObject.GetEndTime();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -83,12 +79,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
{ {
DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime); DistanceSpacing = SnapProvider.GetBeatSnapDistanceAt(StartTime);
if (nextHitObject == null) if (endTime == null)
MaxIntervals = int.MaxValue; MaxIntervals = int.MaxValue;
else else
{ {
// +1 is added since a snapped hitobject may have its start time slightly less than the snapped time due to floating point errors // +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; double maxDuration = endTime.Value - StartTime + 1;
MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing)); MaxIntervals = (int)(maxDuration / SnapProvider.DistanceToDuration(StartTime, DistanceSpacing));
} }
@ -110,7 +106,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (!gridCache.IsValid) if (!gridCache.IsValid)
{ {
ClearInternal(); ClearInternal();
CreateContent(CentrePosition); CreateContent(StartPosition);
gridCache.Validate(); gridCache.Validate();
} }
} }
@ -118,7 +114,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
/// <summary> /// <summary>
/// Creates the content which visualises the grid ticks. /// Creates the content which visualises the grid ticks.
/// </summary> /// </summary>
protected abstract void CreateContent(Vector2 centrePosition); protected abstract void CreateContent(Vector2 startPosition);
/// <summary> /// <summary>
/// Snaps a position to this grid. /// Snaps a position to this grid.