diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index 365ad37f4c..193068193a 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -178,6 +178,7 @@ namespace osu.Game.Configuration
SetDefault(OsuSetting.EditorWaveformOpacity, 0.25f, 0f, 1f, 0.25f);
SetDefault(OsuSetting.EditorShowHitMarkers, true);
SetDefault(OsuSetting.EditorAutoSeekOnPlacement, true);
+ SetDefault(OsuSetting.EditorLimitedDistanceSnap, false);
SetDefault(OsuSetting.LastProcessedMetadataId, -1);
@@ -383,5 +384,6 @@ namespace osu.Game.Configuration
SafeAreaConsiderations,
ComboColourNormalisationAmount,
ProfileCoverExpanded,
+ EditorLimitedDistanceSnap
}
}
diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs
index 20258b9c35..077bd92d4f 100644
--- a/osu.Game/Localisation/EditorStrings.cs
+++ b/osu.Game/Localisation/EditorStrings.cs
@@ -109,6 +109,11 @@ namespace osu.Game.Localisation
///
public static LocalisableString RotationSnapped(float newRotation) => new TranslatableString(getKey(@"rotation_snapped"), @"{0:0}° (snapped)", newRotation);
+ ///
+ /// "Limit distance snap placement to current time"
+ ///
+ public static LocalisableString LimitedDistanceSnap => new TranslatableString(getKey(@"limited_distance_snap_grid"), @"Limit distance snap placement to current time");
+
private static string getKey(string key) => $@"{prefix}:{key}";
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
index d6e4e1f030..63886e38eb 100644
--- a/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/CircularDistanceSnapGrid.cs
@@ -18,6 +18,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
public abstract partial class CircularDistanceSnapGrid : DistanceSnapGrid
{
+ [Resolved]
+ private EditorClock editorClock { get; set; }
+
protected CircularDistanceSnapGrid(HitObject referenceObject, Vector2 startPosition, double startTime, double? endTime = null)
: base(referenceObject, startPosition, startTime, endTime)
{
@@ -98,9 +101,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
if (travelLength < DistanceBetweenTicks)
travelLength = DistanceBetweenTicks;
- // When interacting with the resolved snap provider, the distance spacing multiplier should first be removed
- // to allow for snapping at a non-multiplied ratio.
- float snappedDistance = SnapProvider.FindSnappedDistance(ReferenceObject, travelLength / distanceSpacingMultiplier);
+ float snappedDistance = LimitedDistanceSnap.Value
+ ? SnapProvider.DurationToDistance(ReferenceObject, editorClock.CurrentTime - ReferenceObject.GetEndTime())
+ // When interacting with the resolved snap provider, the distance spacing multiplier should first be removed
+ // to allow for snapping at a non-multiplied ratio.
+ : SnapProvider.FindSnappedDistance(ReferenceObject, travelLength / distanceSpacingMultiplier);
+
double snappedTime = StartTime + SnapProvider.DistanceToDuration(ReferenceObject, snappedDistance);
if (snappedTime > LatestEndTime)
diff --git a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
index 6092ebc08f..8aa2fa9f45 100644
--- a/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/DistanceSnapGrid.cs
@@ -10,6 +10,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Layout;
+using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
@@ -60,6 +61,18 @@ namespace osu.Game.Screens.Edit.Compose.Components
[Resolved]
private BindableBeatDivisor beatDivisor { get; set; }
+ ///
+ /// When enabled, distance snap should only snap to the current time (as per the editor clock).
+ /// This is to emulate stable behaviour.
+ ///
+ protected Bindable LimitedDistanceSnap { get; private set; }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager config)
+ {
+ LimitedDistanceSnap = config.GetBindable(OsuSetting.EditorLimitedDistanceSnap);
+ }
+
private readonly LayoutValue gridCache = new LayoutValue(Invalidation.RequiredParentSizeToFit);
protected readonly HitObject ReferenceObject;
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index 74947aab09..41c11ce5c1 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -185,6 +185,7 @@ namespace osu.Game.Screens.Edit
private Bindable editorBackgroundDim;
private Bindable editorHitMarkers;
private Bindable editorAutoSeekOnPlacement;
+ private Bindable editorLimitedDistanceSnap;
public Editor(EditorLoader loader = null)
{
@@ -276,6 +277,7 @@ namespace osu.Game.Screens.Edit
editorBackgroundDim = config.GetBindable(OsuSetting.EditorDim);
editorHitMarkers = config.GetBindable(OsuSetting.EditorShowHitMarkers);
editorAutoSeekOnPlacement = config.GetBindable(OsuSetting.EditorAutoSeekOnPlacement);
+ editorLimitedDistanceSnap = config.GetBindable(OsuSetting.EditorLimitedDistanceSnap);
AddInternal(new OsuContextMenuContainer
{
@@ -337,6 +339,10 @@ namespace osu.Game.Screens.Edit
new ToggleMenuItem(EditorStrings.AutoSeekOnPlacement)
{
State = { BindTarget = editorAutoSeekOnPlacement },
+ },
+ new ToggleMenuItem(EditorStrings.LimitedDistanceSnap)
+ {
+ State = { BindTarget = editorLimitedDistanceSnap },
}
}
},