diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/sim/lib/mod.rs | 1 | ||||
| -rw-r--r-- | src/sim/lib/ray.rs | 63 | ||||
| -rw-r--r-- | src/sim/particle_sim/mod.rs | 40 |
3 files changed, 71 insertions, 33 deletions
diff --git a/src/sim/lib/mod.rs b/src/sim/lib/mod.rs index a00d7e6..01373bc 100644 --- a/src/sim/lib/mod.rs +++ b/src/sim/lib/mod.rs @@ -1,2 +1,3 @@ pub mod force; pub mod marching_squares; +pub mod ray; diff --git a/src/sim/lib/ray.rs b/src/sim/lib/ray.rs new file mode 100644 index 0000000..52d5ba9 --- /dev/null +++ b/src/sim/lib/ray.rs @@ -0,0 +1,63 @@ +use glam::{IVec2, Vec2}; + +// Amanatides and Woo's fast Voxel Traversal +pub struct AwDda { + next: IVec2, + step_sign: IVec2, + step_delta: Vec2, + t_max: Vec2, +} + +impl AwDda { + pub fn new(from: Vec2, to: Vec2) -> Self { + let first = from.round().as_ivec2(); + // direction we step for each component on each iteration + let from_to_delta = to - from; + let step_sign = from_to_delta.signum().as_ivec2(); + + let step_delta = 1.0 / from_to_delta.abs(); + + let frac = Vec2::new( + if step_sign.x > 0 { + (first.x as f32 + 0.5) - from.x + } else { + from.x - (first.x as f32 - 0.5) + }, + if step_sign.y > 0 { + (first.y as f32 + 0.5) - from.y + } else { + from.y - (first.y as f32 - 0.5) + }, + ); + + let t_max = frac * step_delta; + + AwDda { + next: first, + step_sign, + step_delta, + t_max, + } + } +} + +impl Iterator for AwDda { + type Item = IVec2; + fn next(&mut self) -> Option<Self::Item> { + if self.t_max.min_element() >= 1.0 { + return None; + } + + let cur = self.next; + + if self.t_max.x < self.t_max.y { + self.next.x += self.step_sign.x; + self.t_max.x += self.step_delta.x; + } else { + self.next.y += self.step_sign.y; + self.t_max.y += self.step_delta.y; + } + + Some(cur) + } +} diff --git a/src/sim/particle_sim/mod.rs b/src/sim/particle_sim/mod.rs index 08febfb..4378d25 100644 --- a/src/sim/particle_sim/mod.rs +++ b/src/sim/particle_sim/mod.rs @@ -8,6 +8,7 @@ use crate::{ materials::{MaterialForm, MaterialId}, }, cell_sim::world::World, + lib::ray::AwDda, particle_sim::particle::Particle, }, }; @@ -35,46 +36,20 @@ impl ParticleManager { p.velocity.y += PARTICLE_GRAVITY * delta_time; let dt_velocity = p.velocity * delta_time; - // Amanatides and Woo's fast Voxel Traversal - { - let mut cur = IVec2::new(p.position.x.round() as i32, p.position.y.round() as i32); - // direction we step for each component on each iteration - let step_sign = - IVec2::new(dt_velocity.x.signum() as i32, dt_velocity.y.signum() as i32); - let delta = Vec2::new(1.0 / dt_velocity.x.abs(), 1.0 / dt_velocity.y.abs()); + let mut dda = AwDda::new(p.position, p.position + p.velocity * delta_time); - let frac = Vec2::new( - if step_sign.x > 0 { - (cur.x as f32 + 0.5) - p.position.x - } else { - p.position.x - (cur.x as f32 - 0.5) - }, - if step_sign.y > 0 { - (cur.y as f32 + 0.5) - p.position.y - } else { - p.position.y - (cur.y as f32 - 0.5) - }, - ); - let mut t_max = frac * delta; - - let mut prev = cur; + if let Some(prev) = dda.next() { if let Some(cell) = world.get_cell_from_game_position(prev.x, prev.y) && [MaterialForm::Solid, MaterialForm::Powder] .contains(&cell.material.def().form) { - // already occupied, die + // the particle is already inside a collider, we should just kill it self.particles.swap_remove(i); continue 'outer; } - while t_max.min_element() <= 1.0 { - if t_max.x < t_max.y { - cur.x += step_sign.x; - t_max.x += delta.x; - } else { - cur.y += step_sign.y; - t_max.y += delta.y; - } - if let Some(cell) = world.get_cell_from_game_position(cur.x, cur.y) + + for cell in dda.map(|p| world.get_cell_from_game_position(p.x, p.y)) { + if let Some(cell) = cell && [MaterialForm::Solid, MaterialForm::Powder] .contains(&cell.material.def().form) { @@ -88,7 +63,6 @@ impl ParticleManager { self.particles.swap_remove(i); continue 'outer; } - prev = cur; } } |
