I want to implement collision on each enemy between each other. I want the enemies to hit each other and statically resolve the collision which means moving both enemy pairs once collision is found - mutable references.
for i in 0..enemies_len {
let enemy = &mut self.enemies[i];
// Register enemy collision on player
if enemy.rect.collision_other(&self.player.rect) {
info!("Player dead!");
return Ok(crate::State::GameOver)
}
for j in 0..enemies_len {
let other_enemy = &self.enemies[j];
}
// Move enemies
enemy.rect.offset_x(-enemy.rect.facing.cos() * dt as f32 * enemy.speed);
enemy.rect.offset_y(-enemy.rect.facing.sin() * dt as f32 * enemy.speed);
}
This leads to having both mutable and immutable borrows.
error[E0502]: cannot borrow `self.enemies` as immutable because it is also borrowed as mutable
--> src\GameStates\playing\mod.rs:167:24
|
160 | let enemy = &mut self.enemies[i];
| ------------ mutable borrow occurs here
...
167 | let other_enemy = &self.enemies[j];
| ^^^^^^^^^^^^ immutable borrow occurs here
...
171 | enemy.rect.offset_x(-enemy.rect.facing.cos() * dt as f32 * enemy.speed);
| ---------- mutable borrow later used here
split_at_mut is your friend, in general, for this kind of thing.
The other thing you can do is build a separate queue of changes to apply -- which is parallelizable and only needs shared reads -- and apply all the collision resolutions afterwards. That's how some of the MIR optimizations work in rustc, for example: