WIP: ResourceManager refactor, hot reloading using ResourceRef, API changes.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
using System.ComponentModel;
|
||||
using System.Numerics;
|
||||
using Voile.Rendering;
|
||||
using Tommy;
|
||||
using Voile.Resources;
|
||||
using Voile.Utils;
|
||||
|
||||
namespace Voile.Systems;
|
||||
@@ -41,18 +43,71 @@ public class ParticleEmitterSettings
|
||||
public float Damping { get; set; } = 1.0f;
|
||||
}
|
||||
|
||||
public class ParticleEmitterSettingsResource : Resource
|
||||
{
|
||||
public ParticleEmitterSettings Settings { get; private set; }
|
||||
public ParticleEmitterSettingsResource(string path, ParticleEmitterSettings settings) : base(path)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ParticleEmitterSettingsResourceLoader : ResourceLoader<ParticleEmitterSettingsResource>
|
||||
{
|
||||
public override IEnumerable<string> SupportedExtensions => new string[] {
|
||||
"toml"
|
||||
};
|
||||
|
||||
protected override ParticleEmitterSettingsResource LoadResource(string path)
|
||||
{
|
||||
// TODO: this is ugly, better to make some sort of wrapper API for TOML files.
|
||||
var settings = new ParticleEmitterSettings();
|
||||
// Parse into a node
|
||||
using (StreamReader reader = File.OpenText(path))
|
||||
{
|
||||
// Parse the table
|
||||
TomlTable table = TOML.Parse(reader);
|
||||
|
||||
if (!table.HasKey("ParticleEmitterSettings"))
|
||||
{
|
||||
Console.WriteLine("Particle emitter settings doesnt have a header!");
|
||||
}
|
||||
|
||||
if (table["ParticleEmitterSettings"]["MaxParticles"] is TomlInteger maxParticles)
|
||||
{
|
||||
settings.MaxParticles = (int)maxParticles.Value;
|
||||
}
|
||||
|
||||
if (table["ParticleEmitterSettings"]["EmitRadius"] is TomlInteger emitRadius)
|
||||
{
|
||||
settings.EmitRadius = (int)emitRadius.Value;
|
||||
}
|
||||
|
||||
if (table["ParticleEmitterSettings"]["LifeTime"] is TomlFloat lifetime)
|
||||
{
|
||||
settings.LifeTime = (float)lifetime.Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new ParticleEmitterSettingsResource(path, settings);
|
||||
}
|
||||
}
|
||||
|
||||
public class ParticleEmitter : IUpdatableSystem
|
||||
{
|
||||
public ReadOnlySpan<Particle> Particles => _particles.AsSpan();
|
||||
public Vector2 OriginPosition => _originPosition;
|
||||
public ParticleEmitterSettings Settings => _settings;
|
||||
public ParticleEmitterSettings Settings => _settingsResource.Value.Settings;
|
||||
public int ParticleArrayOffset => _particles.Offset;
|
||||
|
||||
public ParticleEmitter(Vector2 originPosition, ParticleEmitterSettings settings, ArraySegment<Particle> particles)
|
||||
public ParticleEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource, ArraySegment<Particle> particles)
|
||||
{
|
||||
_originPosition = originPosition;
|
||||
|
||||
_settings = settings;
|
||||
_maxParticles = _settings.MaxParticles;
|
||||
_settingsResource = settingsResource;
|
||||
_maxParticles = _settingsResource.Value.Settings.MaxParticles;
|
||||
_particleIndex = _maxParticles - 1;
|
||||
|
||||
_particles = particles;
|
||||
@@ -60,9 +115,29 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
_random = new LehmerRandom();
|
||||
}
|
||||
|
||||
public void Restart(ArraySegment<Particle> particles)
|
||||
{
|
||||
// foreach (var particle in _particles)
|
||||
// {
|
||||
// particle.LifeTimeRemaining = 0.0f;
|
||||
// }
|
||||
|
||||
for (int i = 0; i < _particles.Count; i++)
|
||||
{
|
||||
var particle = _particles[i];
|
||||
particle.LifeTimeRemaining = 0.0f;
|
||||
}
|
||||
|
||||
_particles = particles;
|
||||
|
||||
_maxParticles = Settings.MaxParticles;
|
||||
_particleIndex = _maxParticles - 1;
|
||||
}
|
||||
|
||||
public void Update(double deltaTime)
|
||||
{
|
||||
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();
|
||||
@@ -71,19 +146,19 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
for (int i = 0; i < _maxParticles; i++)
|
||||
{
|
||||
var particle = _particles[i];
|
||||
if (!particle.Alive) continue;
|
||||
// if (!particle.Alive) continue;
|
||||
|
||||
if (particle.LifeTimeRemaining <= 0.0f)
|
||||
{
|
||||
particle.Alive = false;
|
||||
continue;
|
||||
}
|
||||
// if (particle.LifeTimeRemaining <= 0.0f)
|
||||
// {
|
||||
// particle.Alive = false;
|
||||
// continue;
|
||||
// }
|
||||
|
||||
particle.LifeTimeRemaining = Math.Clamp(particle.LifeTimeRemaining - (float)deltaTime, 0.0f, particle.LifeTime);
|
||||
|
||||
var t = particle.LifeTimeRemaining / particle.LifeTime;
|
||||
|
||||
particle.Velocity += _settings.Gravity * (float)deltaTime;
|
||||
particle.Velocity += Settings.Gravity * (float)deltaTime;
|
||||
particle.Position += particle.Velocity * (float)deltaTime;
|
||||
particle.Rotation += particle.AngularVelocity * (float)deltaTime;
|
||||
particle.Scale = MathUtils.Lerp(Settings.ScaleEnd, Settings.ScaleBegin, t);
|
||||
@@ -91,7 +166,7 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
var color = MathUtils.LerpColor(Settings.ColorEnd, Settings.ColorBegin, t);
|
||||
particle.ColorArgb = color.Argb;
|
||||
|
||||
particle.Velocity -= particle.Velocity * _settings.Damping * (float)deltaTime;
|
||||
particle.Velocity -= particle.Velocity * Settings.Damping * (float)deltaTime;
|
||||
|
||||
_particles[i] = particle;
|
||||
}
|
||||
@@ -101,16 +176,17 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
{
|
||||
Particle particle = _particles[_particleIndex];
|
||||
if (!(particle.LifeTimeRemaining <= 0)) return;
|
||||
particle.Alive = true;
|
||||
|
||||
// particle.Alive = true;
|
||||
particle.Position = GetEmitPosition();
|
||||
particle.Velocity = _settings.Direction * _settings.LinearVelocity;
|
||||
particle.Velocity = Settings.Direction * Settings.LinearVelocity;
|
||||
|
||||
particle.Velocity += Vector2.One * _settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||
particle.Velocity += Vector2.One * Settings.LinearVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||
|
||||
particle.AngularVelocity = _settings.AngularVelocity;
|
||||
particle.AngularVelocity += 1f * _settings.AngularVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||
particle.AngularVelocity = Settings.AngularVelocity;
|
||||
particle.AngularVelocity += 1f * Settings.AngularVelocityRandom * ((float)_random.NextDouble() - 0.5f);
|
||||
|
||||
particle.LifeTime = _settings.LifeTime;
|
||||
particle.LifeTime = Settings.LifeTime;
|
||||
particle.LifeTimeRemaining = particle.LifeTime;
|
||||
|
||||
_particles[_particleIndex] = particle;
|
||||
@@ -119,9 +195,11 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
|
||||
private Vector2 GetEmitPosition()
|
||||
{
|
||||
var settings = _settingsResource.Value.Settings;
|
||||
|
||||
// https://gamedev.stackexchange.com/questions/26713/calculate-random-points-pixel-within-a-circle-image
|
||||
var angle = _random.NextDouble() * Math.PI * 2;
|
||||
float radius = (float)Math.Sqrt(_random.NextDouble()) * _settings.EmitRadius;
|
||||
float radius = (float)Math.Sqrt(_random.NextDouble()) * settings.EmitRadius;
|
||||
|
||||
float x = radius * (float)Math.Cos(angle);
|
||||
float y = radius * (float)Math.Sin(angle);
|
||||
@@ -134,7 +212,7 @@ public class ParticleEmitter : IUpdatableSystem
|
||||
private int _particleIndex;
|
||||
private Vector2 _originPosition = Vector2.Zero;
|
||||
private ArraySegment<Particle> _particles;
|
||||
private ParticleEmitterSettings _settings;
|
||||
private ResourceRef<ParticleEmitterSettingsResource> _settingsResource;
|
||||
}
|
||||
|
||||
public class ParticleSystem : IUpdatableSystem, IDisposable
|
||||
@@ -152,12 +230,14 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
||||
_particles = new Particle[ParticleLimit];
|
||||
}
|
||||
|
||||
public void CreateEmitter(Vector2 originPosition, ParticleEmitterSettings settings)
|
||||
public int CreateEmitter(Vector2 originPosition, ResourceRef<ParticleEmitterSettingsResource> settingsResource)
|
||||
{
|
||||
var settings = settingsResource.Value.Settings;
|
||||
|
||||
if (_emitterSliceOffset + settings.MaxParticles >= ParticleLimit - 1)
|
||||
{
|
||||
_logger.Error("Cannot create an emitter! Reached particle limit.");
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
|
||||
var particles = new ArraySegment<Particle>(_particles, _emitterSliceOffset, settings.MaxParticles);
|
||||
@@ -173,11 +253,25 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
||||
particle.LifeTime = settings.LifeTime;
|
||||
}
|
||||
|
||||
var emitter = new ParticleEmitter(originPosition, settings, particles);
|
||||
var emitter = new ParticleEmitter(originPosition, settingsResource, particles);
|
||||
|
||||
_emitters.Add(emitter);
|
||||
|
||||
_emitterSliceOffset += settings.MaxParticles;
|
||||
|
||||
return _emitters.Count - 1;
|
||||
}
|
||||
|
||||
public void RestartEmitter(int id)
|
||||
{
|
||||
if (id > _emitters.Count - 1)
|
||||
{
|
||||
throw new ArgumentException($"Emitter with id {id} doesn't exist!");
|
||||
}
|
||||
|
||||
var emitter = _emitters[id];
|
||||
var particles = new ArraySegment<Particle>(_particles, emitter.ParticleArrayOffset, emitter.Settings.MaxParticles);
|
||||
|
||||
emitter.Restart(particles);
|
||||
}
|
||||
|
||||
public void Update(double deltaTime)
|
||||
@@ -196,7 +290,6 @@ public class ParticleSystem : IUpdatableSystem, IDisposable
|
||||
private void CleanupParticles() => Array.Clear(_particles);
|
||||
private Particle[] _particles;
|
||||
private int _particleIndex;
|
||||
|
||||
private int _emitterSliceOffset;
|
||||
|
||||
private List<ParticleEmitter> _emitters = new();
|
||||
|
||||
Reference in New Issue
Block a user