1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 11:37:28 +08:00

Create SnapResult class to hold various snapping results

This commit is contained in:
Dean Herbert 2020-05-20 18:19:21 +09:00
parent 3354d48a38
commit c46bfc2532
10 changed files with 70 additions and 61 deletions

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 System;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Edit.Tools;
@ -45,12 +44,7 @@ namespace osu.Game.Rulesets.Mania.Edit
public int TotalColumns => Playfield.TotalColumns; public int TotalColumns => Playfield.TotalColumns;
public override (Vector2 position, double time) SnapPositionToValidTime(Vector2 position) public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
{
throw new NotImplementedException();
}
public override (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
{ {
var hoc = Playfield.GetColumn(0).HitObjectContainer; var hoc = Playfield.GetColumn(0).HitObjectContainer;
@ -69,7 +63,7 @@ namespace osu.Game.Rulesets.Mania.Edit
drawableRuleset.ScrollingInfo.TimeRange.Value, drawableRuleset.ScrollingInfo.TimeRange.Value,
hoc.DrawHeight); hoc.DrawHeight);
return (targetPosition, targetTime); return new SnapResult(targetPosition, targetTime);
} }
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null) protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)

View File

@ -174,9 +174,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private class SnapProvider : IPositionSnapProvider private class SnapProvider : IPositionSnapProvider
{ {
public (Vector2 position, double time) SnapPositionToValidTime(Vector2 position) => (position, 0); public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => new SnapResult(screenSpacePosition, 0);
public (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => (screenSpacePosition, 0);
public float GetBeatSnapDistanceAt(double referenceTime) => (float)beat_length; public float GetBeatSnapDistanceAt(double referenceTime) => (float)beat_length;

View File

@ -162,11 +162,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
if (ControlPoint == slider.Path.ControlPoints[0]) if (ControlPoint == slider.Path.ControlPoints[0])
{ {
// Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account // Special handling for the head control point - the position of the slider changes which means the snapped position and time have to be taken into account
(Vector2 snappedPosition, double snappedTime) = snapProvider?.SnapScreenSpacePositionToValidTime(e.MousePosition) ?? (e.MousePosition, slider.StartTime); var result = snapProvider?.SnapScreenSpacePositionToValidTime(e.MousePosition);
Vector2 movementDelta = snappedPosition - slider.Position; Vector2 movementDelta = (result?.ScreenSpacePosition ?? e.MousePosition) - slider.Position;
slider.Position += movementDelta; slider.Position += movementDelta;
slider.StartTime = snappedTime; slider.StartTime = result?.Time ?? slider.StartTime;
// Since control points are relative to the position of the slider, they all need to be offset backwards by the delta // Since control points are relative to the position of the slider, they all need to be offset backwards by the delta
for (int i = 1; i < slider.Path.ControlPoints.Count; i++) for (int i = 1; i < slider.Path.ControlPoints.Count; i++)

View File

@ -153,9 +153,7 @@ namespace osu.Game.Tests.Visual.Editing
private class SnapProvider : IPositionSnapProvider private class SnapProvider : IPositionSnapProvider
{ {
public (Vector2 position, double time) SnapPositionToValidTime(Vector2 position) => (position, 0); public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => new SnapResult(screenSpacePosition, 0);
public (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => (screenSpacePosition, 0);
public float GetBeatSnapDistanceAt(double referenceTime) => 10; public float GetBeatSnapDistanceAt(double referenceTime) => 10;

View File

@ -245,7 +245,8 @@ namespace osu.Game.Rulesets.Edit
{ {
EditorBeatmap.PlacementObject.Value = hitObject; EditorBeatmap.PlacementObject.Value = hitObject;
hitObject.StartTime = SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position).time; if (SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position).Time is double time)
hitObject.StartTime = time;
} }
public void EndPlacement(HitObject hitObject, bool commit) public void EndPlacement(HitObject hitObject, bool commit)
@ -264,11 +265,13 @@ namespace osu.Game.Rulesets.Edit
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject); public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
public override (Vector2 position, double time) SnapPositionToValidTime(Vector2 position) => public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
distanceSnapGrid?.GetSnappedPosition(position) ?? (position, 0); {
if (distanceSnapGrid == null) return new SnapResult(screenSpacePosition, null);
public override (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) (Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition));
=> SnapPositionToValidTime(drawableRulesetWrapper.Playfield.ToLocalSpace(screenSpacePosition)); return new SnapResult(distanceSnapGrid.ToScreenSpace(pos), time);
}
public override float GetBeatSnapDistanceAt(double referenceTime) public override float GetBeatSnapDistanceAt(double referenceTime)
{ {
@ -326,9 +329,7 @@ namespace osu.Game.Rulesets.Edit
[CanBeNull] [CanBeNull]
protected virtual DistanceSnapGrid CreateDistanceSnapGrid([NotNull] IEnumerable<HitObject> selectedHitObjects) => null; protected virtual DistanceSnapGrid CreateDistanceSnapGrid([NotNull] IEnumerable<HitObject> selectedHitObjects) => null;
public abstract (Vector2 position, double time) SnapPositionToValidTime(Vector2 position); public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
public abstract (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
public abstract float GetBeatSnapDistanceAt(double referenceTime); public abstract float GetBeatSnapDistanceAt(double referenceTime);

View File

@ -8,13 +8,11 @@ namespace osu.Game.Rulesets.Edit
public interface IPositionSnapProvider public interface IPositionSnapProvider
{ {
/// <summary> /// <summary>
/// Given a position (local to the provider), find a valid time snap /// Given a position, find a valid time snap.
/// </summary> /// </summary>
/// <param name="position">The local position to be snapped.</param> /// <param name="screenSpacePosition">The screen-space position to be snapped.</param>
/// <returns>The time and position post-snapping.</returns> /// <returns>The time and position post-snapping.</returns>
(Vector2 position, double time) SnapPositionToValidTime(Vector2 position); SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
(Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
/// <summary> /// <summary>
/// Retrieves the distance between two points within a timing point that are one beat length apart. /// Retrieves the distance between two points within a timing point that are one beat length apart.
@ -55,4 +53,23 @@ namespace osu.Game.Rulesets.Edit
/// <returns>A value that represents <paramref name="distance"/> snapped to the closest beat of the timing point.</returns> /// <returns>A value that represents <paramref name="distance"/> snapped to the closest beat of the timing point.</returns>
float GetSnappedDistanceFromDistance(double referenceTime, float distance); float GetSnappedDistanceFromDistance(double referenceTime, float distance);
} }
public class SnapResult
{
/// <summary>
/// The screen space position, potentially altered for snapping.
/// </summary>
public Vector2 ScreenSpacePosition;
/// <summary>
/// The resultant time for snapping, if a value could be attained.
/// </summary>
public double? Time;
public SnapResult(Vector2 screenSpacePosition, double? time)
{
ScreenSpacePosition = screenSpacePosition;
Time = time;
}
}
} }

View File

@ -405,16 +405,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
Vector2 movePosition = movementBlueprintOriginalPosition.Value + e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition; Vector2 movePosition = movementBlueprintOriginalPosition.Value + e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition;
// Retrieve a snapped position. // Retrieve a snapped position.
(Vector2 snappedPosition, double snappedTime) = snapProvider.SnapScreenSpacePositionToValidTime(movePosition); var result = snapProvider.SnapScreenSpacePositionToValidTime(movePosition);
// Move the hitobjects. // Move the hitobjects.
if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, ToScreenSpace(snappedPosition)))) if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, result.ScreenSpacePosition)))
return true; return true;
if (result.Time.HasValue)
{
// Apply the start time at the newly snapped-to position // Apply the start time at the newly snapped-to position
double offset = snappedTime - draggedObject.StartTime; double offset = result.Time.Value - draggedObject.StartTime;
foreach (HitObject obj in selectionHandler.SelectedHitObjects) foreach (HitObject obj in selectionHandler.SelectedHitObjects)
obj.StartTime += offset; obj.StartTime += offset;
}
return true; return true;
} }

