mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 22:27:25 +08:00
Merge pull request #28792 from bdach/stacking-updates
Run stacking while performing movement in osu! composer
This commit is contained in:
commit
fb8f80f1e2
@ -42,7 +42,12 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
{
|
||||
base.PostProcess();
|
||||
|
||||
var hitObjects = Beatmap.HitObjects as List<OsuHitObject> ?? Beatmap.HitObjects.OfType<OsuHitObject>().ToList();
|
||||
ApplyStacking(Beatmap);
|
||||
}
|
||||
|
||||
internal static void ApplyStacking(IBeatmap beatmap)
|
||||
{
|
||||
var hitObjects = beatmap.HitObjects as List<OsuHitObject> ?? beatmap.HitObjects.OfType<OsuHitObject>().ToList();
|
||||
|
||||
if (hitObjects.Count > 0)
|
||||
{
|
||||
@ -50,14 +55,14 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
foreach (var h in hitObjects)
|
||||
h.StackHeight = 0;
|
||||
|
||||
if (Beatmap.BeatmapInfo.BeatmapVersion >= 6)
|
||||
applyStacking(Beatmap.BeatmapInfo, hitObjects, 0, hitObjects.Count - 1);
|
||||
if (beatmap.BeatmapInfo.BeatmapVersion >= 6)
|
||||
applyStacking(beatmap.BeatmapInfo, hitObjects, 0, hitObjects.Count - 1);
|
||||
else
|
||||
applyStackingOld(Beatmap.BeatmapInfo, hitObjects);
|
||||
applyStackingOld(beatmap.BeatmapInfo, hitObjects);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyStacking(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects, int startIndex, int endIndex)
|
||||
private static void applyStacking(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects, int startIndex, int endIndex)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex, endIndex);
|
||||
ArgumentOutOfRangeException.ThrowIfNegative(startIndex);
|
||||
@ -209,7 +214,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
private void applyStackingOld(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects)
|
||||
private static void applyStackingOld(BeatmapInfo beatmapInfo, List<OsuHitObject> hitObjects)
|
||||
{
|
||||
for (int i = 0; i < hitObjects.Count; i++)
|
||||
{
|
||||
|
@ -295,6 +295,12 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
|
||||
if (Vector2.Distance(closestSnapPosition, screenSpacePosition) < snapRadius)
|
||||
{
|
||||
// if the snap target is a stacked object, snap to its unstacked position rather than its stacked position.
|
||||
// this is intended to make working with stacks easier (because thanks to this, you can drag an object to any
|
||||
// of the items on the stack to add an object to it, rather than having to drag to the position of the *first* object on it at all times).
|
||||
if (b.Item is OsuHitObject osuObject && osuObject.StackOffset != Vector2.Zero)
|
||||
closestSnapPosition = b.ToScreenSpace(b.ToLocalSpace(closestSnapPosition) - osuObject.StackOffset);
|
||||
|
||||
// only return distance portion, since time is not really valid
|
||||
snapResult = new SnapResult(closestSnapPosition, null, playfield);
|
||||
return true;
|
||||
|
@ -13,6 +13,7 @@ using osu.Game.Graphics.UserInterface;
|
||||
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 osu.Game.Rulesets.Osu.UI;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
@ -50,12 +51,33 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
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();
|
||||
|
||||
// manually update stacking.
|
||||
// this intentionally bypasses the editor `UpdateState()` / beatmap processor flow for performance reasons,
|
||||
// as the entire flow is too expensive to run on every movement.
|
||||
Scheduler.AddOnce(OsuBeatmapProcessor.ApplyStacking, EditorBeatmap);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user