Rewrote the particles to allow for more advanced particles.
+ Particles can now be detached from the object. + Each particle now has an own Lifetime, that can be controlled. + Particles can now appear in a continuous way.
This commit is contained in:
parent
651628401d
commit
db7f01dca1
9 changed files with 171 additions and 109 deletions
|
|
@ -1,24 +0,0 @@
|
||||||
#region usings
|
|
||||||
|
|
||||||
using SM.Base.Time;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
namespace SM.Base.Drawing.Particles
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A context, with that the particle system sends the information for the movement function.
|
|
||||||
/// </summary>
|
|
||||||
public struct ParticleContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The Timer of the particles
|
|
||||||
/// </summary>
|
|
||||||
public Timer Timer;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The current speed of the particles.
|
|
||||||
/// </summary>
|
|
||||||
public float Speed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -18,6 +18,18 @@ namespace SM.Base.Drawing.Particles
|
||||||
where TTransform : GenericTransformation, new()
|
where TTransform : GenericTransformation, new()
|
||||||
where TDirection : struct
|
where TDirection : struct
|
||||||
{
|
{
|
||||||
|
private float? _continuesIntervalSeconds = null;
|
||||||
|
private Interval _continuesInterval;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The stopwatch of the particles.
|
||||||
|
/// </summary>
|
||||||
|
protected Timer timer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This contains the different instances for the particles.
|
||||||
|
/// </summary>
|
||||||
|
protected List<ParticleInstance<TDirection>> instances;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The amount of particles
|
/// The amount of particles
|
||||||
|
|
@ -25,24 +37,38 @@ namespace SM.Base.Drawing.Particles
|
||||||
public int Amount = 32;
|
public int Amount = 32;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This contains the different instances for the particles.
|
/// The base lifetime for particles in seconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected List<Instance> instances;
|
public float Lifetime;
|
||||||
|
/// <summary>
|
||||||
|
/// Ranomizes the lifetime for particles.
|
||||||
|
/// </summary>
|
||||||
|
public float LifetimeRandomize = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If set to any value (except null), it will create the particles continuously.
|
||||||
|
/// </summary>
|
||||||
|
public float? ContinuousInterval
|
||||||
|
{
|
||||||
|
get => _continuesIntervalSeconds;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value.HasValue)
|
||||||
|
{
|
||||||
|
_continuesInterval.Target = value.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
_continuesIntervalSeconds = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DetachedParticles;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum speed of the particles
|
/// The maximum speed of the particles
|
||||||
|
/// <para>Default: 25</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float MaxSpeed = 50;
|
public float MaxSpeed = 25;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This contains all important information for each particle.
|
|
||||||
/// </summary>
|
|
||||||
protected ParticleStruct<TDirection>[] particleStructs;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The stopwatch of the particles.
|
|
||||||
/// </summary>
|
|
||||||
protected Timer timer;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets up the timer.
|
/// Sets up the timer.
|
||||||
|
|
@ -51,6 +77,10 @@ namespace SM.Base.Drawing.Particles
|
||||||
protected ParticleDrawingBasis(TimeSpan duration)
|
protected ParticleDrawingBasis(TimeSpan duration)
|
||||||
{
|
{
|
||||||
timer = new Timer(duration);
|
timer = new Timer(duration);
|
||||||
|
_continuesInterval = new Interval(0);
|
||||||
|
_continuesInterval.End += CreateContinuesParticles;
|
||||||
|
|
||||||
|
Lifetime = (float) duration.TotalSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -65,27 +95,29 @@ namespace SM.Base.Drawing.Particles
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controls the movement of each particles.
|
/// Controls the movement of each particles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract Func<TDirection, ParticleContext, TDirection> MovementCalculation { get; set; }
|
public abstract Func<ParticleInstance<TDirection>, TDirection> MovementCalculation { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool UpdateActive {
|
public bool UpdateActive {
|
||||||
get => timer.Active;
|
get => timer.Active || _continuesInterval.Active;
|
||||||
set { return; }
|
set { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Update(UpdateContext context)
|
public void Update(UpdateContext context)
|
||||||
{
|
{
|
||||||
ParticleContext particleContext = new ParticleContext
|
|
||||||
{
|
|
||||||
Timer = timer
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int i = 0; i < Amount; i++)
|
for (int i = 0; i < instances.Count; i++)
|
||||||
{
|
{
|
||||||
particleContext.Speed = particleStructs[i].Speed;
|
instances[i].Lifetime -= context.Deltatime;
|
||||||
instances[i].ModelMatrix = CreateMatrix(particleStructs[i],
|
if (instances[i].Lifetime <= 0)
|
||||||
MovementCalculation(particleStructs[i].Direction, particleContext));
|
{
|
||||||
|
instances.Remove(instances[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
instances[i].ModelMatrix = CreateMatrix(instances[i],
|
||||||
|
MovementCalculation(instances[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,19 +126,50 @@ namespace SM.Base.Drawing.Particles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Trigger()
|
public void Trigger()
|
||||||
{
|
{
|
||||||
|
instances = new List<ParticleInstance<TDirection>>();
|
||||||
|
if (_continuesIntervalSeconds.HasValue)
|
||||||
|
{
|
||||||
|
_continuesInterval.Target = _continuesIntervalSeconds.Value;
|
||||||
|
_continuesInterval.Start();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
timer.Start();
|
timer.Start();
|
||||||
|
|
||||||
CreateParticles();
|
CreateParticles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stops the particles.
|
||||||
|
/// </summary>
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (_continuesInterval.Active)
|
||||||
|
{
|
||||||
|
_continuesInterval.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemoved(object sender)
|
||||||
|
{
|
||||||
|
base.OnRemoved(sender);
|
||||||
|
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void DrawContext(ref DrawContext context)
|
protected override void DrawContext(ref DrawContext context)
|
||||||
{
|
{
|
||||||
if (!timer.Active) return;
|
if (!timer.Active && _continuesInterval != null && !_continuesInterval.Active) return;
|
||||||
|
|
||||||
base.DrawContext(ref context);
|
base.DrawContext(ref context);
|
||||||
|
|
||||||
context.Instances = instances;
|
if (DetachedParticles) context.ModelMatrix = Matrix4.Identity;
|
||||||
|
|
||||||
|
context.Instances = instances.ConvertAll(a => (Instance)a);
|
||||||
|
|
||||||
context.Shader.Draw(context);
|
context.Shader.Draw(context);
|
||||||
}
|
}
|
||||||
|
|
@ -116,24 +179,27 @@ namespace SM.Base.Drawing.Particles
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void CreateParticles()
|
protected virtual void CreateParticles()
|
||||||
{
|
{
|
||||||
particleStructs = new ParticleStruct<TDirection>[Amount];
|
|
||||||
instances = new List<Instance>();
|
|
||||||
for (int i = 0; i < Amount; i++)
|
for (int i = 0; i < Amount; i++)
|
||||||
{
|
{
|
||||||
particleStructs[i] = CreateObject(i);
|
instances.Add(CreateObject(i));
|
||||||
|
|
||||||
instances.Add(new Instance());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreateContinuesParticles(Timer arg1, UpdateContext arg2)
|
||||||
|
{
|
||||||
|
instances.Add(CreateObject(instances.Count));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a particle.
|
/// Creates a particle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract ParticleStruct<TDirection> CreateObject(int index);
|
protected abstract ParticleInstance<TDirection> CreateObject(int index);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates the desired matrix for drawing.
|
/// Generates the desired matrix for drawing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected abstract Matrix4 CreateMatrix(ParticleStruct<TDirection> Struct, TDirection relativePosition);
|
protected abstract Matrix4 CreateMatrix(ParticleInstance<TDirection> Struct, TDirection relativePosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
38
SMCode/SM.Base/Drawing/Particles/ParticleInstance.cs
Normal file
38
SMCode/SM.Base/Drawing/Particles/ParticleInstance.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
using OpenTK;
|
||||||
|
|
||||||
|
namespace SM.Base.Drawing.Particles
|
||||||
|
{
|
||||||
|
public class ParticleInstance : Instance
|
||||||
|
{
|
||||||
|
public float StartLifetime = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The lifetime this particular particle still has.
|
||||||
|
/// </summary>
|
||||||
|
public float Lifetime = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A additional matrix to store rotation and scale.
|
||||||
|
/// </summary>
|
||||||
|
public Matrix4 Matrix;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Speeeeeeeeeed
|
||||||
|
/// </summary>
|
||||||
|
public float Speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParticleInstance<TValue> : ParticleInstance
|
||||||
|
where TValue : struct
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A direction, that the particle should travel.
|
||||||
|
/// </summary>
|
||||||
|
public TValue Direction;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start position.
|
||||||
|
/// </summary>
|
||||||
|
public TValue StartPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,17 +14,17 @@ namespace SM.Base.Drawing.Particles
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default movement for 2D.
|
/// Default movement for 2D.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Vector2 Default2D(Vector2 direction, ParticleContext context)
|
public static Vector2 Default2D(ParticleInstance<Vector2> particle)
|
||||||
{
|
{
|
||||||
return direction * (context.Timer.Elapsed * context.Speed);
|
return particle.Direction * ((particle.StartLifetime - particle.Lifetime) * particle.Speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default movement for 3D.
|
/// Default movement for 3D.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Vector3 Default3D(Vector3 direction, ParticleContext context)
|
public static Vector3 Default3D(ParticleInstance<Vector3> particle)
|
||||||
{
|
{
|
||||||
return direction * (context.Timer.Elapsed * context.Speed);
|
return particle.Direction * ((particle.StartLifetime - particle.Lifetime) * particle.Speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#region usings
|
|
||||||
|
|
||||||
using OpenTK;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
namespace SM.Base.Drawing.Particles
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A particle...
|
|
||||||
/// </summary>
|
|
||||||
public struct ParticleStruct<TDirection>
|
|
||||||
where TDirection : struct
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A direction, that the particle should travel.
|
|
||||||
/// </summary>
|
|
||||||
public TDirection Direction;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A matrix to store rotation and scale.
|
|
||||||
/// </summary>
|
|
||||||
public Matrix4 Matrix;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Speeeeeeeeeed
|
|
||||||
/// </summary>
|
|
||||||
public float Speed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -62,6 +62,7 @@
|
||||||
<Compile Include="Drawing\DrawingBasis.cs" />
|
<Compile Include="Drawing\DrawingBasis.cs" />
|
||||||
<Compile Include="Drawing\GenericTransformation.cs" />
|
<Compile Include="Drawing\GenericTransformation.cs" />
|
||||||
<Compile Include="Drawing\Instance.cs" />
|
<Compile Include="Drawing\Instance.cs" />
|
||||||
|
<Compile Include="Drawing\Particles\ParticleInstance.cs" />
|
||||||
<Compile Include="Drawing\ShaderArguments.cs" />
|
<Compile Include="Drawing\ShaderArguments.cs" />
|
||||||
<Compile Include="Drawing\TextureTransformation.cs" />
|
<Compile Include="Drawing\TextureTransformation.cs" />
|
||||||
<Compile Include="Drawing\Text\Font.cs" />
|
<Compile Include="Drawing\Text\Font.cs" />
|
||||||
|
|
@ -69,9 +70,7 @@
|
||||||
<Compile Include="Scene\ICollectionItem.cs" />
|
<Compile Include="Scene\ICollectionItem.cs" />
|
||||||
<Compile Include="Scene\IFixedScriptable.cs" />
|
<Compile Include="Scene\IFixedScriptable.cs" />
|
||||||
<Compile Include="Shaders\MaterialShader.cs" />
|
<Compile Include="Shaders\MaterialShader.cs" />
|
||||||
<Compile Include="Drawing\Particles\ParticleContext.cs" />
|
|
||||||
<Compile Include="Drawing\Particles\ParticleMovement.cs" />
|
<Compile Include="Drawing\Particles\ParticleMovement.cs" />
|
||||||
<Compile Include="Drawing\Particles\ParticleStruct.cs" />
|
|
||||||
<Compile Include="Drawing\Particles\ParticleDrawingBasis.cs" />
|
<Compile Include="Drawing\Particles\ParticleDrawingBasis.cs" />
|
||||||
<Compile Include="Shaders\SimpleShader.cs" />
|
<Compile Include="Shaders\SimpleShader.cs" />
|
||||||
<Compile Include="Types\CVector4.cs" />
|
<Compile Include="Types\CVector4.cs" />
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace SM.Base.Time
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The target time in seconds.
|
/// The target time in seconds.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Target { get; }
|
public float Target { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The already elapsed time but normalized to the target.
|
/// The already elapsed time but normalized to the target.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace SM2D.Drawing
|
||||||
public class DrawParticles : ParticleDrawingBasis<Transformation, Vector2>
|
public class DrawParticles : ParticleDrawingBasis<Transformation, Vector2>
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Func<Vector2, ParticleContext, Vector2> MovementCalculation { get; set; } = ParticleMovement.Default2D;
|
public override Func<ParticleInstance<Vector2>, Vector2> MovementCalculation { get; set; } = ParticleMovement.Default2D;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The direction the particles should travel.
|
/// The direction the particles should travel.
|
||||||
|
|
@ -30,7 +30,7 @@ namespace SM2D.Drawing
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override ParticleStruct<Vector2> CreateObject(int index)
|
protected override ParticleInstance<Vector2> CreateObject(int index)
|
||||||
{
|
{
|
||||||
Vector2 dir;
|
Vector2 dir;
|
||||||
if (Direction.HasValue)
|
if (Direction.HasValue)
|
||||||
|
|
@ -42,18 +42,27 @@ namespace SM2D.Drawing
|
||||||
}
|
}
|
||||||
else dir = new Vector2(Randomize.GetFloat(-1, 1), Randomize.GetFloat(-1, 1));
|
else dir = new Vector2(Randomize.GetFloat(-1, 1), Randomize.GetFloat(-1, 1));
|
||||||
|
|
||||||
return new ParticleStruct<Vector2>()
|
var particle = new ParticleInstance<Vector2>()
|
||||||
{
|
{
|
||||||
Matrix = Matrix4.CreateScale(1),
|
Matrix = DetachedParticles ? Transform.GetMatrix() : Matrix4.CreateScale(1),
|
||||||
|
|
||||||
Direction = dir,
|
Direction = dir,
|
||||||
Speed = Randomize.GetFloat(MaxSpeed)
|
StartPosition = Transform.Position,
|
||||||
|
|
||||||
|
Speed = Randomize.GetFloat(MaxSpeed),
|
||||||
|
StartLifetime = Lifetime - Randomize.GetFloat(LifetimeRandomize)
|
||||||
};
|
};
|
||||||
|
particle.Lifetime = particle.StartLifetime;
|
||||||
|
|
||||||
|
return particle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override Matrix4 CreateMatrix(ParticleStruct<Vector2> Struct, Vector2 direction)
|
protected override Matrix4 CreateMatrix(ParticleInstance<Vector2> Struct, Vector2 direction)
|
||||||
{
|
{
|
||||||
return Struct.Matrix * Matrix4.CreateTranslation(direction.X, direction.Y, 0);
|
Vector2 pos = direction;
|
||||||
|
|
||||||
|
return Struct.Matrix * Matrix4.CreateTranslation(pos.X, pos.Y, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ using SM.Base.Drawing;
|
||||||
using SM.Base.Time;
|
using SM.Base.Time;
|
||||||
using SM.Base.Window;
|
using SM.Base.Window;
|
||||||
using SM2D;
|
using SM2D;
|
||||||
|
using SM2D.Controls;
|
||||||
using SM2D.Drawing;
|
using SM2D.Drawing;
|
||||||
using SM2D.Object;
|
using SM2D.Object;
|
||||||
using SM2D.Scene;
|
using SM2D.Scene;
|
||||||
|
|
@ -48,16 +49,17 @@ namespace SM_TEST
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DrawObject2D test = new DrawObject2D()
|
particles = new DrawParticles(TimeSpan.FromSeconds(1))
|
||||||
{
|
{
|
||||||
Texture = new Bitmap("test.png")
|
Lifetime = 1f,
|
||||||
};
|
ContinuousInterval = .5f,
|
||||||
test.Material.Blending = true;
|
|
||||||
test.Transform.Size.Set(100);
|
|
||||||
test.TextureTransform.SetRectangleRelative(test.Texture, new Vector2(234, 0), new Vector2(220, 201));
|
|
||||||
test.Transform.AdjustSizeToTextureTransform(test.TextureTransform);
|
|
||||||
|
|
||||||
scene.Objects.Add(test);
|
Direction = -Vector2.UnitY,
|
||||||
|
DetachedParticles = true
|
||||||
|
};
|
||||||
|
particles.Transform.Size.Set(50);
|
||||||
|
|
||||||
|
scene.Objects.Add(particles);
|
||||||
|
|
||||||
window.UpdateFrame += WindowOnUpdateFrame;
|
window.UpdateFrame += WindowOnUpdateFrame;
|
||||||
window.RenderFrame += Window_RenderFrame;
|
window.RenderFrame += Window_RenderFrame;
|
||||||
|
|
@ -74,9 +76,11 @@ namespace SM_TEST
|
||||||
private static void WindowOnUpdateFrame(object sender, FrameEventArgs e)
|
private static void WindowOnUpdateFrame(object sender, FrameEventArgs e)
|
||||||
{
|
{
|
||||||
if (Mouse.LeftClick)
|
if (Mouse.LeftClick)
|
||||||
interpolation.Stop();
|
particles.Trigger();
|
||||||
if (Mouse.RightClick)
|
if (Mouse.RightClick)
|
||||||
interpolation.Stop(false);
|
particles.ContinuousInterval = .05f;
|
||||||
|
|
||||||
|
particles.Transform.Position.Set(Mouse2D.InWorld(scene.Camera));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue