Finalize ParticleSystem, add angular velocity, multiple emitters, GetBool for IDataReader, use Lerp in LerpColor.
This commit is contained in:
20
TestGame/Resources/fire_effect.toml
Normal file
20
TestGame/Resources/fire_effect.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Fire effect example
|
||||||
|
[ParticleEmitterSettings]
|
||||||
|
|
||||||
|
Local = true
|
||||||
|
MaxParticles = 128
|
||||||
|
EmitRadius = 8
|
||||||
|
Explosiveness = 0
|
||||||
|
LifeTime = 1.0
|
||||||
|
Direction = [0.0, -1.0]
|
||||||
|
LinearVelocity = 200
|
||||||
|
LinearVelocityDamping = 0.0
|
||||||
|
AngularVelocity = 230
|
||||||
|
AngularVelocityDamping = 0.0
|
||||||
|
AngularVelocityRandom = 1.0
|
||||||
|
Gravity = [0.0, 0.0]
|
||||||
|
LinearVelocityRandom = 0.5
|
||||||
|
ScaleBegin = 0.1
|
||||||
|
ScaleEnd = 5.0
|
||||||
|
ColorBegin = [255, 162, 0]
|
||||||
|
ColorEnd = [64, 64, 64, 0]
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
[ParticleEmitterSettings]
|
|
||||||
|
|
||||||
MaxParticles = 1024
|
|
||||||
EmitRadius = 128
|
|
||||||
Explosiveness = 1.0
|
|
||||||
LifeTime = 2.0
|
|
||||||
Direction = [0.0, -1.0]
|
|
||||||
LinearVelocity = 200
|
|
||||||
Gravity = [0.0, 0.0]
|
|
||||||
LinearVelocityRandom = 0.5
|
|
||||||
ScaleBegin = 1.0
|
|
||||||
ScaleEnd = 5.0
|
|
||||||
ColorBegin = [255, 0, 0, 0]
|
|
||||||
ColorEnd = [0, 255, 0, 255]
|
|
||||||
@@ -26,11 +26,6 @@ public class TestGame : Game
|
|||||||
|
|
||||||
protected override void LoadResources()
|
protected override void LoadResources()
|
||||||
{
|
{
|
||||||
// if (!ResourceManager.TryLoad("my_sound", "sounds/test_sound.ogg", out Sound? _testSound))
|
|
||||||
// {
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (!ResourceManager.TryLoad("fonts/Inter-Regular.ttf", out _font))
|
if (!ResourceManager.TryLoad("fonts/Inter-Regular.ttf", out _font))
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -38,7 +33,7 @@ public class TestGame : Game
|
|||||||
|
|
||||||
ResourceManager.TryLoad("icon.png", out _icon);
|
ResourceManager.TryLoad("icon.png", out _icon);
|
||||||
|
|
||||||
if (!ResourceManager.TryLoad("test_emitter.toml", out _emitterSettings))
|
if (!ResourceManager.TryLoad("fire_effect.toml", out _fireEffect))
|
||||||
{
|
{
|
||||||
throw new Exception("Failed to load emitter settings!");
|
throw new Exception("Failed to load emitter settings!");
|
||||||
}
|
}
|
||||||
@@ -46,7 +41,7 @@ public class TestGame : Game
|
|||||||
|
|
||||||
protected override void Ready()
|
protected override void Ready()
|
||||||
{
|
{
|
||||||
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _emitterSettings);
|
_emitterId = _particleSystem.CreateEmitter(Renderer.WindowSize / 2, _fireEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Run()
|
protected override void Run()
|
||||||
@@ -59,6 +54,16 @@ public class TestGame : Game
|
|||||||
_particleSystem!.RestartEmitter(_emitterId);
|
_particleSystem!.RestartEmitter(_emitterId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Input.KeyboardKeyJustPressed(KeyboardKey.One))
|
||||||
|
{
|
||||||
|
_particleSystem.CreateEmitter(Input.GetMousePosition(), _fireEffect);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Input.IsMouseButtonDown(MouseButton.Left))
|
||||||
|
{
|
||||||
|
_particleSystem.SetEmitterPosition(_emitterId, Input.GetMousePosition());
|
||||||
|
}
|
||||||
|
|
||||||
_particleSimStopwatch = Stopwatch.StartNew();
|
_particleSimStopwatch = Stopwatch.StartNew();
|
||||||
_particleSystem!.Update(Renderer.FrameTime);
|
_particleSystem!.Update(Renderer.FrameTime);
|
||||||
_particleSimStopwatch.Stop();
|
_particleSimStopwatch.Stop();
|
||||||
@@ -97,15 +102,15 @@ public class TestGame : Game
|
|||||||
Renderer.BeginBlended(Voile.Rendering.BlendMode.BlendAlpha);
|
Renderer.BeginBlended(Voile.Rendering.BlendMode.BlendAlpha);
|
||||||
|
|
||||||
var maxParticles = emitter.Settings.MaxParticles;
|
var maxParticles = emitter.Settings.MaxParticles;
|
||||||
|
var particleSize = new Vector2(16.0f, 16.0f);
|
||||||
|
var pivot = particleSize / 2;
|
||||||
|
|
||||||
for (int i = maxParticles - 1; i > 0; i--)
|
for (int i = maxParticles - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var particle = emitter.GetParticle(i);
|
var particle = emitter.GetParticle(i);
|
||||||
|
|
||||||
var color = new Color(particle.ColorArgb);
|
Renderer.SetTransform(particle.Position, pivot, particle.Rotation);
|
||||||
|
Renderer.DrawRectangle(particleSize * particle.Scale, particle.Color);
|
||||||
Renderer.SetTransform(emitter.OriginPosition + particle.Position, Vector2.Zero);
|
|
||||||
Renderer.DrawRectangle(Vector2.One * 16.0f * particle.Scale, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.EndBlended();
|
Renderer.EndBlended();
|
||||||
@@ -116,7 +121,7 @@ public class TestGame : Game
|
|||||||
private Stopwatch _particleSimStopwatch, _renderStopwatch;
|
private Stopwatch _particleSimStopwatch, _renderStopwatch;
|
||||||
private long _lastRenderTime;
|
private long _lastRenderTime;
|
||||||
private int _emitterId;
|
private int _emitterId;
|
||||||
private ResourceRef<ParticleEmitterSettingsResource> _emitterSettings;
|
private ResourceRef<ParticleEmitterSettingsResource> _fireEffect;
|
||||||
private ResourceRef<Font> _font;
|
private ResourceRef<Font> _font;
|
||||||
private ResourceRef<Texture2d> _icon;
|
private ResourceRef<Texture2d> _icon;
|
||||||
private Logger _logger = new(nameof(TestGame));
|
private Logger _logger = new(nameof(TestGame));
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ namespace Voile.Resources.DataReaders
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IStreamKeyValueGetter
|
public interface IStreamKeyValueGetter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get a boolean from this data getter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">Key of the value.</param>
|
||||||
|
/// <param name="defaultValue">Default value in case this getter fails to get data.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool GetBool(string key, bool defaultValue = false);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get an int from this data getter.
|
/// Get an int from this data getter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -31,6 +31,30 @@ public class TomlDataReader : IStreamDataReader, IDataValidator, IStreamKeyValue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool GetBool(string key, bool defaultValue = false)
|
||||||
|
{
|
||||||
|
if (_table is null)
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataTable = _table[ExpectedHeader];
|
||||||
|
|
||||||
|
if (!dataTable.HasKey(key))
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tableValue = dataTable[key];
|
||||||
|
|
||||||
|
if (!tableValue.IsBoolean)
|
||||||
|
{
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tableValue.AsBoolean;
|
||||||
|
}
|
||||||
|
|
||||||
public int GetInt(string key, int defaultValue = 0)
|
public int GetInt(string key, int defaultValue = 0)
|
||||||
{
|
{
|
||||||
if (_table is null)
|
if (_table is null)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public struct Particle
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int EmitterIndex { get; set; }
|
public int EmitterIndex { get; set; }
|
||||||
public int ColorArgb { get; set; }
|
public Color Color { get; set; }
|
||||||
public Vector2 Position { get; set; }
|
public Vector2 Position { get; set; }
|
||||||
public float LifeTime { get; set; } = 1.0f;
|
public float LifeTime { get; set; } = 1.0f;
|
||||||
public float Scale { get; set; }
|
public float Scale { get; set; }
|
||||||
@@ -21,6 +21,7 @@ public struct Particle
|
|||||||
|
|
||||||
public class ParticleEmitterSettings
|
public class ParticleEmitterSettings
|
||||||
{
|
{
|
||||||
|
public bool Local { get; set; } = true;
|
||||||
public int MaxParticles { get; set; } = 16;
|
public int MaxParticles { get; set; } = 16;
|
||||||
public float EmitRadius { get; set; }
|
public float EmitRadius { get; set; }
|
||||||
public float LifeTime { get; set; } = 1.0f;
|
public float LifeTime { get; set; } = 1.0f;
|
||||||
@@ -28,14 +29,15 @@ public class ParticleEmitterSettings
|
|||||||
public Vector2 Direction { get; set; } = -Vector2.UnitY;
|
public Vector2 Direction { get; set; } = -Vector2.UnitY;
|
||||||
public float LinearVelocity { get; set; } = 980.0f;
|
public float LinearVelocity { get; set; } = 980.0f;
|
||||||
public float AngularVelocity { get; set; }
|
public float AngularVelocity { get; set; }
|
||||||
public float AngularVelocityRandom { get; set; }
|
public float AngularVelocityRandom { get; set; } = 0.5f;
|
||||||
public float LinearVelocityRandom { get; set; } = 0.5f;
|
public float LinearVelocityRandom { get; set; } = 0.5f;
|
||||||
public Vector2 Gravity { get; set; } = Vector2.UnitY * 980f;
|
public Vector2 Gravity { get; set; } = Vector2.UnitY * 980f;
|
||||||
public float ScaleBegin { get; set; } = 1.0f;
|
public float ScaleBegin { get; set; } = 1.0f;
|
||||||
public float ScaleEnd { get; set; } = 0.0f;
|
public float ScaleEnd { get; set; } = 0.0f;
|
||||||
public Color ColorBegin { get; set; } = Color.White;
|
public Color ColorBegin { get; set; } = Color.White;
|
||||||
public Color ColorEnd { get; set; } = Color.Black;
|
public Color ColorEnd { get; set; } = Color.Black;
|
||||||
public float Damping { get; set; } = 1.0f;
|
public float LinearVelocityDamping { get; set; } = 1.0f;
|
||||||
|
public float AngularVelocityDamping { get; set; } = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ParticleEmitterSettingsResource : Resource
|
public class ParticleEmitterSettingsResource : Resource
|
||||||
@@ -45,7 +47,6 @@ public class ParticleEmitterSettingsResource : Resource
|
|||||||
{
|
{
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -65,6 +66,7 @@ public class ParticleEmitterSettingsResourceLoader : ResourceLoader<ParticleEmit
|
|||||||
{
|
{
|
||||||
reader.Read(File.Open(path, FileMode.Open));
|
reader.Read(File.Open(path, FileMode.Open));
|
||||||
|
|
||||||
|
settings.Local = reader.GetBool("Local", true);
|
||||||
settings.MaxParticles = reader.GetInt("MaxParticles");
|
settings.MaxParticles = reader.GetInt("MaxParticles");
|
||||||
settings.EmitRadius = reader.GetInt("EmitRadius");
|
settings.EmitRadius = reader.GetInt("EmitRadius");
|
||||||
settings.LifeTime = reader.GetFloat("LifeTime", 1.0f);
|
settings.LifeTime = reader.GetFloat("LifeTime", 1.0f);
|
||||||
@@ -79,7 +81,8 @@ public class ParticleEmitterSettingsResourceLoader : ResourceLoader<ParticleEmit
|
|||||||
settings.ScaleEnd = reader.GetFloat("ScaleEnd");
|
settings.ScaleEnd = reader.GetFloat("ScaleEnd");
|
||||||
settings.ColorBegin = reader.GetColor("ColorBegin", Color.White);
|
settings.ColorBegin = reader.GetColor("ColorBegin", Color.White);
|
||||||
settings.ColorEnd = reader.GetColor("ColorEnd", Color.Black);
|
settings.ColorEnd = reader.GetColor("ColorEnd", Color.Black);
|
||||||
settings.Damping = reader.GetFloat("Damping", 1.0f);
|
settings.LinearVelocityDamping = reader.GetFloat("LinearVelocityDamping", 1.0f);
|
||||||
|
settings.AngularVelocityDamping = reader.GetFloat("AngularVelocityDamping", 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ParticleEmitterSettingsResource(path, settings);
|
return new ParticleEmitterSettingsResource(path, settings);
|
||||||
@@ -94,12 +97,11 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Origin position in the world of this emitter.
|
/// Origin position in the world of this emitter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Vector2 OriginPosition => _originPosition;
|
public Vector2 OriginPosition { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <see cref="ParticleEmitterSettings"/> for this emitter.
|
/// <see cref="ParticleEmitterSettings"/> for this emitter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ParticleEmitterSettings Settings => _settingsResource.Value.Settings;
|
public ParticleEmitterSettings Settings => _settingsResource.Value.Settings;
|
||||||
public int ArrayOffset => _lifetimes.Offset;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a new <see cref="ParticleEmitter"/>.
|
/// Constructs a new <see cref="ParticleEmitter"/>.
|
||||||
@@ -107,29 +109,39 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
/// <param name="originPosition">World origin position.</param>
|
/// <param name="originPosition">World origin position.</param>
|
||||||
/// <param name="settingsResource">Emitter settings resource.</param>
|
/// <param name="settingsResource">Emitter settings resource.</param>
|
||||||
/// <param name="particles">Particle segment that this emitter will simulate.</param>
|
/// <param name="particles">Particle segment that this emitter will simulate.</param>
|
||||||
public ParticleEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource, ArraySegment<Vector2> positionsSlice, ArraySegment<Vector2> velocitiesSlice, ArraySegment<float> lifetimesSlice)
|
public ParticleEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource)
|
||||||
{
|
{
|
||||||
_originPosition = originPosition;
|
OriginPosition = originPosition;
|
||||||
|
|
||||||
_settingsResource = settingsResource;
|
_settingsResource = settingsResource;
|
||||||
_maxParticles = _settingsResource.Value.Settings.MaxParticles;
|
_maxParticles = _settingsResource.Value.Settings.MaxParticles;
|
||||||
// _particleIndex = _maxParticles - 1;
|
|
||||||
|
|
||||||
_positions = positionsSlice;
|
_positions = new Vector2[_maxParticles];
|
||||||
_velocities = velocitiesSlice;
|
_velocities = new Vector2[_maxParticles];
|
||||||
_lifetimes = lifetimesSlice;
|
_angularVelocities = new float[_maxParticles];
|
||||||
|
_lifetimes = new float[_maxParticles];
|
||||||
|
_rotations = new float[_maxParticles];
|
||||||
|
|
||||||
_random = new LehmerRandom();
|
_random = new LehmerRandom();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Particle GetParticle(int idx)
|
public Particle GetParticle(int idx)
|
||||||
{
|
{
|
||||||
|
if (idx > _lifetimes.Length)
|
||||||
|
{
|
||||||
|
return new Particle();
|
||||||
|
}
|
||||||
|
|
||||||
var t = _lifetimes[idx] / Settings.LifeTime;
|
var t = _lifetimes[idx] / Settings.LifeTime;
|
||||||
|
var scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t);
|
||||||
|
var color = MathUtils.LerpColor(Settings.ColorEnd, Settings.ColorBegin, t);
|
||||||
|
|
||||||
return new Particle()
|
return new Particle()
|
||||||
{
|
{
|
||||||
Position = _positions[idx],
|
Position = _positions[idx],
|
||||||
Scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t),
|
Scale = scale,
|
||||||
ColorArgb = MathUtils.LerpColor(Settings.ColorEnd, Settings.ColorBegin, t).Argb
|
Color = color,
|
||||||
|
Rotation = _rotations[idx]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,12 +151,14 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
/// <param name="particles">New particle segment.</param>
|
/// <param name="particles">New particle segment.</param>
|
||||||
public void Restart()
|
public void Restart()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _lifetimes.Count; i++)
|
|
||||||
{
|
|
||||||
_lifetimes[i] = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
_maxParticles = Settings.MaxParticles;
|
_maxParticles = Settings.MaxParticles;
|
||||||
|
|
||||||
|
_positions = new Vector2[_maxParticles];
|
||||||
|
_velocities = new Vector2[_maxParticles];
|
||||||
|
_angularVelocities = new float[_maxParticles];
|
||||||
|
_lifetimes = new float[_maxParticles];
|
||||||
|
_rotations = new float[_maxParticles];
|
||||||
|
|
||||||
_particleIndex = 0;
|
_particleIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,23 +170,28 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
{
|
{
|
||||||
var rate = (int)MathUtils.Lerp(1, _maxParticles, Settings.Explosiveness);
|
var rate = (int)MathUtils.Lerp(1, _maxParticles, Settings.Explosiveness);
|
||||||
|
|
||||||
for (int i = 0; i < rate; i++)
|
|
||||||
{
|
|
||||||
Emit();
|
|
||||||
}
|
|
||||||
|
|
||||||
var deltaTimeVector = new Vector2((float)deltaTime);
|
var deltaTimeVector = new Vector2((float)deltaTime);
|
||||||
var gravityVector = Settings.Gravity * (float)deltaTime;
|
var gravityVector = Settings.Gravity * (float)deltaTime;
|
||||||
var dampingFactor = Settings.Damping * (float)deltaTime;
|
|
||||||
|
var linearVelocityDampingFactor = Settings.LinearVelocityDamping * (float)deltaTime;
|
||||||
|
var angularVelocityDampingFactor = Settings.AngularVelocityDamping * (float)deltaTime;
|
||||||
|
|
||||||
for (int i = 0; i < _maxParticles; i++)
|
for (int i = 0; i < _maxParticles; i++)
|
||||||
{
|
{
|
||||||
_lifetimes[i] = Math.Max(0.0f, _lifetimes[i] - (float)deltaTime);
|
_lifetimes[i] = Math.Max(0.0f, _lifetimes[i] - (float)deltaTime);
|
||||||
|
|
||||||
_velocities[i] += gravityVector;
|
_velocities[i] += gravityVector;
|
||||||
_positions[i] += _velocities[i] * deltaTimeVector;
|
|
||||||
|
|
||||||
_velocities[i] -= _velocities[i] * dampingFactor;
|
_positions[i] += _velocities[i] * deltaTimeVector;
|
||||||
|
_rotations[i] += _angularVelocities[i] * (float)deltaTime;
|
||||||
|
|
||||||
|
_velocities[i] -= _velocities[i] * linearVelocityDampingFactor;
|
||||||
|
_angularVelocities[i] -= _angularVelocities[i] * angularVelocityDampingFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < rate; i++)
|
||||||
|
{
|
||||||
|
Emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +203,7 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
_velocities[_particleIndex] = Settings.Direction * Settings.LinearVelocity;
|
_velocities[_particleIndex] = Settings.Direction * Settings.LinearVelocity;
|
||||||
|
|
||||||
_velocities[_particleIndex] += Vector2.One * Settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
_velocities[_particleIndex] += Vector2.One * Settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||||
|
_angularVelocities[_particleIndex] = Settings.AngularVelocity * Settings.AngularVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||||
|
|
||||||
_lifetimes[_particleIndex] = Settings.LifeTime;
|
_lifetimes[_particleIndex] = Settings.LifeTime;
|
||||||
|
|
||||||
@@ -193,6 +213,7 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
private Vector2 GetEmitPosition()
|
private Vector2 GetEmitPosition()
|
||||||
{
|
{
|
||||||
var settings = _settingsResource.Value.Settings;
|
var settings = _settingsResource.Value.Settings;
|
||||||
|
Vector2 originOffset = Settings.Local ? OriginPosition : Vector2.Zero;
|
||||||
|
|
||||||
// https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image
|
// https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image
|
||||||
var angle = _random.NextDouble() * Math.PI * 2;
|
var angle = _random.NextDouble() * Math.PI * 2;
|
||||||
@@ -201,15 +222,16 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
float x = radius * (float)Math.Cos(angle);
|
float x = radius * (float)Math.Cos(angle);
|
||||||
float y = radius * (float)Math.Sin(angle);
|
float y = radius * (float)Math.Sin(angle);
|
||||||
|
|
||||||
return new Vector2(x, y);
|
var point = new Vector2(x, y);
|
||||||
|
|
||||||
|
return point + originOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LehmerRandom _random;
|
private LehmerRandom _random;
|
||||||
private int _maxParticles;
|
private int _maxParticles;
|
||||||
private int _particleIndex;
|
private int _particleIndex;
|
||||||
private Vector2 _originPosition = Vector2.Zero;
|
private Vector2[] _positions, _velocities;
|
||||||
private ArraySegment<Vector2> _positions, _velocities;
|
private float[] _lifetimes, _rotations, _angularVelocities;
|
||||||
private ArraySegment<float> _lifetimes;
|
|
||||||
private ResourceRef<ParticleEmitterSettingsResource> _settingsResource;
|
private ResourceRef<ParticleEmitterSettingsResource> _settingsResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,26 +240,11 @@ public class ParticleEmitter : IUpdatableSystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ParticleSystem : IUpdatableSystem, IDisposable
|
public class ParticleSystem : IUpdatableSystem, IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Maximum amount of particles emittable by the system.
|
|
||||||
/// </summary>
|
|
||||||
public int ParticleLimit { get; set; } = short.MaxValue;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// List of particle emitters created for this ParticleSystem.
|
/// List of particle emitters created for this ParticleSystem.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IReadOnlyList<ParticleEmitter> Emitters => _emitters;
|
public IReadOnlyList<ParticleEmitter> Emitters => _emitters;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <see cref="ParticleSystem"/>.
|
|
||||||
/// </summary>
|
|
||||||
public ParticleSystem()
|
|
||||||
{
|
|
||||||
_particlePositions = new Vector2[ParticleLimit];
|
|
||||||
_particleVelocities = new Vector2[ParticleLimit];
|
|
||||||
_particleLifetimes = new float[ParticleLimit];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an emitter from a <see cref="ParticleEmitterSettingsResource"/>.
|
/// Creates an emitter from a <see cref="ParticleEmitterSettingsResource"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -246,31 +253,22 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public int CreateEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource)
|
public int CreateEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource)
|
||||||
{
|
{
|
||||||
var settings = settingsResource.Value.Settings;
|
var emitter = new ParticleEmitter(originPosition, settingsResource);
|
||||||
|
|
||||||
if (_emitterSliceOffset + settings.MaxParticles >= ParticleLimit - 1)
|
|
||||||
{
|
|
||||||
_logger.Error("Cannot create an emitter! Reached particle limit.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var positionsSlice = new ArraySegment<Vector2>(_particlePositions, _emitterSliceOffset, settings.MaxParticles);
|
|
||||||
var velocitiesSlice = new ArraySegment<Vector2>(_particleVelocities, _emitterSliceOffset, settings.MaxParticles);
|
|
||||||
var lifetimesSlice = new ArraySegment<float>(_particleLifetimes, _emitterSliceOffset, settings.MaxParticles);
|
|
||||||
|
|
||||||
for (int i = 0; i < lifetimesSlice.Count; i++)
|
|
||||||
{
|
|
||||||
lifetimesSlice[i] = settings.LifeTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
var emitter = new ParticleEmitter(originPosition, settingsResource, positionsSlice, velocitiesSlice, lifetimesSlice);
|
|
||||||
|
|
||||||
_emitters.Add(emitter);
|
_emitters.Add(emitter);
|
||||||
_emitterSliceOffset += settings.MaxParticles;
|
|
||||||
|
|
||||||
return _emitters.Count - 1;
|
return _emitters.Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetEmitterPosition(int emitterIdx, Vector2 position)
|
||||||
|
{
|
||||||
|
if (emitterIdx >= _emitters.Count)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Emitter with idx {emitterIdx} is not present!");
|
||||||
|
}
|
||||||
|
|
||||||
|
var emitter = _emitters[emitterIdx];
|
||||||
|
emitter.OriginPosition = position;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restarts an emitter.
|
/// Restarts an emitter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -284,7 +282,6 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
var emitter = _emitters[id];
|
var emitter = _emitters[id];
|
||||||
|
|
||||||
emitter.Restart();
|
emitter.Restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,16 +299,7 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Array.Clear(_particlePositions);
|
|
||||||
Array.Clear(_particleVelocities);
|
|
||||||
Array.Clear(_particleLifetimes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vector2[] _particlePositions, _particleVelocities;
|
|
||||||
private float[] _particleLifetimes;
|
|
||||||
private int _emitterSliceOffset;
|
|
||||||
|
|
||||||
private List<ParticleEmitter> _emitters = new();
|
private List<ParticleEmitter> _emitters = new();
|
||||||
|
|
||||||
private Logger _logger = new(nameof(ParticleSystem));
|
|
||||||
}
|
}
|
||||||
@@ -19,10 +19,10 @@ namespace Voile
|
|||||||
{
|
{
|
||||||
t = Math.Clamp(t, 0f, 1f);
|
t = Math.Clamp(t, 0f, 1f);
|
||||||
|
|
||||||
byte r = (byte)(colorA.R + (colorB.R - colorA.R) * t);
|
byte r = (byte)Lerp(colorA.R, colorB.R, t);
|
||||||
byte g = (byte)(colorA.G + (colorB.G - colorA.G) * t);
|
byte g = (byte)Lerp(colorA.G, colorB.G, t);
|
||||||
byte b = (byte)(colorA.B + (colorB.B - colorA.B) * t);
|
byte b = (byte)Lerp(colorA.B, colorB.B, t);
|
||||||
byte a = (byte)(colorA.A + (colorB.A - colorA.A) * t);
|
byte a = (byte)Lerp(colorA.A, colorB.A, t);
|
||||||
|
|
||||||
return new Color(r, g, b, a);
|
return new Color(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user