use super::*;
impl ParticleRng {
pub fn with_seed(seed: u64) -> ParticleRng {
if seed == 0 {
ParticleRng::new(PARTICLE_DEFAULT_RNG_SEED)
} else {
ParticleRng::new(seed)
}
}
pub fn next_u64(&mut self) -> u64 {
let mut state: u64 = self.get_state();
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
self.set_state(state);
state.wrapping_mul(0x2545_F491_4F6C_DD1D)
}
pub fn next_f64(&mut self) -> f64 {
(self.next_u64() >> 11) as f64 / (1u64 << 53) as f64
}
pub fn range(&mut self, min: f64, max: f64) -> f64 {
min + (max - min) * self.next_f64()
}
}
impl Default for ParticleRng {
fn default() -> ParticleRng {
ParticleRng::with_seed(PARTICLE_DEFAULT_RNG_SEED)
}
}
impl Default for ParticleConfig {
fn default() -> ParticleConfig {
ParticleConfig {
emission_rate: PARTICLE_DEFAULT_EMISSION_RATE,
max_particles: PARTICLE_DEFAULT_MAX_COUNT,
lifetime_min: PARTICLE_DEFAULT_LIFETIME_MIN,
lifetime_max: PARTICLE_DEFAULT_LIFETIME_MAX,
speed_min: PARTICLE_DEFAULT_SPEED_MIN,
speed_max: PARTICLE_DEFAULT_SPEED_MAX,
angle: PARTICLE_DEFAULT_ANGLE,
spread: PARTICLE_DEFAULT_SPREAD,
gravity: Vector2D::zero(),
color_start: Color::white(),
color_end: Color::transparent(),
size_start: PARTICLE_DEFAULT_SIZE_START,
size_end: PARTICLE_DEFAULT_SIZE_END,
}
}
}
impl ParticleEmitter {
pub fn create(position: Vector2D, config: ParticleConfig) -> ParticleEmitter {
let mut emitter: ParticleEmitter = ParticleEmitter::new(position, config);
emitter.set_active(true);
emitter
}
pub fn with_defaults(position: Vector2D) -> ParticleEmitter {
ParticleEmitter::create(position, ParticleConfig::default())
}
pub fn update(&mut self, delta_time: f64) {
let delta_time: f64 = delta_time.max(0.0);
if self.get_active() {
*self.get_mut_emit_accumulator() += self.get_config().get_emission_rate() * delta_time;
let mut spawn_count: usize = self.get_emit_accumulator() as usize;
let capacity: usize = self
.get_config()
.get_max_particles()
.saturating_sub(self.get_particles().len());
spawn_count = spawn_count.min(capacity);
*self.get_mut_emit_accumulator() -= spawn_count as f64;
for _ in 0..spawn_count {
self.spawn_particle();
}
}
let gravity: Vector2D = self.get_config().get_gravity();
for particle in self.get_mut_particles().iter_mut() {
*particle.get_mut_velocity() += gravity.scaled(delta_time);
let velocity: Vector2D = particle.get_velocity();
*particle.get_mut_position() += velocity.scaled(delta_time);
*particle.get_mut_age() += delta_time;
}
self.get_mut_particles()
.retain(|particle: &Particle| particle.get_age() < particle.get_lifetime());
}
pub fn burst(&mut self, count: usize) {
let capacity: usize = self
.get_config()
.get_max_particles()
.saturating_sub(self.get_particles().len());
for _ in 0..count.min(capacity) {
self.spawn_particle();
}
}
pub fn render(&self, draw_list: &mut DrawList) {
let config: ParticleConfig = self.get_config();
for particle in self.get_particles().iter() {
let t: f64 = if particle.get_lifetime() > 0.0 {
(particle.get_age() / particle.get_lifetime()).min(1.0)
} else {
1.0
};
let color: Color = config.get_color_start().lerp(config.get_color_end(), t);
let radius: f64 = Numeric::lerp(config.get_size_start(), config.get_size_end(), t);
if radius <= 0.0 || color.get_alpha() <= 0.0 {
continue;
}
draw_list.fill_circle(particle.get_position(), radius, color);
}
}
pub fn alive_count(&self) -> usize {
self.get_particles().len()
}
pub fn clear(&mut self) {
self.get_mut_particles().clear();
self.set_emit_accumulator(0.0);
}
fn spawn_particle(&mut self) {
let config: ParticleConfig = self.get_config();
let half_spread: f64 = config.get_spread() / 2.0;
let angle: f64 = config.get_angle() + self.get_mut_rng().range(-half_spread, half_spread);
let speed: f64 = self
.get_mut_rng()
.range(config.get_speed_min(), config.get_speed_max());
let lifetime: f64 = self
.get_mut_rng()
.range(config.get_lifetime_min(), config.get_lifetime_max())
.max(EPSILON);
let position: Vector2D = self.get_position();
let particle: Particle = Particle::new(
position,
Vector2D::from_angle(angle).scaled(speed),
0.0,
lifetime,
);
self.get_mut_particles().push(particle);
}
}
impl Updatable for ParticleEmitter {
fn update(&mut self, delta_time: f64) {
ParticleEmitter::update(self, delta_time);
}
}