1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 19:42:55 +08:00

Use structs for parts for added safety

This commit is contained in:
Dean Herbert 2020-11-19 18:05:41 +09:00
parent 3a7291c5cf
commit 84e73e88d5

View File

@ -13,8 +13,12 @@ using osuTK;
namespace osu.Game.Graphics namespace osu.Game.Graphics
{ {
/// <summary>
/// An explosion of textured particles based on how osu-stable randomises the explosion pattern.
/// </summary>
public class ParticleExplosion : Sprite public class ParticleExplosion : Sprite
{ {
private readonly int particleCount;
private readonly double duration; private readonly double duration;
private double startTime; private double startTime;
@ -23,11 +27,9 @@ namespace osu.Game.Graphics
public ParticleExplosion(Texture texture, int particleCount, double duration) public ParticleExplosion(Texture texture, int particleCount, double duration)
{ {
Texture = texture; Texture = texture;
this.particleCount = particleCount;
this.duration = duration; this.duration = duration;
Blending = BlendingParameters.Additive; Blending = BlendingParameters.Additive;
for (int i = 0; i < particleCount; i++)
parts.Add(new ParticlePart(duration));
} }
protected override void LoadComplete() protected override void LoadComplete()
@ -36,19 +38,23 @@ namespace osu.Game.Graphics
Restart(); Restart();
} }
/// <summary>
/// Restart the animation from the current point in time.
/// Supports transform time offset chaining.
/// </summary>
public void Restart() public void Restart()
{ {
startTime = TransformStartTime; startTime = TransformStartTime;
this.FadeOutFromOne(duration); this.FadeOutFromOne(duration);
foreach (var p in parts) parts.Clear();
p.Randomise(); for (int i = 0; i < particleCount; i++)
parts.Add(new ParticlePart(duration));
} }
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
Invalidate(Invalidation.DrawNode); Invalidate(Invalidation.DrawNode);
} }
@ -56,7 +62,7 @@ namespace osu.Game.Graphics
private class ParticleExplosionDrawNode : SpriteDrawNode private class ParticleExplosionDrawNode : SpriteDrawNode
{ {
private List<ParticlePart> parts = new List<ParticlePart>(); private readonly List<ParticlePart> parts = new List<ParticlePart>();
private ParticleExplosion source => (ParticleExplosion)Source; private ParticleExplosion source => (ParticleExplosion)Source;
@ -73,9 +79,9 @@ namespace osu.Game.Graphics
{ {
base.ApplyState(); base.ApplyState();
// this is mostly safe as the parts are immutable. parts.Clear();
// the most that can go wrong is the random state be incorrect parts.AddRange(source.parts);
parts = source.parts;
sourceSize = source.Size; sourceSize = source.Size;
startTime = source.startTime; startTime = source.startTime;
currentTime = source.Time.Current; currentTime = source.Time.Current;
@ -111,22 +117,13 @@ namespace osu.Game.Graphics
} }
} }
private class ParticlePart private readonly struct ParticlePart
{ {
private readonly double availableDuration; private readonly double duration;
private readonly double direction;
private double duration; private readonly float distance;
private double direction;
private float distance;
public ParticlePart(double availableDuration) public ParticlePart(double availableDuration)
{
this.availableDuration = availableDuration;
Randomise();
}
public void Randomise()
{ {
distance = RNG.NextSingle(0.5f); distance = RNG.NextSingle(0.5f);
duration = RNG.NextDouble(availableDuration / 3, availableDuration); duration = RNG.NextDouble(availableDuration / 3, availableDuration);
@ -137,12 +134,8 @@ namespace osu.Game.Graphics
public Vector2 PositionAtTime(double time) public Vector2 PositionAtTime(double time)
{ {
return new Vector2(0.5f) + positionForOffset(distance * progressAtTime(time)); var travelledDistance = distance * progressAtTime(time);
return new Vector2(0.5f) + travelledDistance * new Vector2((float)Math.Sin(direction), (float)Math.Cos(direction));
Vector2 positionForOffset(float offset) => new Vector2(
(float)(offset * Math.Sin(direction)),
(float)(offset * Math.Cos(direction))
);
} }
private float progressAtTime(double time) => (float)Math.Clamp(time / duration, 0, 1); private float progressAtTime(double time) => (float)Math.Clamp(time / duration, 0, 1);