mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 08:33:21 +08:00
Merge pull request #22265 from Wleter/SliderEnd-Snap
Add snapping sliderends with nearby objects
This commit is contained in:
commit
3cd810f332
@ -22,6 +22,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector2 PathStartLocation => body.PathOffset;
|
public Vector2 PathStartLocation => body.PathOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset in absolute (local) coordinates from the end of the curve.
|
||||||
|
/// </summary>
|
||||||
|
public Vector2 PathEndLocation => body.PathEndOffset;
|
||||||
|
|
||||||
public SliderBodyPiece()
|
public SliderBodyPiece()
|
||||||
{
|
{
|
||||||
InternalChild = body = new ManualSliderBody
|
InternalChild = body = new ManualSliderBody
|
||||||
|
@ -409,6 +409,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset)
|
public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathOffset)
|
||||||
?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation);
|
?? BodyPiece.ToScreenSpace(BodyPiece.PathStartLocation);
|
||||||
|
|
||||||
|
protected override Vector2[] ScreenSpaceAdditionalNodes => new[]
|
||||||
|
{
|
||||||
|
DrawableObject.SliderBody?.ToScreenSpace(DrawableObject.SliderBody.PathEndOffset) ?? BodyPiece.ToScreenSpace(BodyPiece.PathEndLocation)
|
||||||
|
};
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
||||||
BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true;
|
BodyPiece.ReceivePositionalInputAt(screenSpacePos) || ControlPointVisualiser?.Pieces.Any(p => p.ReceivePositionalInputAt(screenSpacePos)) == true;
|
||||||
|
|
||||||
|
@ -31,6 +31,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Vector2 PathOffset => path.PositionInBoundingBox(path.Vertices[0]);
|
public virtual Vector2 PathOffset => path.PositionInBoundingBox(path.Vertices[0]);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Offset in absolute coordinates from the end of the curve.
|
||||||
|
/// </summary>
|
||||||
|
public virtual Vector2 PathEndOffset => path.PositionInBoundingBox(path.Vertices[^1]);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to colour the path.
|
/// Used to colour the path.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,6 +43,8 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
public override Vector2 PathOffset => snakedPathOffset;
|
public override Vector2 PathOffset => snakedPathOffset;
|
||||||
|
|
||||||
|
public override Vector2 PathEndOffset => snakedPathEndOffset;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The top-left position of the path when fully snaked.
|
/// The top-left position of the path when fully snaked.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -53,6 +55,11 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private Vector2 snakedPathOffset;
|
private Vector2 snakedPathOffset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The offset of the end of path from <see cref="snakedPosition"/> when fully snaked.
|
||||||
|
/// </summary>
|
||||||
|
private Vector2 snakedPathEndOffset;
|
||||||
|
|
||||||
private DrawableSlider drawableSlider = null!;
|
private DrawableSlider drawableSlider = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
@ -109,6 +116,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
|||||||
|
|
||||||
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
|
snakedPosition = Path.PositionInBoundingBox(Vector2.Zero);
|
||||||
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
|
snakedPathOffset = Path.PositionInBoundingBox(Path.Vertices[0]);
|
||||||
|
snakedPathEndOffset = Path.PositionInBoundingBox(Path.Vertices[^1]);
|
||||||
|
|
||||||
double lastSnakedStart = SnakedStart ?? 0;
|
double lastSnakedStart = SnakedStart ?? 0;
|
||||||
double lastSnakedEnd = SnakedEnd ?? 0;
|
double lastSnakedEnd = SnakedEnd ?? 0;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -125,10 +126,21 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
public virtual MenuItem[] ContextMenuItems => Array.Empty<MenuItem>();
|
public virtual MenuItem[] ContextMenuItems => Array.Empty<MenuItem>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The screen-space point that causes this <see cref="HitObjectSelectionBlueprint"/> to be selected via a drag.
|
/// The screen-space main point that causes this <see cref="HitObjectSelectionBlueprint"/> to be selected via a drag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre;
|
public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Any points that should be used for snapping purposes in addition to <see cref="ScreenSpaceSelectionPoint"/>. Exposed via <see cref="ScreenSpaceSnapPoints"/>.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual Vector2[] ScreenSpaceAdditionalNodes => Array.Empty<Vector2>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The screen-space collection of base points on this <see cref="HitObjectSelectionBlueprint"/> that other objects can be snapped to.
|
||||||
|
/// The first element of this collection is <see cref="ScreenSpaceSelectionPoint"/>
|
||||||
|
/// </summary>
|
||||||
|
public Vector2[] ScreenSpaceSnapPoints => ScreenSpaceAdditionalNodes.Prepend(ScreenSpaceSelectionPoint).ToArray();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The screen-space quad that outlines this <see cref="HitObjectSelectionBlueprint"/> for selections.
|
/// The screen-space quad that outlines this <see cref="HitObjectSelectionBlueprint"/> for selections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -439,7 +439,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
#region Selection Movement
|
#region Selection Movement
|
||||||
|
|
||||||
private Vector2[] movementBlueprintOriginalPositions;
|
private Vector2[][] movementBlueprintsOriginalPositions;
|
||||||
private SelectionBlueprint<T>[] movementBlueprints;
|
private SelectionBlueprint<T>[] movementBlueprints;
|
||||||
private bool isDraggingBlueprint;
|
private bool isDraggingBlueprint;
|
||||||
|
|
||||||
@ -459,7 +459,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
// Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item
|
// Movement is tracked from the blueprint of the earliest item, since it only makes sense to distance snap from that item
|
||||||
movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray();
|
movementBlueprints = SortForMovement(SelectionHandler.SelectedBlueprints).ToArray();
|
||||||
movementBlueprintOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSelectionPoint).ToArray();
|
movementBlueprintsOriginalPositions = movementBlueprints.Select(m => m.ScreenSpaceSnapPoints).ToArray();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,26 +480,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (movementBlueprints == null)
|
if (movementBlueprints == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Debug.Assert(movementBlueprintOriginalPositions != null);
|
Debug.Assert(movementBlueprintsOriginalPositions != null);
|
||||||
|
|
||||||
Vector2 distanceTravelled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition;
|
Vector2 distanceTravelled = e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition;
|
||||||
|
|
||||||
if (snapProvider != null)
|
if (snapProvider != null)
|
||||||
{
|
{
|
||||||
// check for positional snap for every object in selection (for things like object-object snapping)
|
for (int i = 0; i < movementBlueprints.Length; i++)
|
||||||
for (int i = 0; i < movementBlueprintOriginalPositions.Length; i++)
|
|
||||||
{
|
{
|
||||||
Vector2 originalPosition = movementBlueprintOriginalPositions[i];
|
if (checkSnappingBlueprintToNearbyObjects(movementBlueprints[i], distanceTravelled, movementBlueprintsOriginalPositions[i]))
|
||||||
var testPosition = originalPosition + distanceTravelled;
|
|
||||||
|
|
||||||
var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects);
|
|
||||||
|
|
||||||
if (positionalResult.ScreenSpacePosition == testPosition) continue;
|
|
||||||
|
|
||||||
var delta = positionalResult.ScreenSpacePosition - movementBlueprints[i].ScreenSpaceSelectionPoint;
|
|
||||||
|
|
||||||
// attempt to move the objects, and abort any time based snapping if we can.
|
|
||||||
if (SelectionHandler.HandleMovement(new MoveSelectionEvent<T>(movementBlueprints[i], delta)))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,7 +497,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
// item in the selection.
|
// item in the selection.
|
||||||
|
|
||||||
// The final movement position, relative to movementBlueprintOriginalPosition.
|
// The final movement position, relative to movementBlueprintOriginalPosition.
|
||||||
Vector2 movePosition = movementBlueprintOriginalPositions.First() + distanceTravelled;
|
Vector2 movePosition = movementBlueprintsOriginalPositions.First().First() + distanceTravelled;
|
||||||
|
|
||||||
// Retrieve a snapped position.
|
// Retrieve a snapped position.
|
||||||
var result = snapProvider?.FindSnappedPositionAndTime(movePosition, ~SnapType.NearbyObjects);
|
var result = snapProvider?.FindSnappedPositionAndTime(movePosition, ~SnapType.NearbyObjects);
|
||||||
@ -521,6 +510,36 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return ApplySnapResult(movementBlueprints, result);
|
return ApplySnapResult(movementBlueprints, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check for positional snap for given blueprint.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blueprint">The blueprint to check for snapping.</param>
|
||||||
|
/// <param name="distanceTravelled">Distance travelled since start of dragging action.</param>
|
||||||
|
/// <param name="originalPositions">The snap positions of blueprint before start of dragging action.</param>
|
||||||
|
/// <returns>Whether an object to snap to was found.</returns>
|
||||||
|
private bool checkSnappingBlueprintToNearbyObjects(SelectionBlueprint<T> blueprint, Vector2 distanceTravelled, Vector2[] originalPositions)
|
||||||
|
{
|
||||||
|
var currentPositions = blueprint.ScreenSpaceSnapPoints;
|
||||||
|
|
||||||
|
for (int i = 0; i < originalPositions.Length; i++)
|
||||||
|
{
|
||||||
|
Vector2 originalPosition = originalPositions[i];
|
||||||
|
var testPosition = originalPosition + distanceTravelled;
|
||||||
|
|
||||||
|
var positionalResult = snapProvider.FindSnappedPositionAndTime(testPosition, SnapType.NearbyObjects);
|
||||||
|
|
||||||
|
if (positionalResult.ScreenSpacePosition == testPosition) continue;
|
||||||
|
|
||||||
|
var delta = positionalResult.ScreenSpacePosition - currentPositions[i];
|
||||||
|
|
||||||
|
// attempt to move the objects, and abort any time based snapping if we can.
|
||||||
|
if (SelectionHandler.HandleMovement(new MoveSelectionEvent<T>(blueprint, delta)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual bool ApplySnapResult(SelectionBlueprint<T>[] blueprints, SnapResult result) =>
|
protected virtual bool ApplySnapResult(SelectionBlueprint<T>[] blueprints, SnapResult result) =>
|
||||||
SelectionHandler.HandleMovement(new MoveSelectionEvent<T>(blueprints.First(), result.ScreenSpacePosition - blueprints.First().ScreenSpaceSelectionPoint));
|
SelectionHandler.HandleMovement(new MoveSelectionEvent<T>(blueprints.First(), result.ScreenSpacePosition - blueprints.First().ScreenSpaceSelectionPoint));
|
||||||
|
|
||||||
@ -533,7 +552,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (movementBlueprints == null)
|
if (movementBlueprints == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
movementBlueprintOriginalPositions = null;
|
movementBlueprintsOriginalPositions = null;
|
||||||
movementBlueprints = null;
|
movementBlueprints = null;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user