mirror of
https://github.com/osukey/osukey.git
synced 2025-06-05 12:57:39 +09:00
Remove abstract from ParticleSpewer
This commit is contained in:
parent
ef530ed87c
commit
3f8454cb76
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// 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.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
@ -20,12 +20,17 @@ using osuTK.Graphics;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
||||||
{
|
{
|
||||||
public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler<OsuAction>
|
public class LegacyCursorParticles : CompositeDrawable, IKeyBindingHandler<OsuAction>, IRequireHighFrequencyMousePosition
|
||||||
{
|
{
|
||||||
|
private const int particle_lifetime_min = 300;
|
||||||
|
private const int particle_lifetime_max = 1000;
|
||||||
|
private const float particle_gravity = 240;
|
||||||
|
|
||||||
public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true;
|
public bool Active => breakSpewer?.Active.Value == true || kiaiSpewer?.Active.Value == true;
|
||||||
|
|
||||||
private LegacyCursorParticleSpewer breakSpewer;
|
private Vector2 cursorVelocity;
|
||||||
private LegacyCursorParticleSpewer kiaiSpewer;
|
private ParticleSpewer breakSpewer;
|
||||||
|
private ParticleSpewer kiaiSpewer;
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private Player player { get; set; }
|
private Player player { get; set; }
|
||||||
@ -45,21 +50,25 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
texture.ScaleAdjust *= 1.6f;
|
texture.ScaleAdjust *= 1.6f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
Anchor = Anchor.Centre;
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
breakSpewer = new LegacyCursorParticleSpewer(texture, 20)
|
breakSpewer = new ParticleSpewer(texture, 20, particle_lifetime_max)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Size = Vector2.One,
|
||||||
Colour = starBreakAdditive,
|
Colour = starBreakAdditive,
|
||||||
Direction = SpewDirection.None,
|
ParticleGravity = particle_gravity,
|
||||||
|
CreateParticle = createBreakParticle,
|
||||||
},
|
},
|
||||||
kiaiSpewer = new LegacyCursorParticleSpewer(texture, 60)
|
kiaiSpewer = new ParticleSpewer(texture, 60, particle_lifetime_max)
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Origin = Anchor.Centre,
|
Size = Vector2.One,
|
||||||
Colour = starBreakAdditive,
|
Colour = starBreakAdditive,
|
||||||
Direction = SpewDirection.None,
|
ParticleGravity = particle_gravity,
|
||||||
|
CreateParticle = createParticle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -85,6 +94,39 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
kiaiSpewer.Active.Value = kiaiHitObject != null;
|
kiaiSpewer.Active.Value = kiaiHitObject != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2? cursorScreenPosition;
|
||||||
|
|
||||||
|
private const double max_velocity_frame_length = 15;
|
||||||
|
private double velocityFrameLength;
|
||||||
|
private Vector2 totalPosDifference;
|
||||||
|
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
||||||
|
|
||||||
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
|
{
|
||||||
|
if (cursorScreenPosition == null)
|
||||||
|
{
|
||||||
|
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate cursor velocity.
|
||||||
|
totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value;
|
||||||
|
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
||||||
|
|
||||||
|
velocityFrameLength += Math.Abs(Clock.ElapsedFrameTime);
|
||||||
|
|
||||||
|
if (velocityFrameLength > max_velocity_frame_length)
|
||||||
|
{
|
||||||
|
cursorVelocity = totalPosDifference / (float)velocityFrameLength;
|
||||||
|
|
||||||
|
totalPosDifference = Vector2.Zero;
|
||||||
|
velocityFrameLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnMouseMove(e);
|
||||||
|
}
|
||||||
|
|
||||||
public bool OnPressed(OsuAction action)
|
public bool OnPressed(OsuAction action)
|
||||||
{
|
{
|
||||||
handleInput(action, true);
|
handleInput(action, true);
|
||||||
@ -111,125 +153,53 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
|
|||||||
rightPressed = pressed;
|
rightPressed = pressed;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParticleSpewer.FallingParticle? createParticle()
|
||||||
|
{
|
||||||
|
if (!cursorScreenPosition.HasValue) return null;
|
||||||
|
|
||||||
|
return new ParticleSpewer.FallingParticle
|
||||||
|
{
|
||||||
|
StartPosition = ToLocalSpace(cursorScreenPosition.Value),
|
||||||
|
Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max),
|
||||||
|
StartAngle = (float)(RNG.NextDouble() * 4 - 2),
|
||||||
|
EndAngle = RNG.NextSingle(-2f, 2f),
|
||||||
|
EndScale = RNG.NextSingle(2f),
|
||||||
|
Velocity = cursorVelocity * 40,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParticleSpewer.FallingParticle? createBreakParticle()
|
||||||
|
{
|
||||||
|
var baseParticle = createParticle();
|
||||||
|
if (!baseParticle.HasValue) return null;
|
||||||
|
|
||||||
|
var p = baseParticle.Value;
|
||||||
|
|
||||||
if (leftPressed && rightPressed)
|
if (leftPressed && rightPressed)
|
||||||
breakSpewer.Direction = SpewDirection.Omni;
|
{
|
||||||
|
p.Velocity += new Vector2(
|
||||||
|
RNG.NextSingle(-460f, 460f),
|
||||||
|
RNG.NextSingle(-160f, 160f)
|
||||||
|
);
|
||||||
|
}
|
||||||
else if (leftPressed)
|
else if (leftPressed)
|
||||||
breakSpewer.Direction = SpewDirection.Left;
|
{
|
||||||
|
p.Velocity += new Vector2(
|
||||||
|
RNG.NextSingle(-460f, 0),
|
||||||
|
RNG.NextSingle(-40f, 40f)
|
||||||
|
);
|
||||||
|
}
|
||||||
else if (rightPressed)
|
else if (rightPressed)
|
||||||
breakSpewer.Direction = SpewDirection.Right;
|
|
||||||
else
|
|
||||||
breakSpewer.Direction = SpewDirection.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class LegacyCursorParticleSpewer : ParticleSpewer, IRequireHighFrequencyMousePosition
|
|
||||||
{
|
|
||||||
private const int particle_lifetime_min = 300;
|
|
||||||
private const int particle_lifetime_max = 1000;
|
|
||||||
|
|
||||||
public SpewDirection Direction { get; set; }
|
|
||||||
|
|
||||||
protected override bool CanSpawnParticles => base.CanSpawnParticles && cursorScreenPosition.HasValue;
|
|
||||||
protected override float ParticleGravity => 240;
|
|
||||||
|
|
||||||
public LegacyCursorParticleSpewer(Texture texture, int perSecond)
|
|
||||||
: base(texture, perSecond, particle_lifetime_max)
|
|
||||||
{
|
{
|
||||||
Active.BindValueChanged(_ => resetVelocityCalculation());
|
p.Velocity += new Vector2(
|
||||||
|
RNG.NextSingle(0, 460f),
|
||||||
|
RNG.NextSingle(-40f, 40f)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2? cursorScreenPosition;
|
return p;
|
||||||
private Vector2 cursorVelocity;
|
|
||||||
|
|
||||||
private const double max_velocity_frame_length = 15;
|
|
||||||
private double velocityFrameLength;
|
|
||||||
private Vector2 totalPosDifference;
|
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true;
|
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
|
||||||
{
|
|
||||||
if (cursorScreenPosition == null)
|
|
||||||
{
|
|
||||||
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate cursor velocity.
|
|
||||||
totalPosDifference += e.ScreenSpaceMousePosition - cursorScreenPosition.Value;
|
|
||||||
cursorScreenPosition = e.ScreenSpaceMousePosition;
|
|
||||||
|
|
||||||
velocityFrameLength += Clock.ElapsedFrameTime;
|
|
||||||
|
|
||||||
if (velocityFrameLength > max_velocity_frame_length)
|
|
||||||
{
|
|
||||||
cursorVelocity = totalPosDifference / (float)velocityFrameLength;
|
|
||||||
|
|
||||||
totalPosDifference = Vector2.Zero;
|
|
||||||
velocityFrameLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return base.OnMouseMove(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetVelocityCalculation()
|
|
||||||
{
|
|
||||||
cursorScreenPosition = null;
|
|
||||||
totalPosDifference = Vector2.Zero;
|
|
||||||
velocityFrameLength = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override FallingParticle CreateParticle() =>
|
|
||||||
new FallingParticle
|
|
||||||
{
|
|
||||||
StartPosition = ToLocalSpace(cursorScreenPosition ?? Vector2.Zero),
|
|
||||||
Duration = RNG.NextSingle(particle_lifetime_min, particle_lifetime_max),
|
|
||||||
StartAngle = (float)(RNG.NextDouble() * 4 - 2),
|
|
||||||
EndAngle = RNG.NextSingle(-2f, 2f),
|
|
||||||
EndScale = RNG.NextSingle(2f),
|
|
||||||
Velocity = getVelocity(),
|
|
||||||
};
|
|
||||||
|
|
||||||
private Vector2 getVelocity()
|
|
||||||
{
|
|
||||||
Vector2 velocity = Vector2.Zero;
|
|
||||||
|
|
||||||
switch (Direction)
|
|
||||||
{
|
|
||||||
case SpewDirection.Left:
|
|
||||||
velocity = new Vector2(
|
|
||||||
RNG.NextSingle(-460f, 0),
|
|
||||||
RNG.NextSingle(-40f, 40f)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SpewDirection.Right:
|
|
||||||
velocity = new Vector2(
|
|
||||||
RNG.NextSingle(0, 460f),
|
|
||||||
RNG.NextSingle(-40f, 40f)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SpewDirection.Omni:
|
|
||||||
velocity = new Vector2(
|
|
||||||
RNG.NextSingle(-460f, 460f),
|
|
||||||
RNG.NextSingle(-160f, 160f)
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
velocity += cursorVelocity * 40;
|
|
||||||
|
|
||||||
return velocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum SpewDirection
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Omni,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ using System;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -17,7 +16,12 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TestSceneParticleSpewer : OsuTestScene
|
public class TestSceneParticleSpewer : OsuTestScene
|
||||||
{
|
{
|
||||||
private TestParticleSpewer spewer;
|
private const int max_particle_duration = 1500;
|
||||||
|
|
||||||
|
private float particleMaxVelocity = 0.5f;
|
||||||
|
private Vector2 particleSpawnPosition = new Vector2(0.5f);
|
||||||
|
|
||||||
|
private ParticleSpewer spewer;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinManager skinManager { get; set; }
|
private SkinManager skinManager { get; set; }
|
||||||
@ -28,11 +32,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
Child = spewer = createSpewer();
|
Child = spewer = createSpewer();
|
||||||
|
|
||||||
AddToggleStep("toggle spawning", value => spewer.Active.Value = value);
|
AddToggleStep("toggle spawning", value => spewer.Active.Value = value);
|
||||||
AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.Gravity = value);
|
AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => particleMaxVelocity = value);
|
||||||
AddSliderStep("particle velocity", 0f, 1f, 0.5f, value => spewer.MaxVelocity = value);
|
AddSliderStep("particle gravity", 0f, 1f, 0f, value => spewer.ParticleGravity = value);
|
||||||
AddStep("move to new location", () =>
|
AddStep("move to new location", () =>
|
||||||
{
|
{
|
||||||
spewer.TransformTo(nameof(spewer.SpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out);
|
this.TransformTo(nameof(particleSpawnPosition), new Vector2(RNG.NextSingle(), RNG.NextSingle()), 1000, Easing.Out);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,47 +59,29 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddAssert("is not present", () => !spewer.IsPresent);
|
AddAssert("is not present", () => !spewer.IsPresent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TestParticleSpewer createSpewer() =>
|
private ParticleSpewer createSpewer() =>
|
||||||
new TestParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2"))
|
new ParticleSpewer(skinManager.DefaultLegacySkin.GetTexture("star2"), 1500, max_particle_duration)
|
||||||
{
|
{
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativePositionAxes = Axes.Both,
|
RelativePositionAxes = Axes.Both,
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Position = new Vector2(0.5f),
|
Position = new Vector2(0.5f),
|
||||||
Size = new Vector2(0.5f),
|
Size = new Vector2(0.5f),
|
||||||
|
CreateParticle = createParticle,
|
||||||
};
|
};
|
||||||
|
|
||||||
private class TestParticleSpewer : ParticleSpewer
|
private ParticleSpewer.FallingParticle? createParticle() =>
|
||||||
{
|
new ParticleSpewer.FallingParticle
|
||||||
private const int lifetime = 1500;
|
|
||||||
private const int rate = 250;
|
|
||||||
|
|
||||||
public float Gravity;
|
|
||||||
|
|
||||||
public float MaxVelocity = 0.25f;
|
|
||||||
|
|
||||||
public Vector2 SpawnPosition { get; set; } = new Vector2(0.5f);
|
|
||||||
|
|
||||||
protected override float ParticleGravity => Gravity;
|
|
||||||
|
|
||||||
public TestParticleSpewer(Texture texture)
|
|
||||||
: base(texture, rate, lifetime)
|
|
||||||
{
|
{
|
||||||
}
|
Velocity = new Vector2(
|
||||||
|
RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity),
|
||||||
protected override FallingParticle CreateParticle() =>
|
RNG.NextSingle(-particleMaxVelocity, particleMaxVelocity)
|
||||||
new FallingParticle
|
),
|
||||||
{
|
StartPosition = particleSpawnPosition,
|
||||||
Velocity = new Vector2(
|
Duration = RNG.NextSingle(max_particle_duration),
|
||||||
RNG.NextSingle(-MaxVelocity, MaxVelocity),
|
StartAngle = RNG.NextSingle(MathF.PI * 2),
|
||||||
RNG.NextSingle(-MaxVelocity, MaxVelocity)
|
EndAngle = RNG.NextSingle(MathF.PI * 2),
|
||||||
),
|
EndScale = RNG.NextSingle(0.5f, 1.5f)
|
||||||
StartPosition = SpawnPosition,
|
};
|
||||||
Duration = RNG.NextSingle(lifetime),
|
|
||||||
StartAngle = RNG.NextSingle(MathF.PI * 2),
|
|
||||||
EndAngle = RNG.NextSingle(MathF.PI * 2),
|
|
||||||
EndScale = RNG.NextSingle(0.5f, 1.5f)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,14 @@ using osuTK;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics
|
namespace osu.Game.Graphics
|
||||||
{
|
{
|
||||||
public abstract class ParticleSpewer : Sprite
|
public class ParticleSpewer : Sprite
|
||||||
{
|
{
|
||||||
private readonly FallingParticle[] particles;
|
private readonly FallingParticle[] particles;
|
||||||
private int currentIndex;
|
private int currentIndex;
|
||||||
private double lastParticleAdded;
|
private double lastParticleAdded;
|
||||||
|
|
||||||
private readonly double cooldown;
|
private readonly double cooldown;
|
||||||
private readonly double maxLifetime;
|
private readonly double maxDuration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether particles are being spawned.
|
/// Determines whether particles are being spawned.
|
||||||
@ -29,20 +29,24 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
public override bool IsPresent => base.IsPresent && hasActiveParticles;
|
public override bool IsPresent => base.IsPresent && hasActiveParticles;
|
||||||
|
|
||||||
protected virtual bool CanSpawnParticles => true;
|
/// <summary>
|
||||||
protected virtual float ParticleGravity => 0;
|
/// Called each time a new particle should be spawned.
|
||||||
|
/// </summary>
|
||||||
|
public Func<FallingParticle?> CreateParticle = () => new FallingParticle();
|
||||||
|
|
||||||
private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxLifetime) > Time.Current;
|
public float ParticleGravity;
|
||||||
|
|
||||||
protected ParticleSpewer(Texture texture, int perSecond, double maxLifetime)
|
private bool hasActiveParticles => Active.Value || (lastParticleAdded + maxDuration) > Time.Current;
|
||||||
|
|
||||||
|
public ParticleSpewer(Texture texture, int perSecond, double maxDuration)
|
||||||
{
|
{
|
||||||
Texture = texture;
|
Texture = texture;
|
||||||
Blending = BlendingParameters.Additive;
|
Blending = BlendingParameters.Additive;
|
||||||
|
|
||||||
particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxLifetime / 1000)];
|
particles = new FallingParticle[perSecond * (int)Math.Ceiling(maxDuration / 1000)];
|
||||||
|
|
||||||
cooldown = 1000f / perSecond;
|
cooldown = 1000f / perSecond;
|
||||||
this.maxLifetime = maxLifetime;
|
this.maxDuration = maxDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -53,25 +57,25 @@ namespace osu.Game.Graphics
|
|||||||
// this can happen when seeking in replays.
|
// this can happen when seeking in replays.
|
||||||
if (lastParticleAdded > Time.Current) lastParticleAdded = 0;
|
if (lastParticleAdded > Time.Current) lastParticleAdded = 0;
|
||||||
|
|
||||||
if (Active.Value && CanSpawnParticles && Time.Current > lastParticleAdded + cooldown)
|
if (Active.Value && Time.Current > lastParticleAdded + cooldown)
|
||||||
{
|
{
|
||||||
var newParticle = CreateParticle();
|
var newParticle = CreateParticle();
|
||||||
newParticle.StartTime = (float)Time.Current;
|
|
||||||
|
|
||||||
particles[currentIndex] = newParticle;
|
if (newParticle.HasValue)
|
||||||
|
{
|
||||||
|
var particle = newParticle.Value;
|
||||||
|
particle.StartTime = (float)Time.Current;
|
||||||
|
|
||||||
currentIndex = (currentIndex + 1) % particles.Length;
|
particles[currentIndex] = particle;
|
||||||
lastParticleAdded = Time.Current;
|
|
||||||
|
currentIndex = (currentIndex + 1) % particles.Length;
|
||||||
|
lastParticleAdded = Time.Current;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Invalidate(Invalidation.DrawNode);
|
Invalidate(Invalidation.DrawNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Called each time a new particle should be spawned.
|
|
||||||
/// </summary>
|
|
||||||
protected virtual FallingParticle CreateParticle() => new FallingParticle();
|
|
||||||
|
|
||||||
protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this);
|
protected override DrawNode CreateDrawNode() => new ParticleSpewerDrawNode(this);
|
||||||
|
|
||||||
# region DrawNode
|
# region DrawNode
|
||||||
@ -82,7 +86,7 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
protected new ParticleSpewer Source => (ParticleSpewer)base.Source;
|
protected new ParticleSpewer Source => (ParticleSpewer)base.Source;
|
||||||
|
|
||||||
private readonly float maxLifetime;
|
private readonly float maxDuration;
|
||||||
|
|
||||||
private float currentTime;
|
private float currentTime;
|
||||||
private float gravity;
|
private float gravity;
|
||||||
@ -93,7 +97,7 @@ namespace osu.Game.Graphics
|
|||||||
: base(source)
|
: base(source)
|
||||||
{
|
{
|
||||||
particles = new FallingParticle[Source.particles.Length];
|
particles = new FallingParticle[Source.particles.Length];
|
||||||
maxLifetime = (float)Source.maxLifetime;
|
maxDuration = (float)Source.maxDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ApplyState()
|
public override void ApplyState()
|
||||||
@ -124,7 +128,7 @@ namespace osu.Game.Graphics
|
|||||||
var alpha = p.AlphaAtTime(timeSinceStart);
|
var alpha = p.AlphaAtTime(timeSinceStart);
|
||||||
if (alpha <= 0) continue;
|
if (alpha <= 0) continue;
|
||||||
|
|
||||||
var pos = p.PositionAtTime(timeSinceStart, gravity, maxLifetime);
|
var pos = p.PositionAtTime(timeSinceStart, gravity, maxDuration);
|
||||||
var scale = p.ScaleAtTime(timeSinceStart);
|
var scale = p.ScaleAtTime(timeSinceStart);
|
||||||
var angle = p.AngleAtTime(timeSinceStart);
|
var angle = p.AngleAtTime(timeSinceStart);
|
||||||
|
|
||||||
@ -174,7 +178,7 @@ namespace osu.Game.Graphics
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
protected struct FallingParticle
|
public struct FallingParticle
|
||||||
{
|
{
|
||||||
public float StartTime;
|
public float StartTime;
|
||||||
public Vector2 StartPosition;
|
public Vector2 StartPosition;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user