Run stacking when performing movement in osu! composer

Closes https://github.com/ppy/osu/issues/28635.
This commit is contained in:
Bartłomiej Dach 2024-07-09 13:52:36 +02:00
parent 13c8370823
commit ec9040798f
No known key found for this signature in database
1 changed files with 22 additions and 1 deletions

View File

@ -50,12 +50,33 @@ public override bool HandleMovement(MoveSelectionEvent<HitObject> moveEvent)
{
var hitObjects = selectedMovableObjects;
var localDelta = this.ScreenSpaceDeltaToParentSpace(moveEvent.ScreenSpaceDelta);
// this conditional is a rather ugly special case for stacks.
// as it turns out, adding the `EditorBeatmap.Update()` call at the end of this would cause stacked objects to jitter when moved around
// (they would stack and then unstack every frame).
// the reason for that is that the selection handling abstractions are not aware of the distinction between "displayed" and "actual" position
// which is unique to osu! due to stacking being applied as a post-processing step.
// therefore, the following loop would occur:
// - on frame 1 the blueprint is snapped to the stack's baseline position. `EditorBeatmap.Update()` applies stacking successfully,
// the blueprint moves up the stack from its original drag position.
// - on frame 2 the blueprint's position is now the *stacked* position, which is interpreted higher up as *manually performing an unstack*
// to the blueprint's unstacked position (as the machinery higher up only cares about differences in screen space position).
if (hitObjects.Any(h => Precision.AlmostEquals(localDelta, -h.StackOffset)))
return true;
// this will potentially move the selection out of bounds...
foreach (var h in hitObjects)
h.Position += this.ScreenSpaceDeltaToParentSpace(moveEvent.ScreenSpaceDelta);
h.Position += localDelta;
// but this will be corrected.
moveSelectionInBounds();
// update all of the objects in order to update stacking.
// in particular, this causes stacked objects to instantly unstack on drag.
foreach (var h in hitObjects)
EditorBeatmap.Update(h);
return true;
}