amethyst/legion

Idiomatic way of removing specific entities

nyvs opened this issue · 3 comments

nyvs commented

Let's say someone wants to delete missiles which have been exploded.
Intuitively, I'd want to delete it directly in the system which goes over all the missiles, but this won't work because of the borrow checker.
The next step for me would be to try to note their 'Entity' which acts as an ID, so I can call world.remove. Which also doesn't work, I cannot "get" the entity in the system.
So that leaves one option open; for every frame, Iterating over every entity and checking if some entity has a special component which hints for this entity to be deleted, then pushing it to a vec, and then going over the vec and calling world.remove?

Is that correct? Is there a better way? Thank you :)

nyvs commented

My current way of removing missiles looks like this:

fn remove_dead_missiles(world: &mut World) {
	let mut entity_list = vec![];
	let mut query = <Entity>::query();
	for entity in query.iter(world) {
		entity_list.push(*entity);
	}
	let mut to_delete = vec![];
	for e in entity_list {
		let ent = world.entry(e).unwrap();
		match ent.get_component::<Missile>() {
			Ok(m) => if m.is_set_off {
				to_delete.push(e);
			},
			Err(_) => (),
		}
	}
	for del in to_delete.iter() {
		world.remove(*del);
	}
}

Hi @nyvs, not sure about the idiomatic way, but I can share with you my approach for solving such tasks.

All my logic is packed into systems generated via #[legion::system] macro (and executed in Schedule), so when I need to add/remove entities or components I simply request my system to access CommandBuffer and record corresponding commands into it.

In your case, such a system can look like this:

use legion::{Query, systems::CommandBuffer, world::SubWorld};

#[legion::system]
fn remove_exploded_missiles(objects: &mut Query<(Entity, &Missile)>,
                            commands: &mut CommandBuffer,
                            world: &mut SubWorld)
{
    for (entity, missile) in objects.iter(world) {
        if missile.is_set_off {
            commands.remove(entity);
        }
    }                    
}

Please let us know if this does not work for you.

nyvs commented

Hi! Thank you so much. I now successfully moved from plain queries to all-systems, which works beautifully, and even better: everything works as expected. I must say I love legion.