Last active
December 11, 2020 09:50
-
-
Save niksaak/24b352c275e08822065dd94c0694469c to your computer and use it in GitHub Desktop.
Comparison of using different ECS frameworks for implementing non-trivial but simple logic. Legion version courtesy of @lain-dono .
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[derive(Default)] | |
pub struct ParticleSystem { | |
to_spawn: Vec<(Particle, Transform, LocalToWorld, Velocity, Render, Flags)>, | |
to_despawn: Vec<Entity>, | |
} | |
impl ParticleSystem { | |
pub fn run(&mut self, world: &mut World, resources: &mut Resources) { | |
let dt = resources.frame_time; | |
for (entity, (emitter, matrix)) in &mut world.query::<(&mut ParticleEmitter, &LocalToWorld)>() { | |
if emitter.current_count < emitter.max_count { | |
emitter.current_count += 5; | |
let angle = rand::random::<f32>() * 2.0 * ::std::f32::consts::PI; | |
let dist = emitter.spawn_radius * rand::random::<f32>().sqrt(); | |
let mut position = na::Vector2::from([angle.cos(), angle.sin()]) * dist; | |
position = matrix.0.transform_point(&position.into()).coords; | |
let scale = 0.25; | |
self.to_spawn.push(( | |
Particle { emitter: entity, kill_timer: emitter.initial_kill_timer }, | |
Transform { position, scale, ..Default::default() }, | |
LocalToWorld::default(), | |
Velocity( emitter.initial_velocity ), | |
Render { | |
handle: *resources.drawable_registry.0.get("filled_circle").unwrap(), | |
color: [0.314, 0.682, 0.314, 1.0], | |
}, | |
Flags::EDITOR_HIDDEN, | |
)); | |
} | |
} | |
for particle in self.to_spawn.drain(..) { | |
world.spawn(particle); | |
} | |
for (entity, (particle, render, transform)) in &mut world.query::<(&mut Particle, &mut Render, &mut Transform)>() { | |
let mut deleted = false; | |
if particle.kill_timer <= 0.0 { | |
self.to_despawn.push(entity); | |
deleted = true; | |
} | |
if let Ok(mut emitter) = world.get_mut::<ParticleEmitter>(particle.emitter) { | |
if deleted { | |
emitter.current_count -= 1; | |
} | |
let life_ratio = particle.kill_timer / emitter.initial_kill_timer; | |
render.color[3] = life_ratio; | |
transform.scale = life_ratio * 0.2; | |
} | |
particle.kill_timer -= dt; | |
} | |
for entity in self.to_despawn.drain(..) { | |
world.despawn(entity).unwrap(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let mut particle_system = SystemBuilder::new("ParticleSystem") | |
.read_resource::<Time>() | |
.write_resource::<DrawableRegistry>() | |
.with_query(<(&mut ParticleEmitter, &LocalToWorld)>::query()) | |
.with_query(<(&mut Particle, &mut Render, &mut Transform)>::query()) | |
.build(move |commands, world, (time, drawable_registry), (emitters, particles)| { | |
for (entity, emitter, matrix) in emitters.iter_mut(world) { | |
if emitter.current_count < emitter.max_count { | |
emitter.current_count += 5; | |
let angle = rand::random::<f32>() * 2.0 * ::std::f32::consts::PI; | |
let dist = emitter.spawn_radius * rand::random::<f32>().sqrt(); | |
let mut position = na::Vector2::from([angle.cos(), angle.sin()]) * dist; | |
position = matrix.0.transform_point(&position.into()).coords; | |
let scale = 0.25; | |
commands.push(( | |
Particle { emitter: entity, kill_timer: emitter.initial_kill_timer }, | |
Transform { position, scale, ..Default::default() }, | |
LocalToWorld::default(), | |
Velocity( emitter.initial_velocity ), | |
Render { | |
handle: drawable_registry.get("filled_circle").unwrap(), | |
color: [0.314, 0.682, 0.314, 1.0], | |
}, | |
Flags::EDITOR_HIDDEN, | |
)); | |
} | |
} | |
let (left, right) = world.split::<&mut ParticleEmitter>(); | |
for (entity, particle, render, transform) in particles.iter_mut(right) { | |
let mut deleted = false; | |
if particle.kill_timer <= 0.0 { | |
commands.remove(entity); | |
deleted = true; | |
} | |
if let Ok(mut emitter) = left.entry_mut(particle.emitter) | |
.and_then(|entry| entry.into_component_mut::<ParticleEmitter>().ok()) { | |
if deleted { | |
emitter.current_count -= 1; | |
} | |
let life_ratio = particle.kill_timer / emitter.initial_kill_timer; | |
render.color[3] = life_ratio; | |
transform.scale = life_ratio * 0.2; | |
} | |
particle.kill_timer -= dt; | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[derive(Default)] | |
pub struct ParticleSystem; | |
impl<'a> System<'a> for ParticleSystem { | |
type SystemData = ( | |
Entities<'a>, | |
Read<'a, DrawableRegistry>, | |
ReadExpect<'a, FrameTime>, | |
ReadStorage<'a, TransformMatrix>, | |
WriteStorage<'a, ParticleEmitter>, | |
WriteStorage<'a, Particle>, | |
WriteStorage<'a, Transform>, | |
WriteStorage<'a, Velocity>, | |
WriteStorage<'a, Render>, | |
WriteStorage<'a, EditorHidden>, | |
); | |
fn run( | |
&mut self, | |
( | |
entities, | |
drawable_registry, | |
delta_time, | |
matrices, | |
mut emitters, | |
mut particles, | |
mut transforms, | |
mut velocities, | |
mut renders, | |
mut editor_hidden, | |
): Self::SystemData | |
) { | |
let dt = delta_time.0; | |
for (entity, emitter, matrix) in (&entities, &mut emitters, &matrices).join() { | |
if emitter.current_count < emitter.max_count { | |
emitter.current_count += 5; | |
for _ in 0..5 { | |
let particle = entities.create(); | |
let angle = rand::random::<f32>() * 2.0 * ::std::f32::consts::PI; | |
let dist = emitter.spawn_radius * rand::random::<f32>().sqrt(); | |
let mut position = (na::Vector2::from([angle.cos(), angle.sin()]) * dist).into(); | |
position = matrix.0.transform_point(&position); | |
let scale = [0.25, 0.25].into(); | |
particles.insert(particle, Particle { emitter: entity, kill_timer: emitter.initial_kill_timer }).unwrap(); | |
transforms.insert(particle, Transform{ position, scale, ..Default::default() }).unwrap(); | |
velocities.insert(particle, Velocity( emitter.initial_velocity )).unwrap(); | |
renders.insert(particle, Render { | |
handle: *drawable_registry.0.get("filled_square").unwrap(), | |
color: [0.314, 0.682, 0.314, 1.0], | |
}).unwrap(); | |
editor_hidden.insert(particle, EditorHidden).unwrap(); | |
} | |
} | |
} | |
for (entity, particle, render, transform) in (&entities, &mut particles, &mut renders, &mut transforms).join() { | |
let mut deleted = false; | |
if particle.kill_timer <= 0.0 { | |
entities.delete(entity).unwrap(); | |
deleted = true; | |
} | |
if let Some(emitter) = emitters.get_mut(particle.emitter) { | |
if deleted { | |
emitter.current_count -= 1; | |
} | |
let life_ratio = particle.kill_timer / emitter.initial_kill_timer; | |
render.color[3] = life_ratio; | |
transform.scale = na::Vector2::from([life_ratio, life_ratio]) * 0.25; | |
} | |
particle.kill_timer -= dt; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment