mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:37:28 +08:00
Merge branch 'editor-position-snap' into mania-distance-snap-grid
This commit is contained in:
commit
94bb59db0d
@ -50,5 +50,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
public Column ColumnAt(Vector2 screenSpacePosition) => column;
|
||||
|
||||
public ManiaPlayfield Playfield => null;
|
||||
|
||||
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null) => Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
@ -34,5 +34,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
public Column ColumnAt(Vector2 screenSpacePosition) => column;
|
||||
|
||||
public ManiaPlayfield Playfield => null;
|
||||
|
||||
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null) => Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
@ -69,5 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
public Column ColumnAt(Vector2 screenSpacePosition) => null;
|
||||
|
||||
public ManiaPlayfield Playfield { get; }
|
||||
|
||||
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null) => Vector2.Zero;
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,10 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osuTK;
|
||||
@ -17,6 +19,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
private readonly EditNotePiece headPiece;
|
||||
private readonly EditNotePiece tailPiece;
|
||||
|
||||
[Resolved]
|
||||
private IManiaHitObjectComposer composer { get; set; }
|
||||
|
||||
public HoldNotePlacementBlueprint()
|
||||
: base(new HoldNote())
|
||||
{
|
||||
@ -36,8 +41,8 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
|
||||
if (Column != null)
|
||||
{
|
||||
headPiece.Y = PositionAt(HitObject.StartTime);
|
||||
tailPiece.Y = PositionAt(HitObject.EndTime);
|
||||
headPiece.Y = Parent.ToLocalSpace(composer.ScreenSpacePositionAtTime(HitObject.StartTime, Column)).Y;
|
||||
tailPiece.Y = Parent.ToLocalSpace(composer.ScreenSpacePositionAtTime(HitObject.EndTime, Column)).Y;
|
||||
}
|
||||
|
||||
var topPosition = new Vector2(headPiece.DrawPosition.X, Math.Min(headPiece.DrawPosition.Y, tailPiece.DrawPosition.Y));
|
||||
@ -59,23 +64,28 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
|
||||
private double originalStartTime;
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
base.UpdatePosition(screenSpacePosition);
|
||||
base.UpdatePosition(result);
|
||||
|
||||
if (PlacementActive)
|
||||
{
|
||||
var endTime = TimeAt(screenSpacePosition);
|
||||
|
||||
HitObject.StartTime = endTime < originalStartTime ? endTime : originalStartTime;
|
||||
HitObject.Duration = Math.Abs(endTime - originalStartTime);
|
||||
if (result.Time is double endTime)
|
||||
{
|
||||
HitObject.StartTime = endTime < originalStartTime ? endTime : originalStartTime;
|
||||
HitObject.Duration = Math.Abs(endTime - originalStartTime);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
headPiece.Width = tailPiece.Width = SnappedWidth;
|
||||
headPiece.X = tailPiece.X = SnappedMousePosition.X;
|
||||
if (result is ManiaSnapResult maniaResult)
|
||||
{
|
||||
headPiece.Width = tailPiece.Width = maniaResult.Column.DrawWidth;
|
||||
headPiece.X = tailPiece.X = ToLocalSpace(result.ScreenSpacePosition).X;
|
||||
}
|
||||
|
||||
originalStartTime = HitObject.StartTime = TimeAt(screenSpacePosition);
|
||||
if (result.Time is double startTime)
|
||||
originalStartTime = HitObject.StartTime = startTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,6 +77,6 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
|
||||
public override Quad SelectionQuad => ScreenSpaceDrawQuad;
|
||||
|
||||
public override Vector2 SelectionPoint => DrawableObject.Head.ScreenSpaceDrawQuad.Centre;
|
||||
public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.Head.ScreenSpaceDrawQuad.Centre;
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,34 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables.Pieces;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osu.Game.Rulesets.UI.Scrolling;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public abstract class ManiaPlacementBlueprint<T> : PlacementBlueprint,
|
||||
IRequireHighFrequencyMousePosition // the playfield could be moving behind us
|
||||
public abstract class ManiaPlacementBlueprint<T> : PlacementBlueprint
|
||||
where T : ManiaHitObject
|
||||
{
|
||||
protected new T HitObject => (T)base.HitObject;
|
||||
|
||||
protected Column Column;
|
||||
private Column column;
|
||||
|
||||
/// <summary>
|
||||
/// The current mouse position, snapped to the closest column.
|
||||
/// </summary>
|
||||
protected Vector2 SnappedMousePosition { get; private set; }
|
||||
public Column Column
|
||||
{
|
||||
get => column;
|
||||
set
|
||||
{
|
||||
if (value == column)
|
||||
return;
|
||||
|
||||
/// <summary>
|
||||
/// The width of the closest column to the current mouse position.
|
||||
/// </summary>
|
||||
protected float SnappedWidth { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private IManiaHitObjectComposer composer { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IScrollingInfo scrollingInfo { get; set; }
|
||||
column = value;
|
||||
HitObject.Column = column.Index;
|
||||
}
|
||||
}
|
||||
|
||||
protected ManiaPlacementBlueprint(T hitObject)
|
||||
: base(hitObject)
|
||||
@ -51,105 +42,16 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
return false;
|
||||
|
||||
if (Column == null)
|
||||
return base.OnMouseDown(e);
|
||||
return false;
|
||||
|
||||
HitObject.Column = Column.Index;
|
||||
BeginPlacement(TimeAt(e.ScreenSpaceMousePosition), true);
|
||||
BeginPlacement(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
if (!PlacementActive)
|
||||
Column = ColumnAt(screenSpacePosition);
|
||||
|
||||
if (Column == null) return;
|
||||
|
||||
SnappedWidth = Column.DrawWidth;
|
||||
|
||||
// Snap to the column
|
||||
var parentPos = Parent.ToLocalSpace(Column.ToScreenSpace(new Vector2(Column.DrawWidth / 2, 0)));
|
||||
SnappedMousePosition = new Vector2(parentPos.X, Parent.ToLocalSpace(screenSpacePosition).Y);
|
||||
}
|
||||
|
||||
protected double TimeAt(Vector2 screenSpacePosition)
|
||||
{
|
||||
if (Column == null)
|
||||
return 0;
|
||||
|
||||
var hitObjectContainer = Column.HitObjectContainer;
|
||||
|
||||
// If we're scrolling downwards, a position of 0 is actually further away from the hit target
|
||||
// so we need to flip the vertical coordinate in the hitobject container's space
|
||||
var hitObjectPos = mouseToHitObjectPosition(Column.HitObjectContainer.ToLocalSpace(screenSpacePosition)).Y;
|
||||
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
|
||||
hitObjectPos = hitObjectContainer.DrawHeight - hitObjectPos;
|
||||
|
||||
return scrollingInfo.Algorithm.TimeAt(hitObjectPos,
|
||||
EditorClock.CurrentTime,
|
||||
scrollingInfo.TimeRange.Value,
|
||||
hitObjectContainer.DrawHeight);
|
||||
}
|
||||
|
||||
protected float PositionAt(double time)
|
||||
{
|
||||
var pos = scrollingInfo.Algorithm.PositionAt(time,
|
||||
EditorClock.CurrentTime,
|
||||
scrollingInfo.TimeRange.Value,
|
||||
Column.HitObjectContainer.DrawHeight);
|
||||
|
||||
if (scrollingInfo.Direction.Value == ScrollingDirection.Down)
|
||||
pos = Column.HitObjectContainer.DrawHeight - pos;
|
||||
|
||||
return hitObjectToMousePosition(Column.HitObjectContainer.ToSpaceOfOtherDrawable(new Vector2(0, pos), Parent)).Y;
|
||||
}
|
||||
|
||||
protected Column ColumnAt(Vector2 screenSpacePosition)
|
||||
=> composer.ColumnAt(screenSpacePosition);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a mouse position to a hitobject position.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Blueprints are centred on the mouse position, such that the hitobject position is anchored at the top or bottom of the blueprint depending on the scroll direction.
|
||||
/// </remarks>
|
||||
/// <param name="mousePosition">The mouse position.</param>
|
||||
/// <returns>The resulting hitobject position, acnhored at the top or bottom of the blueprint depending on the scroll direction.</returns>
|
||||
private Vector2 mouseToHitObjectPosition(Vector2 mousePosition)
|
||||
{
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
mousePosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Down:
|
||||
mousePosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return mousePosition;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a hitobject position to a mouse position.
|
||||
/// </summary>
|
||||
/// <param name="hitObjectPosition">The hitobject position.</param>
|
||||
/// <returns>The resulting mouse position, anchored at the centre of the hitobject.</returns>
|
||||
private Vector2 hitObjectToMousePosition(Vector2 hitObjectPosition)
|
||||
{
|
||||
switch (scrollingInfo.Direction.Value)
|
||||
{
|
||||
case ScrollingDirection.Up:
|
||||
hitObjectPosition.Y += DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
|
||||
case ScrollingDirection.Down:
|
||||
hitObjectPosition.Y -= DefaultNotePiece.NOTE_HEIGHT / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return hitObjectPosition;
|
||||
Column = (result as ManiaSnapResult)?.Column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.Edit.Blueprints.Components;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osuTK.Input;
|
||||
@ -11,22 +12,25 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
|
||||
{
|
||||
public class NotePlacementBlueprint : ManiaPlacementBlueprint<Note>
|
||||
{
|
||||
private readonly EditNotePiece piece;
|
||||
|
||||
public NotePlacementBlueprint()
|
||||
: base(new Note())
|
||||
{
|
||||
Origin = Anchor.Centre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
InternalChild = new EditNotePiece { RelativeSizeAxes = Axes.X };
|
||||
InternalChild = piece = new EditNotePiece { Origin = Anchor.Centre };
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
base.Update();
|
||||
base.UpdatePosition(result);
|
||||
|
||||
Width = SnappedWidth;
|
||||
Position = SnappedMousePosition;
|
||||
if (result is ManiaSnapResult maniaResult)
|
||||
{
|
||||
piece.Width = maniaResult.Column.DrawWidth;
|
||||
piece.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
|
@ -11,5 +11,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
Column ColumnAt(Vector2 screenSpacePosition);
|
||||
|
||||
ManiaPlayfield Playfield { get; }
|
||||
|
||||
Vector2 ScreenSpacePositionAtTime(double time, Column column = null);
|
||||
}
|
||||
}
|
||||
|
@ -75,31 +75,61 @@ namespace osu.Game.Rulesets.Mania.Edit
|
||||
}
|
||||
else
|
||||
{
|
||||
var placementTime = GetSnappedPosition(ToLocalSpace(inputManager.CurrentState.Mouse.Position), 0).time;
|
||||
beatSnapGrid.SelectionTimeRange = (placementTime, placementTime);
|
||||
var result = SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position);
|
||||
if (result.Time is double time)
|
||||
beatSnapGrid.SelectionTimeRange = (time, time);
|
||||
else
|
||||
beatSnapGrid.SelectionTimeRange = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time)
|
||||
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
||||
{
|
||||
var hoc = Playfield.GetColumn(0).HitObjectContainer;
|
||||
var column = ColumnAt(screenSpacePosition);
|
||||
|
||||
float targetPosition = hoc.ToLocalSpace(ToScreenSpace(position)).Y;
|
||||
if (column == null)
|
||||
return new SnapResult(screenSpacePosition, null);
|
||||
|
||||
if (drawableRuleset.ScrollingInfo.Direction.Value == ScrollingDirection.Down)
|
||||
var hoc = column.HitObjectContainer;
|
||||
|
||||
// convert to local space of column so we can snap and fetch correct location.
|
||||
Vector2 localPosition = hoc.ToLocalSpace(screenSpacePosition);
|
||||
|
||||
var scrollInfo = drawableRuleset.ScrollingInfo;
|
||||
|
||||
if (scrollInfo.Direction.Value == ScrollingDirection.Down)
|
||||
{
|
||||
// We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time.
|
||||
// The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position,
|
||||
// so when scrolling downwards the coordinates need to be flipped.
|
||||
targetPosition = hoc.DrawHeight - targetPosition;
|
||||
localPosition.Y = hoc.DrawHeight - localPosition.Y;
|
||||
}
|
||||
|
||||
double targetTime = drawableRuleset.ScrollingInfo.Algorithm.TimeAt(targetPosition,
|
||||
EditorClock.CurrentTime,
|
||||
drawableRuleset.ScrollingInfo.TimeRange.Value,
|
||||
hoc.DrawHeight);
|
||||
double targetTime = scrollInfo.Algorithm.TimeAt(localPosition.Y, EditorClock.CurrentTime, scrollInfo.TimeRange.Value, hoc.DrawHeight);
|
||||
|
||||
return base.GetSnappedPosition(position, targetTime);
|
||||
// apply beat snapping
|
||||
targetTime = BeatSnapProvider.SnapTime(targetTime);
|
||||
|
||||
// convert back to screen space
|
||||
screenSpacePosition = ScreenSpacePositionAtTime(targetTime, column);
|
||||
|
||||
return new ManiaSnapResult(screenSpacePosition, targetTime, column);
|
||||
}
|
||||
|
||||
public Vector2 ScreenSpacePositionAtTime(double time, Column column = null)
|
||||
{
|
||||
var hoc = (column ?? Playfield.GetColumn(0)).HitObjectContainer;
|
||||
var scrollInfo = drawableRuleset.ScrollingInfo;
|
||||
|
||||
var pos = scrollInfo.Algorithm.PositionAt(time, EditorClock.CurrentTime, scrollInfo.TimeRange.Value, hoc.DrawHeight);
|
||||
|
||||
if (scrollInfo.Direction.Value == ScrollingDirection.Down)
|
||||
{
|
||||
// as explained above
|
||||
pos = hoc.DrawHeight - pos;
|
||||
}
|
||||
|
||||
return hoc.ToScreenSpace(new Vector2(hoc.DrawWidth / 2, pos));
|
||||
}
|
||||
|
||||
protected override DrawableRuleset<ManiaHitObject> CreateDrawableRuleset(Ruleset ruleset, IBeatmap beatmap, IReadOnlyList<Mod> mods = null)
|
||||
|
20
osu.Game.Rulesets.Mania/Edit/ManiaSnapResult.cs
Normal file
20
osu.Game.Rulesets.Mania/Edit/ManiaSnapResult.cs
Normal file
@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Mania.UI;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Edit
|
||||
{
|
||||
public class ManiaSnapResult : SnapResult
|
||||
{
|
||||
public readonly Column Column;
|
||||
|
||||
public ManiaSnapResult(Vector2 screenSpacePosition, double time, Column column)
|
||||
: base(screenSpacePosition, time)
|
||||
{
|
||||
Column = column;
|
||||
}
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Cached]
|
||||
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
||||
|
||||
[Cached(typeof(IDistanceSnapProvider))]
|
||||
[Cached(typeof(IPositionSnapProvider))]
|
||||
private readonly SnapProvider snapProvider = new SnapProvider();
|
||||
|
||||
private TestOsuDistanceSnapGrid grid;
|
||||
@ -172,9 +172,9 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private class SnapProvider : IDistanceSnapProvider
|
||||
private class SnapProvider : IPositionSnapProvider
|
||||
{
|
||||
public (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) => (position, time);
|
||||
public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => new SnapResult(screenSpacePosition, 0);
|
||||
|
||||
public float GetBeatSnapDistanceAt(double referenceTime) => (float)beat_length;
|
||||
|
||||
|
@ -5,7 +5,6 @@ using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
||||
@ -40,6 +39,6 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition) => HitObject.Position = ToLocalSpace(screenSpacePosition);
|
||||
public override void UpdatePosition(SnapResult result) => HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
private IEditorChangeHandler changeHandler { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
private IDistanceSnapProvider snapProvider { get; set; }
|
||||
private IPositionSnapProvider snapProvider { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
@ -162,11 +162,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
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
|
||||
(Vector2 snappedPosition, double snappedTime) = snapProvider?.GetSnappedPosition(e.MousePosition, slider.StartTime) ?? (e.MousePosition, slider.StartTime);
|
||||
Vector2 movementDelta = snappedPosition - slider.Position;
|
||||
var result = snapProvider?.SnapScreenSpacePositionToValidTime(e.MousePosition);
|
||||
Vector2 movementDelta = (result?.ScreenSpacePosition ?? e.MousePosition) - slider.Position;
|
||||
|
||||
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
|
||||
for (int i = 1; i < slider.Path.ControlPoints.Count; i++)
|
||||
|
@ -67,13 +67,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
inputManager = GetContainingInputManager();
|
||||
}
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case PlacementState.Initial:
|
||||
BeginPlacement();
|
||||
HitObject.Position = ToLocalSpace(screenSpacePosition);
|
||||
HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
|
||||
break;
|
||||
|
||||
case PlacementState.Body:
|
||||
|
@ -190,7 +190,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
|
||||
};
|
||||
|
||||
public override Vector2 SelectionPoint => ((DrawableSlider)DrawableObject).HeadCircle.ScreenSpaceDrawQuad.Centre;
|
||||
public override Vector2 ScreenSpaceSelectionPoint => ((DrawableSlider)DrawableObject).HeadCircle.ScreenSpaceDrawQuad.Centre;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
|
@ -8,7 +8,6 @@ using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.UI;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
||||
@ -61,7 +60,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Spinners
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void UpdatePosition(Vector2 screenSpacePosition)
|
||||
public override void UpdatePosition(SnapResult result)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
[Cached(typeof(EditorBeatmap))]
|
||||
private readonly EditorBeatmap editorBeatmap;
|
||||
|
||||
[Cached(typeof(IDistanceSnapProvider))]
|
||||
[Cached(typeof(IPositionSnapProvider))]
|
||||
private readonly SnapProvider snapProvider = new SnapProvider();
|
||||
|
||||
public TestSceneDistanceSnapGrid()
|
||||
@ -151,9 +151,9 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
=> (Vector2.Zero, 0);
|
||||
}
|
||||
|
||||
private class SnapProvider : IDistanceSnapProvider
|
||||
private class SnapProvider : IPositionSnapProvider
|
||||
{
|
||||
public (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) => (position, time);
|
||||
public SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => new SnapResult(screenSpacePosition, 0);
|
||||
|
||||
public float GetBeatSnapDistanceAt(double referenceTime) => 10;
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
private IAdjustableClock adjustableClock { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private IBeatSnapProvider beatSnapProvider { get; set; }
|
||||
protected IBeatSnapProvider BeatSnapProvider { get; private set; }
|
||||
|
||||
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
||||
|
||||
@ -245,8 +245,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
EditorBeatmap.PlacementObject.Value = hitObject;
|
||||
|
||||
if (distanceSnapGrid != null)
|
||||
hitObject.StartTime = GetSnappedPosition(distanceSnapGrid.ToLocalSpace(inputManager.CurrentState.Mouse.Position), hitObject.StartTime).time;
|
||||
hitObject.StartTime = SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position).Time ?? EditorClock.CurrentTime;
|
||||
}
|
||||
|
||||
public void EndPlacement(HitObject hitObject, bool commit)
|
||||
@ -265,40 +264,48 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
|
||||
|
||||
public override (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) => distanceSnapGrid?.GetSnappedPosition(position) ?? (position, time);
|
||||
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
||||
{
|
||||
if (distanceSnapGrid == null) return new SnapResult(screenSpacePosition, null);
|
||||
|
||||
// TODO: move distance snap grid to OsuHitObjectComposer.
|
||||
(Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition));
|
||||
|
||||
return new SnapResult(distanceSnapGrid.ToScreenSpace(pos), time);
|
||||
}
|
||||
|
||||
public override float GetBeatSnapDistanceAt(double referenceTime)
|
||||
{
|
||||
DifficultyControlPoint difficultyPoint = EditorBeatmap.ControlPointInfo.DifficultyPointAt(referenceTime);
|
||||
return (float)(100 * EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / beatSnapProvider.BeatDivisor);
|
||||
return (float)(100 * EditorBeatmap.BeatmapInfo.BaseDifficulty.SliderMultiplier * difficultyPoint.SpeedMultiplier / BeatSnapProvider.BeatDivisor);
|
||||
}
|
||||
|
||||
public override float DurationToDistance(double referenceTime, double duration)
|
||||
{
|
||||
double beatLength = beatSnapProvider.GetBeatLengthAtTime(referenceTime);
|
||||
double beatLength = BeatSnapProvider.GetBeatLengthAtTime(referenceTime);
|
||||
return (float)(duration / beatLength * GetBeatSnapDistanceAt(referenceTime));
|
||||
}
|
||||
|
||||
public override double DistanceToDuration(double referenceTime, float distance)
|
||||
{
|
||||
double beatLength = beatSnapProvider.GetBeatLengthAtTime(referenceTime);
|
||||
double beatLength = BeatSnapProvider.GetBeatLengthAtTime(referenceTime);
|
||||
return distance / GetBeatSnapDistanceAt(referenceTime) * beatLength;
|
||||
}
|
||||
|
||||
public override double GetSnappedDurationFromDistance(double referenceTime, float distance)
|
||||
=> beatSnapProvider.SnapTime(referenceTime + DistanceToDuration(referenceTime, distance), referenceTime) - referenceTime;
|
||||
=> BeatSnapProvider.SnapTime(referenceTime + DistanceToDuration(referenceTime, distance), referenceTime) - referenceTime;
|
||||
|
||||
public override float GetSnappedDistanceFromDistance(double referenceTime, float distance)
|
||||
{
|
||||
var snappedEndTime = beatSnapProvider.SnapTime(referenceTime + DistanceToDuration(referenceTime, distance), referenceTime);
|
||||
var snappedEndTime = BeatSnapProvider.SnapTime(referenceTime + DistanceToDuration(referenceTime, distance), referenceTime);
|
||||
|
||||
return DurationToDistance(referenceTime, snappedEndTime - referenceTime);
|
||||
}
|
||||
}
|
||||
|
||||
[Cached(typeof(HitObjectComposer))]
|
||||
[Cached(typeof(IDistanceSnapProvider))]
|
||||
public abstract class HitObjectComposer : CompositeDrawable, IDistanceSnapProvider
|
||||
[Cached(typeof(IPositionSnapProvider))]
|
||||
public abstract class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||
{
|
||||
internal HitObjectComposer()
|
||||
{
|
||||
@ -323,7 +330,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
[CanBeNull]
|
||||
protected virtual DistanceSnapGrid CreateDistanceSnapGrid([NotNull] IEnumerable<HitObject> selectedHitObjects) => null;
|
||||
|
||||
public abstract (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time);
|
||||
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
||||
|
||||
public abstract float GetBeatSnapDistanceAt(double referenceTime);
|
||||
|
||||
|
@ -5,9 +5,14 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
public interface IDistanceSnapProvider
|
||||
public interface IPositionSnapProvider
|
||||
{
|
||||
(Vector2 position, double time) GetSnappedPosition(Vector2 position, double time);
|
||||
/// <summary>
|
||||
/// Given a position, find a valid time snap.
|
||||
/// </summary>
|
||||
/// <param name="screenSpacePosition">The screen-space position to be snapped.</param>
|
||||
/// <returns>The time and position post-snapping.</returns>
|
||||
SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the distance between two points within a timing point that are one beat length apart.
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
public override Vector2 SelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre;
|
||||
public override Vector2 ScreenSpaceSelectionPoint => DrawableObject.ScreenSpaceDrawQuad.Centre;
|
||||
|
||||
public override Quad SelectionQuad => DrawableObject.ScreenSpaceDrawQuad;
|
||||
|
||||
|
@ -61,12 +61,12 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// Signals that the placement of <see cref="HitObject"/> has started.
|
||||
/// </summary>
|
||||
/// <param name="startTime">The start time of <see cref="HitObject"/> at the placement point. If null, the current clock time is used.</param>
|
||||
/// <param name="commitStart">Whether this call is committing a value for HitObject.StartTime and continuing with further adjustments.</param>
|
||||
protected void BeginPlacement(double? startTime = null, bool commitStart = false)
|
||||
protected void BeginPlacement(bool commitStart = false)
|
||||
{
|
||||
HitObject.StartTime = startTime ?? EditorClock.CurrentTime;
|
||||
// applies snapping to above time
|
||||
placementHandler.BeginPlacement(HitObject);
|
||||
|
||||
PlacementActive |= commitStart;
|
||||
}
|
||||
|
||||
@ -86,8 +86,8 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
|
||||
/// </summary>
|
||||
/// <param name="screenSpacePosition">The screen-space position.</param>
|
||||
public abstract void UpdatePosition(Vector2 screenSpacePosition);
|
||||
/// <param name="snapResult">The snap result information.</param>
|
||||
public abstract void UpdatePosition(SnapResult snapResult);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes <see cref="Objects.HitObject.ApplyDefaults(ControlPointInfo,BeatmapDifficulty)"/>,
|
||||
|
@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Edit
|
||||
/// <summary>
|
||||
/// The screen-space point that causes this <see cref="OverlaySelectionBlueprint"/> to be selected.
|
||||
/// </summary>
|
||||
public virtual Vector2 SelectionPoint => ScreenSpaceDrawQuad.Centre;
|
||||
public virtual Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.Centre;
|
||||
|
||||
/// <summary>
|
||||
/// The screen-space quad that outlines this <see cref="OverlaySelectionBlueprint"/> for selections.
|
||||
|
29
osu.Game/Rulesets/Edit/SnapResult.cs
Normal file
29
osu.Game/Rulesets/Edit/SnapResult.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.
|
||||
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Edit
|
||||
{
|
||||
/// <summary>
|
||||
/// The result of a position/time snapping process.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
private readonly BindableList<HitObject> selectedHitObjects = new BindableList<HitObject>();
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private IDistanceSnapProvider snapProvider { get; set; }
|
||||
private IPositionSnapProvider snapProvider { get; set; }
|
||||
|
||||
protected BlueprintContainer()
|
||||
{
|
||||
@ -326,7 +326,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
foreach (var blueprint in SelectionBlueprints)
|
||||
{
|
||||
if (blueprint.IsAlive && blueprint.IsPresent && rect.Contains(blueprint.SelectionPoint))
|
||||
if (blueprint.IsAlive && blueprint.IsPresent && rect.Contains(blueprint.ScreenSpaceSelectionPoint))
|
||||
blueprint.Select();
|
||||
else
|
||||
blueprint.Deselect();
|
||||
@ -384,7 +384,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
|
||||
// Movement is tracked from the blueprint of the earliest hitobject, since it only makes sense to distance snap from that hitobject
|
||||
movementBlueprint = selectionHandler.SelectedBlueprints.OrderBy(b => b.HitObject.StartTime).First();
|
||||
movementBlueprintOriginalPosition = movementBlueprint.SelectionPoint; // todo: unsure if correct
|
||||
movementBlueprintOriginalPosition = movementBlueprint.ScreenSpaceSelectionPoint; // todo: unsure if correct
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -405,16 +405,19 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
Vector2 movePosition = movementBlueprintOriginalPosition.Value + e.ScreenSpaceMousePosition - e.ScreenSpaceMouseDownPosition;
|
||||
|
||||
// Retrieve a snapped position.
|
||||
(Vector2 snappedPosition, double snappedTime) = snapProvider.GetSnappedPosition(ToLocalSpace(movePosition), draggedObject.StartTime);
|
||||
var result = snapProvider.SnapScreenSpacePositionToValidTime(movePosition);
|
||||
|
||||
// Move the hitobjects.
|
||||
if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, ToScreenSpace(snappedPosition))))
|
||||
if (!selectionHandler.HandleMovement(new MoveSelectionEvent(movementBlueprint, result.ScreenSpacePosition)))
|
||||
return true;
|
||||
|
||||
// Apply the start time at the newly snapped-to position
|
||||
double offset = snappedTime - draggedObject.StartTime;
|
||||
foreach (HitObject obj in selectionHandler.SelectedHitObjects)
|
||||
obj.StartTime += offset;
|
||||
if (result.Time.HasValue)
|
||||
{
|
||||
// Apply the start time at the newly snapped-to position
|
||||
double offset = result.Time.Value - draggedObject.StartTime;
|
||||
foreach (HitObject obj in selectionHandler.SelectedHitObjects)
|
||||
obj.StartTime += offset;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Edit.Tools;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components
|
||||
{
|
||||
@ -65,12 +64,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
createPlacement();
|
||||
}
|
||||
|
||||
private void updatePlacementPosition(Vector2 screenSpacePosition)
|
||||
private void updatePlacementPosition()
|
||||
{
|
||||
Vector2 snappedGridPosition = composer.GetSnappedPosition(ToLocalSpace(screenSpacePosition), 0).position;
|
||||
Vector2 snappedScreenSpacePosition = ToScreenSpace(snappedGridPosition);
|
||||
var snapResult = composer.SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position);
|
||||
|
||||
currentPlacement.UpdatePosition(snappedScreenSpacePosition);
|
||||
currentPlacement.UpdatePosition(snapResult);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -85,7 +83,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
removePlacement();
|
||||
|
||||
if (currentPlacement != null)
|
||||
updatePlacementPosition(inputManager.CurrentState.Mouse.Position);
|
||||
updatePlacementPosition();
|
||||
}
|
||||
|
||||
protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject)
|
||||
@ -117,7 +115,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
placementBlueprintContainer.Child = currentPlacement = blueprint;
|
||||
|
||||
// Fixes a 1-frame position discrepancy due to the first mouse move event happening in the next frame
|
||||
updatePlacementPosition(inputManager.CurrentState.Mouse.Position);
|
||||
updatePlacementPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
protected OsuColour Colours { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
protected IDistanceSnapProvider SnapProvider { get; private set; }
|
||||
protected IPositionSnapProvider SnapProvider { get; private set; }
|
||||
|
||||
[Resolved]
|
||||
private EditorBeatmap beatmap { get; set; }
|
||||
|
@ -17,9 +17,9 @@ using osuTK;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
[Cached(typeof(IDistanceSnapProvider))]
|
||||
[Cached(typeof(IPositionSnapProvider))]
|
||||
[Cached]
|
||||
public class Timeline : ZoomableScrollContainer, IDistanceSnapProvider
|
||||
public class Timeline : ZoomableScrollContainer, IPositionSnapProvider
|
||||
{
|
||||
public readonly Bindable<bool> WaveformVisible = new Bindable<bool>();
|
||||
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
||||
@ -181,11 +181,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
[Resolved]
|
||||
private IBeatSnapProvider beatSnapProvider { get; set; }
|
||||
|
||||
public double GetTimeFromScreenSpacePosition(Vector2 position)
|
||||
=> getTimeFromPosition(Content.ToLocalSpace(position));
|
||||
|
||||
public (Vector2 position, double time) GetSnappedPosition(Vector2 position, double time) =>
|
||||
(position, beatSnapProvider.SnapTime(getTimeFromPosition(position)));
|
||||
public SnapResult SnapScreenSpacePositionToValidTime(Vector2 position) =>
|
||||
new SnapResult(position, beatSnapProvider.SnapTime(getTimeFromPosition(Content.ToLocalSpace(position))));
|
||||
|
||||
private double getTimeFromPosition(Vector2 localPosition) =>
|
||||
(localPosition.X / Content.DrawWidth) * track.Length;
|
||||
|
@ -186,7 +186,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
}
|
||||
}
|
||||
|
||||
public override Vector2 SelectionPoint => ScreenSpaceDrawQuad.TopLeft;
|
||||
public override Vector2 ScreenSpaceSelectionPoint => ScreenSpaceDrawQuad.TopLeft;
|
||||
|
||||
public class DragBar : Container
|
||||
{
|
||||
@ -275,32 +275,33 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
OnDragHandled?.Invoke(e);
|
||||
|
||||
var time = timeline.GetTimeFromScreenSpacePosition(e.ScreenSpaceMousePosition);
|
||||
|
||||
switch (hitObject)
|
||||
if (timeline.SnapScreenSpacePositionToValidTime(e.ScreenSpaceMousePosition).Time is double time)
|
||||
{
|
||||
case IHasRepeats repeatHitObject:
|
||||
// find the number of repeats which can fit in the requested time.
|
||||
var lengthOfOneRepeat = repeatHitObject.Duration / (repeatHitObject.RepeatCount + 1);
|
||||
var proposedCount = Math.Max(0, (int)((time - hitObject.StartTime) / lengthOfOneRepeat) - 1);
|
||||
switch (hitObject)
|
||||
{
|
||||
case IHasRepeats repeatHitObject:
|
||||
// find the number of repeats which can fit in the requested time.
|
||||
var lengthOfOneRepeat = repeatHitObject.Duration / (repeatHitObject.RepeatCount + 1);
|
||||
var proposedCount = Math.Max(0, (int)((time - hitObject.StartTime) / lengthOfOneRepeat) - 1);
|
||||
|
||||
if (proposedCount == repeatHitObject.RepeatCount)
|
||||
return;
|
||||
if (proposedCount == repeatHitObject.RepeatCount)
|
||||
return;
|
||||
|
||||
repeatHitObject.RepeatCount = proposedCount;
|
||||
break;
|
||||
repeatHitObject.RepeatCount = proposedCount;
|
||||
break;
|
||||
|
||||
case IHasEndTime endTimeHitObject:
|
||||
var snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
||||
case IHasEndTime endTimeHitObject:
|
||||
var snappedTime = Math.Max(hitObject.StartTime, beatSnapProvider.SnapTime(time));
|
||||
|
||||
if (endTimeHitObject.EndTime == snappedTime)
|
||||
return;
|
||||
if (endTimeHitObject.EndTime == snappedTime)
|
||||
return;
|
||||
|
||||
endTimeHitObject.EndTime = snappedTime;
|
||||
break;
|
||||
endTimeHitObject.EndTime = snappedTime;
|
||||
break;
|
||||
}
|
||||
|
||||
beatmap.UpdateHitObject(hitObject);
|
||||
}
|
||||
|
||||
beatmap.UpdateHitObject(hitObject);
|
||||
}
|
||||
|
||||
protected override void OnDragEnd(DragEndEvent e)
|
||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Tests.Visual
|
||||
{
|
||||
base.Update();
|
||||
|
||||
currentBlueprint.UpdatePosition(InputManager.CurrentState.Mouse.Position);
|
||||
currentBlueprint.UpdatePosition(new SnapResult(InputManager.CurrentState.Mouse.Position, null));
|
||||
}
|
||||
|
||||
public override void Add(Drawable drawable)
|
||||
@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual
|
||||
if (drawable is PlacementBlueprint blueprint)
|
||||
{
|
||||
blueprint.Show();
|
||||
blueprint.UpdatePosition(InputManager.CurrentState.Mouse.Position);
|
||||
blueprint.UpdatePosition(new SnapResult(InputManager.CurrentState.Mouse.Position, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user