1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-21 21:00:42 +08:00

Merge pull request #33248 from chris-ehmann/fix-distance-snapping-to-stacks

Use stacked position when determining distance snap
This commit is contained in:
Bartłomiej Dach
2025-05-27 10:49:54 +02:00
committed by GitHub
Unverified
2 changed files with 20 additions and 10 deletions
@@ -15,7 +15,11 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
public class OsuBeatmapProcessor : BeatmapProcessor
{
private const int stack_distance = 3;
/// <summary>
/// The maximum distance between the end of one object and the start of another
/// which allows the objects to be stacked on top of another.
/// </summary>
public const int STACK_DISTANCE = 3;
public OsuBeatmapProcessor(IBeatmap beatmap)
: base(beatmap)
@@ -93,8 +97,8 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// We are no longer within stacking range of the next object.
break;
if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < stack_distance
|| (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < stack_distance))
if (Vector2Extensions.Distance(stackBaseObject.Position, objectN.Position) < STACK_DISTANCE
|| (stackBaseObject is Slider && Vector2Extensions.Distance(stackBaseObject.EndPosition, objectN.Position) < STACK_DISTANCE))
{
stackBaseIndex = n;
@@ -163,7 +167,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
* o <- hitCircle has stack of -1
* o <- hitCircle has stack of -2
*/
if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
if (objectN is Slider && Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < STACK_DISTANCE)
{
int offset = objectI.StackHeight - objectN.StackHeight + 1;
@@ -171,7 +175,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{
// For each object which was declared under this slider, we will offset it to appear *below* the slider end (rather than above).
OsuHitObject objectJ = hitObjects[j];
if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < stack_distance)
if (Vector2Extensions.Distance(objectN.EndPosition, objectJ.Position) < STACK_DISTANCE)
objectJ.StackHeight -= offset;
}
@@ -180,7 +184,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
break;
}
if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < stack_distance)
if (Vector2Extensions.Distance(objectN.Position, objectI.Position) < STACK_DISTANCE)
{
// Keep processing as if there are no sliders. If we come across a slider, this gets cancelled out.
//NOTE: Sliders with start positions stacking are a special case that is also handled here.
@@ -204,7 +208,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// We are no longer within stacking range of the previous object.
break;
if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < stack_distance)
if (Vector2Extensions.Distance(objectN.EndPosition, objectI.Position) < STACK_DISTANCE)
{
objectN.StackHeight = objectI.StackHeight + 1;
objectI = objectN;
@@ -245,12 +249,12 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
// Effects of this can be seen on https://osu.ppy.sh/beatmapsets/243#osu/1146 at sliders around 86647 ms, where
// if we use `EndTime` here it would result in unexpected stacking.
if (Vector2Extensions.Distance(hitObjects[j].Position, currHitObject.Position) < stack_distance)
if (Vector2Extensions.Distance(hitObjects[j].Position, currHitObject.Position) < STACK_DISTANCE)
{
currHitObject.StackHeight++;
startTime = hitObjects[j].StartTime;
}
else if (Vector2Extensions.Distance(hitObjects[j].Position, position2) < stack_distance)
else if (Vector2Extensions.Distance(hitObjects[j].Position, position2) < STACK_DISTANCE)
{
// Case for sliders - bump notes down and right, rather than up and left.
sliderStack++;
@@ -7,6 +7,7 @@ using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Osu.Beatmaps;
using osu.Game.Rulesets.Osu.Objects;
using osuTK;
@@ -16,10 +17,15 @@ namespace osu.Game.Rulesets.Osu.Edit
{
public override double ReadCurrentDistanceSnap(HitObject before, HitObject after)
{
// If the pair of hit objects in question here could feasibly be on the same stack, do not provide a distance snap value -
// they're likely too close to one another for the distance snap value to be useful anyway even if they somehow are not.
if (Vector2.Distance(((OsuHitObject)before).EndPosition, ((OsuHitObject)after).Position) < OsuBeatmapProcessor.STACK_DISTANCE)
return 0;
var lastObjectWithVelocity = EditorBeatmap.HitObjects.TakeWhile(ho => ho != after).OfType<IHasSliderVelocity>().LastOrDefault();
float expectedDistance = DurationToDistance(after.StartTime - before.GetEndTime(), before.StartTime, lastObjectWithVelocity);
float actualDistance = Vector2.Distance(((OsuHitObject)before).EndPosition, ((OsuHitObject)after).Position);
float actualDistance = Vector2.Distance(((OsuHitObject)before).StackedEndPosition, ((OsuHitObject)after).StackedPosition);
return actualDistance / expectedDistance;
}