diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs index 0c26c52171..b76e0e9bae 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/CaughtObject.cs @@ -21,11 +21,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public Bindable AccentColour { get; } = new Bindable(); public Bindable HyperDash { get; } = new Bindable(); public Bindable IndexInBeatmap { get; } = new Bindable(); - + public Vector2 DisplayPosition => DrawPosition; public Vector2 DisplaySize => Size * Scale; - public float DisplayRotation => Rotation; - public double DisplayStartTime => HitObject.StartTime; /// @@ -44,19 +42,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2); } - /// - /// Copies the hit object visual state from another object. - /// - public virtual void CopyStateFrom(IHasCatchObjectState objectState) - { - HitObject = objectState.HitObject; - Scale = Vector2.Divide(objectState.DisplaySize, Size); - Rotation = objectState.DisplayRotation; - AccentColour.Value = objectState.AccentColour.Value; - HyperDash.Value = objectState.HyperDash.Value; - IndexInBeatmap.Value = objectState.IndexInBeatmap.Value; - } - protected override void FreeAfterUse() { ClearTransforms(); @@ -64,5 +49,16 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables base.FreeAfterUse(); } + + public void RestoreState(CatchObjectState state) + { + HitObject = state.HitObject; + AccentColour.Value = state.AccentColour; + HyperDash.Value = state.HyperDash; + IndexInBeatmap.Value = state.IndexInBeatmap; + Position = state.DisplayPosition; + Scale = Vector2.Divide(state.DisplaySize, Size); + Rotation = state.DisplayRotation; + } } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs index ade00918ab..2919f69966 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawablePalpableCatchHitObject.cs @@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables /// protected readonly Container ScalingContainer; + public Vector2 DisplayPosition => DrawPosition; + public Vector2 DisplaySize => ScalingContainer.Size * ScalingContainer.Scale; public float DisplayRotation => ScalingContainer.Rotation; @@ -95,5 +97,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables base.OnFree(); } + + public void RestoreState(CatchObjectState state) => throw new NotSupportedException("Cannot restore state into a drawable catch hitobject."); } } diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs index 18fc0db6e3..e4a67d8fbf 100644 --- a/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs +++ b/osu.Game.Rulesets.Catch/Objects/Drawables/IHasCatchObjectState.cs @@ -13,17 +13,37 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables public interface IHasCatchObjectState { PalpableCatchHitObject HitObject { get; } - - double DisplayStartTime { get; } - Bindable AccentColour { get; } - Bindable HyperDash { get; } - Bindable IndexInBeatmap { get; } - + double DisplayStartTime { get; } + Vector2 DisplayPosition { get; } Vector2 DisplaySize { get; } - float DisplayRotation { get; } + + void RestoreState(CatchObjectState state); } + + public static class HasCatchObjectStateExtensions + { + public static CatchObjectState SaveState(this IHasCatchObjectState target) => new CatchObjectState( + target.HitObject, + target.AccentColour.Value, + target.HyperDash.Value, + target.IndexInBeatmap.Value, + target.DisplayStartTime, + target.DisplayPosition, + target.DisplaySize, + target.DisplayRotation); + } + + public readonly record struct CatchObjectState( + PalpableCatchHitObject HitObject, + Color4 AccentColour, + bool HyperDash, + int IndexInBeatmap, + double DisplayStartTime, + Vector2 DisplayPosition, + Vector2 DisplaySize, + float DisplayRotation); } diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index dca01fc61a..6a1b251d60 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Buffers; using System.Diagnostics; using System.Linq; using osu.Framework.Allocation; @@ -362,7 +363,7 @@ namespace osu.Game.Rulesets.Catch.UI if (caughtObject == null) return; - caughtObject.CopyStateFrom(drawableObject); + caughtObject.RestoreState(drawableObject.SaveState()); caughtObject.Anchor = Anchor.TopCentre; caughtObject.Position = position; caughtObject.Scale *= caught_fruit_scale_adjust; @@ -411,41 +412,50 @@ namespace osu.Game.Rulesets.Catch.UI } } - private CaughtObject getDroppedObject(CaughtObject caughtObject) + private CaughtObject getDroppedObject(CatchObjectState state) { - var droppedObject = getCaughtObject(caughtObject.HitObject); + var droppedObject = getCaughtObject(state.HitObject); Debug.Assert(droppedObject != null); - droppedObject.CopyStateFrom(caughtObject); + droppedObject.RestoreState(state); droppedObject.Anchor = Anchor.TopLeft; - droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(caughtObject.DrawPosition, droppedObjectTarget); + droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(state.DisplayPosition, droppedObjectTarget); return droppedObject; } private void clearPlate(DroppedObjectAnimation animation) { - var caughtObjects = caughtObjectContainer.Children.ToArray(); + int caughtCount = caughtObjectContainer.Children.Count; + CatchObjectState[] states = ArrayPool.Shared.Rent(caughtCount); - caughtObjectContainer.Clear(false); + try + { + for (int i = 0; i < caughtCount; i++) + states[i] = caughtObjectContainer.Children[i].SaveState(); - // Use the already returned PoolableDrawables for new objects - var droppedObjects = caughtObjects.Select(getDroppedObject).ToArray(); + caughtObjectContainer.Clear(false); - droppedObjectTarget.AddRange(droppedObjects); - - foreach (var droppedObject in droppedObjects) - applyDropAnimation(droppedObject, animation); + for (int i = 0; i < caughtCount; i++) + { + CaughtObject obj = getDroppedObject(states[i]); + droppedObjectTarget.Add(obj); + applyDropAnimation(obj, animation); + } + } + finally + { + ArrayPool.Shared.Return(states); + } } private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation) { + CatchObjectState state = caughtObject.SaveState(); caughtObjectContainer.Remove(caughtObject, false); - var droppedObject = getDroppedObject(caughtObject); - + var droppedObject = getDroppedObject(state); droppedObjectTarget.Add(droppedObject); - applyDropAnimation(droppedObject, animation); }