Skip to content

Instantly share code, notes, and snippets.

@niksaak
Last active December 11, 2020 09:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niksaak/24b352c275e08822065dd94c0694469c to your computer and use it in GitHub Desktop.
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 .
#[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();
}
}
}
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;
}
});
#[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