// Copyright (c) Craftwork Games. All rights reserved. // Licensed under the MIT license. // See LICENSE file in the project root for full license information. using System; namespace MonoGame.Extended.Particles.Modifiers; /// /// Represents a base class for all particle modifiers. /// /// /// Particle modifiers are used to alter the behavior or properties of particles during their lifetime. /// Each modifier applies changes to particles at a configurable frequency, optimizing performance by /// spreading updates across frames when appropriate. /// Custom modifiers should inherit from this class and implement the method. /// public abstract class Modifier { private const float DEFAULT_MODIFIER_FREQUENCY = 60.0f; private float _frequency; private float _cycleTime; private int _particlesUpdatedThisCycle; /// /// Gets or sets the display name of this modifier. /// public string Name; /// /// Gets or sets the update frequency of this modifier. /// /// /// This value defines how often, in times per second, the modifier attempts to update /// the entire particle buffer. For example, a value of 60.0f means that all particles /// will be updated collectively approximately 60 times per second. /// /// To improve performance, updates are distributed across frames. Rather than updating /// every particle in every frame, the modifier mathematically distributes updates by /// processing a portion of the particles each frame based on the elapsed time and the /// desired frequency. Over time, this results in all particles being updated at the /// specified frequency on average, regardless of the actual frame rate. /// /// Higher values result in more frequent updates and smoother particle behavior, at the /// cost of performance. Lower values reduce CPU usage but may make particle changes appear /// less fluid. /// public float Frequency { get => _frequency; set { if (value <= 0.0f) throw new ArgumentOutOfRangeException(nameof(value), "Frequency must be greater than zero."); _frequency = value; _cycleTime = 1f / _frequency; } } /// /// Indicates whether this modifier is enabled. /// /// /// This value determines if this modifier is enabled. When a modifier is disabled, the modifier is not applied /// to the particles. /// public bool Enabled; /// /// Initializes a new instance of the class. /// /// /// The default constructor sets the property to the name of the derived class /// and initializes to . /// protected Modifier() { Name = GetType().Name; Frequency = DEFAULT_MODIFIER_FREQUENCY; Enabled = true; } internal void InternalUpdate(float elapsedSeconds, ParticleIterator iterator) { if (!Enabled || iterator.Total == 0) return; var particlesRemaining = iterator.Total - _particlesUpdatedThisCycle; var particlesToUpdate = Math.Min(particlesRemaining, (int)Math.Ceiling((elapsedSeconds / _cycleTime) * iterator.Total)); if (particlesToUpdate > 0) { // Create a new iterator starting from the offset position var offsetIterator = iterator.Reset(_particlesUpdatedThisCycle); Update(_cycleTime, offsetIterator, particlesToUpdate); _particlesUpdatedThisCycle += particlesToUpdate; } if (_particlesUpdatedThisCycle >= iterator.Total) _particlesUpdatedThisCycle = 0; } /// /// Updates the properties of particles according to this modifier's specific behavior. /// /// The elapsed time, in seconds, since the last update. /// The iterator used to iterate the particles ot update. protected internal abstract void Update(float elapsedSeconds, ParticleIterator iterator, int particleCount); }