1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 08:13:31 +08:00

Fix fruit positions getting mangled when exploded

This commit is contained in:
Dan Balasescu 2024-08-13 18:07:52 +09:00
parent 93c1a27f22
commit fbfe3a4887
No known key found for this signature in database
4 changed files with 69 additions and 39 deletions

View File

@ -21,11 +21,9 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public Bindable<Color4> AccentColour { get; } = new Bindable<Color4>(); public Bindable<Color4> AccentColour { get; } = new Bindable<Color4>();
public Bindable<bool> HyperDash { get; } = new Bindable<bool>(); public Bindable<bool> HyperDash { get; } = new Bindable<bool>();
public Bindable<int> IndexInBeatmap { get; } = new Bindable<int>(); public Bindable<int> IndexInBeatmap { get; } = new Bindable<int>();
public Vector2 DisplayPosition => DrawPosition;
public Vector2 DisplaySize => Size * Scale; public Vector2 DisplaySize => Size * Scale;
public float DisplayRotation => Rotation; public float DisplayRotation => Rotation;
public double DisplayStartTime => HitObject.StartTime; public double DisplayStartTime => HitObject.StartTime;
/// <summary> /// <summary>
@ -44,19 +42,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2); Size = new Vector2(CatchHitObject.OBJECT_RADIUS * 2);
} }
/// <summary>
/// Copies the hit object visual state from another <see cref="IHasCatchObjectState"/> object.
/// </summary>
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() protected override void FreeAfterUse()
{ {
ClearTransforms(); ClearTransforms();
@ -64,5 +49,16 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
base.FreeAfterUse(); 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;
}
} }
} }

View File

@ -37,6 +37,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
/// </summary> /// </summary>
protected readonly Container ScalingContainer; protected readonly Container ScalingContainer;
public Vector2 DisplayPosition => DrawPosition;
public Vector2 DisplaySize => ScalingContainer.Size * ScalingContainer.Scale; public Vector2 DisplaySize => ScalingContainer.Size * ScalingContainer.Scale;
public float DisplayRotation => ScalingContainer.Rotation; public float DisplayRotation => ScalingContainer.Rotation;
@ -95,5 +97,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
base.OnFree(); base.OnFree();
} }
public void RestoreState(CatchObjectState state) => throw new NotSupportedException("Cannot restore state into a drawable catch hitobject.");
} }
} }

View File

@ -13,17 +13,37 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public interface IHasCatchObjectState public interface IHasCatchObjectState
{ {
PalpableCatchHitObject HitObject { get; } PalpableCatchHitObject HitObject { get; }
double DisplayStartTime { get; }
Bindable<Color4> AccentColour { get; } Bindable<Color4> AccentColour { get; }
Bindable<bool> HyperDash { get; } Bindable<bool> HyperDash { get; }
Bindable<int> IndexInBeatmap { get; } Bindable<int> IndexInBeatmap { get; }
double DisplayStartTime { get; }
Vector2 DisplayPosition { get; }
Vector2 DisplaySize { get; } Vector2 DisplaySize { get; }
float DisplayRotation { 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);
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -362,7 +363,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (caughtObject == null) return; if (caughtObject == null) return;
caughtObject.CopyStateFrom(drawableObject); caughtObject.RestoreState(drawableObject.SaveState());
caughtObject.Anchor = Anchor.TopCentre; caughtObject.Anchor = Anchor.TopCentre;
caughtObject.Position = position; caughtObject.Position = position;
caughtObject.Scale *= caught_fruit_scale_adjust; 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); Debug.Assert(droppedObject != null);
droppedObject.CopyStateFrom(caughtObject); droppedObject.RestoreState(state);
droppedObject.Anchor = Anchor.TopLeft; droppedObject.Anchor = Anchor.TopLeft;
droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(caughtObject.DrawPosition, droppedObjectTarget); droppedObject.Position = caughtObjectContainer.ToSpaceOfOtherDrawable(state.DisplayPosition, droppedObjectTarget);
return droppedObject; return droppedObject;
} }
private void clearPlate(DroppedObjectAnimation animation) private void clearPlate(DroppedObjectAnimation animation)
{ {
var caughtObjects = caughtObjectContainer.Children.ToArray(); int caughtCount = caughtObjectContainer.Children.Count;
CatchObjectState[] states = ArrayPool<CatchObjectState>.Shared.Rent(caughtCount);
try
{
for (int i = 0; i < caughtCount; i++)
states[i] = caughtObjectContainer.Children[i].SaveState();
caughtObjectContainer.Clear(false); caughtObjectContainer.Clear(false);
// Use the already returned PoolableDrawables for new objects for (int i = 0; i < caughtCount; i++)
var droppedObjects = caughtObjects.Select(getDroppedObject).ToArray(); {
CaughtObject obj = getDroppedObject(states[i]);
droppedObjectTarget.AddRange(droppedObjects); droppedObjectTarget.Add(obj);
applyDropAnimation(obj, animation);
foreach (var droppedObject in droppedObjects) }
applyDropAnimation(droppedObject, animation); }
finally
{
ArrayPool<CatchObjectState>.Shared.Return(states);
}
} }
private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation) private void removeFromPlate(CaughtObject caughtObject, DroppedObjectAnimation animation)
{ {
CatchObjectState state = caughtObject.SaveState();
caughtObjectContainer.Remove(caughtObject, false); caughtObjectContainer.Remove(caughtObject, false);
var droppedObject = getDroppedObject(caughtObject); var droppedObject = getDroppedObject(state);
droppedObjectTarget.Add(droppedObject); droppedObjectTarget.Add(droppedObject);
applyDropAnimation(droppedObject, animation); applyDropAnimation(droppedObject, animation);
} }