View File

@ -67,7 +67,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
private void updatePlacementPosition(Vector2 screenSpacePosition) private void updatePlacementPosition(Vector2 screenSpacePosition)
{ {
Vector2 snappedPlayfieldPosition = composer.SnapScreenSpacePositionToValidTime(screenSpacePosition).position; Vector2 snappedPlayfieldPosition = composer.SnapScreenSpacePositionToValidTime(screenSpacePosition).ScreenSpacePosition;
currentPlacement.UpdatePosition(ToScreenSpace(snappedPlayfieldPosition)); currentPlacement.UpdatePosition(ToScreenSpace(snappedPlayfieldPosition));
} }

View File

@ -181,11 +181,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
[Resolved] [Resolved]
private IBeatSnapProvider beatSnapProvider { get; set; } private IBeatSnapProvider beatSnapProvider { get; set; }
public (Vector2 position, double time) SnapPositionToValidTime(Vector2 position) => public SnapResult SnapScreenSpacePositionToValidTime(Vector2 position) =>
(position, beatSnapProvider.SnapTime(getTimeFromPosition(position))); new SnapResult(position, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(position))));
public (Vector2 position, double time) SnapScreenSpacePositionToValidTime(Vector2 position) =>
(position, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(position))));
private double getTimeFromPosition(Vector2 localPosition) => private double getTimeFromPosition(Vector2 localPosition) =>
(localPosition.X / Content.DrawWidth) * track.Length; (localPosition.X / Content.DrawWidth) * track.Length;

View File

@ -275,8 +275,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
OnDragHandled?.Invoke(e); OnDragHandled?.Invoke(e);
var time = timeline.SnapScreenSpacePositionToValidTime(e.ScreenSpaceMousePosition).time; if (timeline.SnapScreenSpacePositionToValidTime(e.ScreenSpaceMousePosition).Time is double time)
{
switch (hitObject) switch (hitObject)
{ {
case IHasRepeats repeatHitObject: case IHasRepeats repeatHitObject:
@ -302,6 +302,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
beatmap.UpdateHitObject(hitObject); beatmap.UpdateHitObject(hitObject);
} }
}
protected override void OnDragEnd(DragEndEvent e) protected override void OnDragEnd(DragEndEvent e)
{ {