summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sim/lib/mod.rs1
-rw-r--r--src/sim/lib/ray.rs63
-rw-r--r--src/sim/particle_sim/mod.rs40
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;
}
}