1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-13 07:22:54 +08:00

Merge pull request #10974 from peppy/editor-beat-snap-always

Fix editor not beat snapping when positional snap is unavailable
This commit is contained in:
Bartłomiej Dach 2020-11-30 19:13:06 +01:00 committed by GitHub
commit 76919a5772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 69 additions and 24 deletions

View File

@ -78,9 +78,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
private double originalStartTime;
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
if (PlacementActive)
{

View File

@ -48,9 +48,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
return true;
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
if (!PlacementActive)
Column = result.Playfield as Column;

View File

@ -22,9 +22,9 @@ namespace osu.Game.Rulesets.Mania.Edit.Blueprints
InternalChild = piece = new EditNotePiece { Origin = Anchor.Centre };
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
if (result.Playfield != null)
{

View File

@ -0,0 +1,41 @@
// 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 System.Linq;
using NUnit.Framework;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Osu.UI;
using osu.Game.Tests.Beatmaps;
using osuTK.Input;
namespace osu.Game.Rulesets.Osu.Tests.Editor
{
[TestFixture]
public class TestSceneObjectBeatSnap : TestSceneOsuEditor
{
private OsuPlayfield playfield;
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(Ruleset.Value, false);
public override void SetUpSteps()
{
base.SetUpSteps();
AddStep("get playfield", () => playfield = Editor.ChildrenOfType<OsuPlayfield>().First());
}
[Test]
public void TestBeatSnapHitCircle()
{
double firstTimingPointTime() => Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.First().Time;
AddStep("seek some milliseconds forward", () => EditorClock.Seek(firstTimingPointTime() + 10));
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre));
AddStep("enter placement mode", () => InputManager.Key(Key.Number2));
AddStep("place first object", () => InputManager.Click(MouseButton.Left));
AddAssert("ensure object snapped back to correct time", () => EditorBeatmap.HitObjects.First().StartTime == firstTimingPointTime());
}
}
}

View File

@ -25,6 +25,7 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
{
base.SetUpSteps();
AddStep("get playfield", () => playfield = Editor.ChildrenOfType<OsuPlayfield>().First());
AddStep("seek to first control point", () => EditorClock.Seek(Beatmap.Value.Beatmap.ControlPointInfo.TimingPoints.First().Time));
}
[TestCase(true)]
@ -66,13 +67,13 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
AddStep("start slider placement", () => InputManager.Click(MouseButton.Left));
AddStep("move to place end", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre + new Vector2(playfield.ScreenSpaceDrawQuad.Width * 0.185f, 0)));
AddStep("move to place end", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre + new Vector2(playfield.ScreenSpaceDrawQuad.Width * 0.225f, 0)));
AddStep("end slider placement", () => InputManager.Click(MouseButton.Right));
AddStep("enter circle placement mode", () => InputManager.Key(Key.Number2));
AddStep("move mouse slightly", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre + new Vector2(playfield.ScreenSpaceDrawQuad.Width * 0.20f, 0)));
AddStep("move mouse slightly", () => InputManager.MoveMouseTo(playfield.ScreenSpaceDrawQuad.Centre + new Vector2(playfield.ScreenSpaceDrawQuad.Width * 0.235f, 0)));
AddStep("place second object", () => InputManager.Click(MouseButton.Left));

View File

@ -45,9 +45,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles
return base.OnMouseDown(e);
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
HitObject.Position = ToLocalSpace(result.ScreenSpacePosition);
}
}

View File

@ -67,9 +67,9 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
inputManager = GetContainingInputManager();
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
switch (state)
{

View File

@ -43,10 +43,10 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
return false;
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
piece.Position = ToLocalSpace(result.ScreenSpacePosition);
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
}
}
}

View File

@ -68,9 +68,9 @@ namespace osu.Game.Rulesets.Taiko.Edit.Blueprints
EndPlacement(true);
}
public override void UpdatePosition(SnapResult result)
public override void UpdateTimeAndPosition(SnapResult result)
{
base.UpdatePosition(result);
base.UpdateTimeAndPosition(result);
if (PlacementActive)
{

View File

@ -85,10 +85,10 @@ namespace osu.Game.Rulesets.Edit
}
/// <summary>
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
/// Updates the time and position of this <see cref="PlacementBlueprint"/> based on the provided snap information.
/// </summary>
/// <param name="result">The snap result information.</param>
public virtual void UpdatePosition(SnapResult result)
public virtual void UpdateTimeAndPosition(SnapResult result)
{
if (!PlacementActive)
HitObject.StartTime = result.Time ?? EditorClock?.CurrentTime ?? Time.Current;

View File

@ -41,7 +41,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
private IEditorChangeHandler changeHandler { get; set; }
[Resolved]
private EditorClock editorClock { get; set; }
protected EditorClock EditorClock { get; private set; }
[Resolved]
protected EditorBeatmap Beatmap { get; private set; }
@ -170,7 +170,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (clickedBlueprint == null || SelectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered) != clickedBlueprint)
return false;
editorClock?.SeekTo(clickedBlueprint.HitObject.StartTime);
EditorClock?.SeekTo(clickedBlueprint.HitObject.StartTime);
return true;
}
@ -381,7 +381,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
case SelectionState.Selected:
// if the editor is playing, we generally don't want to deselect objects even if outside the selection area.
if (!editorClock.IsRunning && !isValidForSelection())
if (!EditorClock.IsRunning && !isValidForSelection())
blueprint.Deselect();
break;
}

View File

@ -157,7 +157,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
var snapResult = Composer.SnapScreenSpacePositionToValidTime(inputManager.CurrentState.Mouse.Position);
currentPlacement.UpdatePosition(snapResult);
// if no time was found from positional snapping, we should still quantize to the beat.
snapResult.Time ??= Beatmap.SnapTime(EditorClock.CurrentTime, null);
currentPlacement.UpdateTimeAndPosition(snapResult);
}
#endregion

View File

@ -72,7 +72,7 @@ namespace osu.Game.Tests.Visual
{
base.Update();
currentBlueprint.UpdatePosition(SnapForBlueprint(currentBlueprint));
currentBlueprint.UpdateTimeAndPosition(SnapForBlueprint(currentBlueprint));
}
protected virtual SnapResult SnapForBlueprint(PlacementBlueprint blueprint) =>
@ -85,7 +85,7 @@ namespace osu.Game.Tests.Visual
if (drawable is PlacementBlueprint blueprint)
{
blueprint.Show();
blueprint.UpdatePosition(SnapForBlueprint(blueprint));
blueprint.UpdateTimeAndPosition(SnapForBlueprint(blueprint));
}
}