I have an entity that is generating other entities. For example, the generator has a position component, and I want the generated entity to have the same position as the generator.
In the generating system, it seems that I need to both read and write a component, which doesn't sound possible. The only option seems to be a LazyUpdate
, but I would like to avoid this because it requires a call to world::maintain
, and I want to use the generated entity in another system within the same frame.
My code for the system:
#[derive(Debug)]
struct Position {
x: f32, // meters
y: f32,
z: f32,
direction: f32,
}
impl Component for Position {
type Storage = VecStorage<Self>;
}
struct GenerateEntity;
impl<'a> System<'a> for GenerateEntity {
type SystemData = (
ReadStorage<'a, Generator>,
ReadStorage<'a, Position>,
Entities<'a>,
);
fn run(&mut self, (gen, pos, entities): Self::SystemData) {
for (pos, gen) in (&pos, &gen).join() {
let generated = entities.create();
// This gives an error because position can only be read
pos.insert(generated, pos.clone());
}
}
}
How do I get around this problem?
it would seem that I would need to both read and write a component, which doesn't sound possible
Sure it is: use a WriteStorage
.
The name is slightly misleading. WriteStorage
isn't write-only storage; it's mutable storage, which includes reading.
The only issue is that you will likely not be able to insert into the position storage while you are iterating over it. You'd need to store the changes you'd want to make during the loop and apply them afterwards.
(Also as the comments point out, you should rename the pos
in your loop (that refers to the single component) so that it doesn't shadow the pos
you take as an argument (that refers to the entire storage))