summaryrefslogtreecommitdiff
path: root/src/sim
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2026-08-22 15:00:35 -0700
committerKai Stevenson <kai@kaistevenson.com>2026-08-22 15:00:35 -0700
commit1a515237afb7ad09353a65f5fbc6e98a7c29ce8e (patch)
tree48cd4b4bcf8f8e357811f905f22607838d7c1f96 /src/sim
parent6350e4ffca8ce1e46465284ef3d7559e0f40229b (diff)
sim manager refactor
Diffstat (limited to 'src/sim')
-rw-r--r--src/sim/cell/materials/fire.rs2
-rw-r--r--src/sim/cell/materials/gas.rs2
-rw-r--r--src/sim/cell/materials/liquid.rs2
-rw-r--r--src/sim/cell/materials/mod.rs2
-rw-r--r--src/sim/cell/materials/powder.rs2
-rw-r--r--src/sim/cell_manager/chunk.rs (renamed from src/sim/cell_sim/chunk.rs)0
-rw-r--r--src/sim/cell_manager/manager.rs (renamed from src/sim/cell_sim/world.rs)29
-rw-r--r--src/sim/cell_manager/mod.rs (renamed from src/sim/cell_sim/mod.rs)2
-rw-r--r--src/sim/cell_manager/sim.rs (renamed from src/sim/cell_sim/sim.rs)6
-rw-r--r--src/sim/entity/mod.rs28
-rw-r--r--src/sim/lib/force.rs24
-rw-r--r--src/sim/mod.rs69
-rw-r--r--src/sim/particle_manager/mod.rs (renamed from src/sim/particle_sim/mod.rs)6
-rw-r--r--src/sim/particle_manager/particle.rs (renamed from src/sim/particle_sim/particle.rs)0
-rw-r--r--src/sim/rb_manager/debug_ops.rs (renamed from src/sim/rb_sim/debug_ops.rs)4
-rw-r--r--src/sim/rb_manager/debug_render.rs (renamed from src/sim/rb_sim/debug_render.rs)0
-rw-r--r--src/sim/rb_manager/mod.rs (renamed from src/sim/rb_sim/mod.rs)12
-rw-r--r--src/sim/rb_manager/rb_entity.rs (renamed from src/sim/rb_sim/rb_entity.rs)0
-rw-r--r--src/sim/sim_manager/mod.rs152
-rw-r--r--src/sim/sim_manager/utils.rs62
20 files changed, 296 insertions, 108 deletions
diff --git a/src/sim/cell/materials/fire.rs b/src/sim/cell/materials/fire.rs
index 8667cea..8cabe30 100644
--- a/src/sim/cell/materials/fire.rs
+++ b/src/sim/cell/materials/fire.rs
@@ -2,7 +2,7 @@ use rand::RngExt;
use crate::sim::{
cell::{cell::Cell, materials::MaterialId},
- cell_sim::sim::{PostUpdateAction, UpdateCtx},
+ cell_manager::sim::{PostUpdateAction, UpdateCtx},
};
pub trait FireCellView {
diff --git a/src/sim/cell/materials/gas.rs b/src/sim/cell/materials/gas.rs
index af8f4fd..229d0e9 100644
--- a/src/sim/cell/materials/gas.rs
+++ b/src/sim/cell/materials/gas.rs
@@ -1,6 +1,6 @@
use rand::RngExt;
-use crate::sim::cell_sim::sim::{PostUpdateAction, UpdateCtx};
+use crate::sim::cell_manager::sim::{PostUpdateAction, UpdateCtx};
#[inline]
pub fn sim_update(ctx: &mut UpdateCtx) -> PostUpdateAction {
diff --git a/src/sim/cell/materials/liquid.rs b/src/sim/cell/materials/liquid.rs
index bff0ac0..6c3bdcd 100644
--- a/src/sim/cell/materials/liquid.rs
+++ b/src/sim/cell/materials/liquid.rs
@@ -1,4 +1,4 @@
-use crate::sim::cell_sim::sim::{PostUpdateAction, UpdateCtx};
+use crate::sim::cell_manager::sim::{PostUpdateAction, UpdateCtx};
#[inline]
pub fn sim_update(ctx: &mut UpdateCtx) -> PostUpdateAction {
diff --git a/src/sim/cell/materials/mod.rs b/src/sim/cell/materials/mod.rs
index ee2b4d0..5439cca 100644
--- a/src/sim/cell/materials/mod.rs
+++ b/src/sim/cell/materials/mod.rs
@@ -1,4 +1,4 @@
-use crate::sim::cell_sim::sim::{PostUpdateAction, UpdateCtx};
+use crate::sim::cell_manager::sim::{PostUpdateAction, UpdateCtx};
pub mod fire;
pub mod gas;
diff --git a/src/sim/cell/materials/powder.rs b/src/sim/cell/materials/powder.rs
index e08ea1f..8c916e4 100644
--- a/src/sim/cell/materials/powder.rs
+++ b/src/sim/cell/materials/powder.rs
@@ -1,4 +1,4 @@
-use crate::sim::cell_sim::sim::{PostUpdateAction, UpdateCtx};
+use crate::sim::cell_manager::sim::{PostUpdateAction, UpdateCtx};
#[inline]
pub fn sim_update(ctx: &mut UpdateCtx) -> PostUpdateAction {
diff --git a/src/sim/cell_sim/chunk.rs b/src/sim/cell_manager/chunk.rs
index 3fe5056..3fe5056 100644
--- a/src/sim/cell_sim/chunk.rs
+++ b/src/sim/cell_manager/chunk.rs
diff --git a/src/sim/cell_sim/world.rs b/src/sim/cell_manager/manager.rs
index 924639a..094f345 100644
--- a/src/sim/cell_sim/world.rs
+++ b/src/sim/cell_manager/manager.rs
@@ -2,24 +2,24 @@ use fxhash::FxHashMap;
use crate::{
config::CHUNK_SIZE,
- sim::{cell::cell::Cell, cell_sim::chunk::Chunk},
+ sim::{
+ cell::cell::Cell,
+ cell_manager::{chunk::Chunk, sim::sim_tick},
+ },
};
-pub struct World {
+pub struct CellManager {
+ pub seqno: u64,
pub chunks: Vec<Chunk>,
// TODO FxFxHashMap?
pub chunk_position_to_chunk_idx: FxHashMap<(i32, i32), usize>,
}
-impl World {
+impl CellManager {
#[inline]
pub fn split_game_position(x: i32, y: i32) -> ((i32, i32), (u8, u8)) {
(
- (
- // TODO is this cast expensive?
- x.div_euclid(CHUNK_SIZE),
- y.div_euclid(CHUNK_SIZE),
- ),
+ (x.div_euclid(CHUNK_SIZE), y.div_euclid(CHUNK_SIZE)),
(
x.rem_euclid(CHUNK_SIZE) as u8,
y.rem_euclid(CHUNK_SIZE) as u8,
@@ -29,7 +29,7 @@ impl World {
// VERY EXPENSIVE
pub fn get_cell_from_game_position(&self, x: i32, y: i32) -> Option<Cell> {
- let ((cx, cy), (dx, dy)) = World::split_game_position(x, y);
+ let ((cx, cy), (dx, dy)) = CellManager::split_game_position(x, y);
self.chunk_position_to_chunk_idx
.get(&(cx, cy))
.map(|&idx| self.chunks[idx].get_cell_at_local_position(dx, dy))
@@ -37,7 +37,7 @@ impl World {
// VERY EXPENSIVE
pub fn set_cell_from_game_position(&mut self, x: i32, y: i32, cell: Cell, sleeping: bool) {
- let ((cx, cy), (dx, dy)) = World::split_game_position(x, y);
+ let ((cx, cy), (dx, dy)) = CellManager::split_game_position(x, y);
if let Some(&idx) = self.chunk_position_to_chunk_idx.get(&(cx, cy)) {
self.chunks[idx].set_cell_at_local_position(dx, dy, cell);
// this is a temporary hack
@@ -52,8 +52,15 @@ impl World {
self.chunks.push(chunk);
}
+ pub fn tick(&mut self, use_threading: bool) {
+ let seqno = self.seqno;
+ sim_tick(self, seqno, use_threading);
+ self.seqno += 1;
+ }
+
pub fn from_default_size() -> Self {
- let mut world = World {
+ let mut world = CellManager {
+ seqno: 0,
chunks: Vec::new(),
chunk_position_to_chunk_idx: FxHashMap::default(),
};
diff --git a/src/sim/cell_sim/mod.rs b/src/sim/cell_manager/mod.rs
index b7d0597..67d7614 100644
--- a/src/sim/cell_sim/mod.rs
+++ b/src/sim/cell_manager/mod.rs
@@ -1,3 +1,3 @@
pub mod chunk;
+pub mod manager;
pub mod sim;
-pub mod world;
diff --git a/src/sim/cell_sim/sim.rs b/src/sim/cell_manager/sim.rs
index fbaf2f0..b79608e 100644
--- a/src/sim/cell_sim/sim.rs
+++ b/src/sim/cell_manager/sim.rs
@@ -8,7 +8,7 @@ use crate::{
config::{CHUNK_SIZE, SETTLED_THRESOHLD},
sim::{
cell::{cell::Cell, materials::MaterialDef},
- cell_sim::{chunk::Chunk, world::World},
+ cell_manager::{chunk::Chunk, manager::CellManager},
},
};
@@ -220,7 +220,7 @@ impl UpdateCtx<'_, '_, '_> {
}
}
-pub fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
+fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
puffin::profile_function!();
let seqno_parity = (seqno as u8) & 0b1;
let mut rng = SmallRng::seed_from_u64(seqno);
@@ -280,7 +280,7 @@ pub fn sim_tick_chunk(chunks: &mut [Option<&mut Chunk>; 9], seqno: u64) {
}
}
-pub fn sim_tick(world: &mut World, seqno: u64, use_threading: bool) {
+pub fn sim_tick(world: &mut CellManager, seqno: u64, use_threading: bool) {
puffin::profile_function!();
let mut columns: FxHashMap<i32, Vec<i32>> = FxHashMap::default();
diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs
new file mode 100644
index 0000000..ab10ea8
--- /dev/null
+++ b/src/sim/entity/mod.rs
@@ -0,0 +1,28 @@
+// use glam::{IVec2, Vec2};
+// use rapier2d::{dynamics::RigidBodyHandle, geometry::ColliderHandle};
+
+// use crate::sim::cell::cell::Cell;
+
+// pub struct EntityCells {
+// pub size: IVec2,
+// pub cells: Vec<Cell>,
+// }
+// pub trait EntityBehaviour {
+// fn update (&mut self) -> ();
+// }
+
+// pub struct Entity {
+// pub rb_h: Option<RigidBodyHandle>,
+// pub collider_h: Option<ColliderHandle>,
+// pub cells: EntityCells,
+// pub behaviour:
+// }
+
+// impl Entity {
+// pub fn position(&self, rbsm:) -> Vec2 {
+
+// }
+// pub fn destroy(&mut self) -> {
+
+// }
+// }
diff --git a/src/sim/lib/force.rs b/src/sim/lib/force.rs
index 50b5c70..e8f7e90 100644
--- a/src/sim/lib/force.rs
+++ b/src/sim/lib/force.rs
@@ -6,20 +6,16 @@ use crate::sim::{
cell::Cell,
materials::{MaterialId, fire::FireCellView},
},
- cell_sim::world::World,
- particle_sim::{ParticleManager, particle::Particle},
- rb_sim::RbSimManager,
+ particle_manager::particle::Particle,
+ sim_manager::SimManager,
};
pub fn apply_explosion(
+ sim: &mut SimManager,
centre: Vec2,
radius: i32,
force_offset: Vec2,
force_multiplier: f32,
- next_seqno: u64,
- particle_manager: &mut ParticleManager,
- world: &mut World,
- rbsm: &mut RbSimManager,
) {
let get_vel = |pos: Vec2| {
let d = pos.distance(centre);
@@ -38,17 +34,18 @@ pub fn apply_explosion(
// if there's a cell, convert it to a particle
let pos = Vec2::new(centre.x + x as f32, centre.y + y as f32);
let ipos = pos.round().as_ivec2();
- if let Some(cell) = world.get_cell_from_game_position(ipos.x, ipos.y) {
+ if let Some(cell) = sim.cell_manager.get_cell_from_game_position(ipos.x, ipos.y) {
let mut fire = Cell::from_material(MaterialId::Fire);
fire.set_ticks_lived(300);
- fire.match_parity(next_seqno);
+ fire.match_parity(sim.cell_manager.seqno);
if cell.material == MaterialId::Void && random_range(0.0..1.0) > 0.5 {
if random_range(0.0..1.0) > 0.1 {
- world.set_cell_from_game_position(ipos.x, ipos.y, fire, false);
+ sim.cell_manager
+ .set_cell_from_game_position(ipos.x, ipos.y, fire, false);
} else {
let vel = get_vel(pos);
- particle_manager.particles.push(Particle::new(
+ sim.particle_manager.particles.push(Particle::new(
pos,
vel,
MaterialId::Fire,
@@ -56,10 +53,11 @@ pub fn apply_explosion(
));
}
} else {
- world.set_cell_from_game_position(ipos.x, ipos.y, fire, false);
+ sim.cell_manager
+ .set_cell_from_game_position(ipos.x, ipos.y, fire, false);
if random_range(0.0..1.0) > 0.6 {
let vel = get_vel(pos);
- particle_manager.particles.push(Particle::new(
+ sim.particle_manager.particles.push(Particle::new(
pos,
vel,
cell.material,
diff --git a/src/sim/mod.rs b/src/sim/mod.rs
index d9e358b..95fb2db 100644
--- a/src/sim/mod.rs
+++ b/src/sim/mod.rs
@@ -1,66 +1,7 @@
-use crate::sim::{cell::materials::MaterialId, cell_sim::world::World, rb_sim::RbSimManager};
-
pub mod cell;
-pub mod cell_sim;
+pub mod cell_manager;
+pub mod entity;
pub mod lib;
-pub mod particle_sim;
-pub mod rb_sim;
-
-pub fn write_rb_entity_to_world(
- world: &mut World,
- rb_sim_manager: &RbSimManager,
- rb_entity_id: u32,
- // make sure these cells will be simulated
- seqno: u64,
- // (entity_x, entity_y, cell_x, cell_y)
-) -> Vec<(u8, u8, i32, i32)> {
- let mut cells_written: Vec<(u8, u8, i32, i32)> = Vec::new();
- if let Some(rb_entity) = rb_sim_manager.rb_entities.get(&rb_entity_id)
- && let Some((rb_x, rb_y, cos, sin)) = rb_sim_manager.get_rb_entity_transform(rb_entity_id)
- {
- let (half_size_x, half_size_y) =
- (rb_entity.width as f32 / 2.0, rb_entity.height as f32 / 2.0);
- // half-extent of the rotated grid's axis-aligned bounding box, plus a cell of margin
- let (radius_x, radius_y) = (
- half_size_x * (cos.abs() + sin.abs()) + 1.0,
- half_size_y * (cos.abs() + sin.abs()) + 1.0,
- );
-
- let world_xl = (rb_x - radius_x).floor() as i32;
- let world_xu = (rb_x + radius_x).ceil() as i32;
- let world_yl = (rb_y - radius_y).floor() as i32;
- let world_yu = (rb_y + radius_y).ceil() as i32;
-
- for world_x in world_xl..=world_xu {
- for world_y in world_yl..=world_yu {
- if let Some(cur_world_cell) = world.get_cell_from_game_position(world_x, world_y)
- && cur_world_cell.material == MaterialId::Void
- {
- // same as shader
- let d = (world_x as f32 + 0.5 - rb_x, world_y as f32 + 0.5 - rb_y);
- let q = (d.0.floor() + 0.5, d.1.floor() + 0.5);
- let (lx, ly) = (
- (q.0 * cos + q.1 * sin + half_size_x).floor() as i32,
- (-q.0 * sin + q.1 * cos + half_size_y).floor() as i32,
- );
-
- if lx < 0 || ly < 0 || lx >= rb_entity.width || ly >= rb_entity.height {
- continue;
- }
-
- let mut cell = rb_entity.get_cell_at_local_position(lx as u8, ly as u8);
- if cell.material == MaterialId::Void {
- continue;
- }
-
- cell.match_parity(seqno);
-
- // TODO: OPTIMIZE!!
- world.set_cell_from_game_position(world_x, world_y, cell, false);
- cells_written.push((lx as u8, ly as u8, world_x, world_y));
- }
- }
- }
- }
- cells_written
-}
+pub mod particle_manager;
+pub mod rb_manager;
+pub mod sim_manager;
diff --git a/src/sim/particle_sim/mod.rs b/src/sim/particle_manager/mod.rs
index 84a728a..e5e47eb 100644
--- a/src/sim/particle_sim/mod.rs
+++ b/src/sim/particle_manager/mod.rs
@@ -2,9 +2,9 @@ use crate::{
config::PIXELS_TO_METRES,
sim::{
cell::{cell::Cell, materials::MaterialForm},
- cell_sim::world::World,
+ cell_manager::manager::CellManager,
lib::ray::AwDda,
- particle_sim::particle::Particle,
+ particle_manager::particle::Particle,
},
};
@@ -17,7 +17,7 @@ pub struct ParticleManager {
const PARTICLE_GRAVITY: f32 = 9.81 * PIXELS_TO_METRES;
impl ParticleManager {
- pub fn particle_tick(&mut self, world: &mut World, delta_time: f32) {
+ pub fn tick(&mut self, world: &mut CellManager, delta_time: f32) {
puffin::profile_function!();
let mut i = 0;
'outer: while i < self.particles.len() {
diff --git a/src/sim/particle_sim/particle.rs b/src/sim/particle_manager/particle.rs
index cc7dd28..cc7dd28 100644
--- a/src/sim/particle_sim/particle.rs
+++ b/src/sim/particle_manager/particle.rs
diff --git a/src/sim/rb_sim/debug_ops.rs b/src/sim/rb_manager/debug_ops.rs
index d6852da..cb56256 100644
--- a/src/sim/rb_sim/debug_ops.rs
+++ b/src/sim/rb_manager/debug_ops.rs
@@ -2,7 +2,7 @@ use glam::{ivec2, vec2};
use crate::sim::{
cell::{cell::Cell, materials::MaterialId},
- rb_sim::RbSimManager,
+ rb_manager::RbManager,
};
pub trait DebugOperator {
@@ -10,7 +10,7 @@ pub trait DebugOperator {
fn test_spawn_ball(&mut self, x: f32, y: f32, material: MaterialId) -> ();
}
-impl DebugOperator for RbSimManager {
+impl DebugOperator for RbManager {
fn test_spawn_box(&mut self, x: f32, y: f32, material: MaterialId) {
let w = 10;
let h = 10;
diff --git a/src/sim/rb_sim/debug_render.rs b/src/sim/rb_manager/debug_render.rs
index 342fc5b..342fc5b 100644
--- a/src/sim/rb_sim/debug_render.rs
+++ b/src/sim/rb_manager/debug_render.rs
diff --git a/src/sim/rb_sim/mod.rs b/src/sim/rb_manager/mod.rs
index f81d5f1..2c64f12 100644
--- a/src/sim/rb_sim/mod.rs
+++ b/src/sim/rb_manager/mod.rs
@@ -10,9 +10,9 @@ use crate::{
config::{CHUNK_SIZE, PHYSICS_DELTA_TIME, PIXELS_TO_METRES},
sim::{
cell::cell::Cell,
- cell_sim::chunk::Chunk,
+ cell_manager::chunk::Chunk,
lib::marching_squares::{Marchable, marching_squares_vertex_trace},
- rb_sim::{
+ rb_manager::{
debug_render::{DebugLineBuffer, DebugVertex},
rb_entity::RbEntity,
},
@@ -65,7 +65,7 @@ impl PhysicsManager {
}
}
-pub struct RbSimManager {
+pub struct RbManager {
chunk_colliders: FxHashMap<(i32, i32), geometry::ColliderHandle>,
pub rb_entities: FxHashMap<u32, RbEntity>,
@@ -74,8 +74,8 @@ pub struct RbSimManager {
debug_line_buffer: DebugLineBuffer,
}
-impl RbSimManager {
- pub fn rb_tick(&mut self, delta_time: f32) {
+impl RbManager {
+ pub fn tick(&mut self, _delta_time: f32) {
let gravity = vec2(0.0, 9.81);
self.physics_manager.physics_pipeline.step(
@@ -277,7 +277,7 @@ impl RbSimManager {
}
pub fn new() -> Self {
- RbSimManager {
+ RbManager {
rb_entities: FxHashMap::default(),
chunk_colliders: FxHashMap::default(),
diff --git a/src/sim/rb_sim/rb_entity.rs b/src/sim/rb_manager/rb_entity.rs
index 18a6693..18a6693 100644
--- a/src/sim/rb_sim/rb_entity.rs
+++ b/src/sim/rb_manager/rb_entity.rs
diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs
new file mode 100644
index 0000000..a98f3b2
--- /dev/null
+++ b/src/sim/sim_manager/mod.rs
@@ -0,0 +1,152 @@
+use std::time::Instant;
+
+use crate::{
+ Config,
+ config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS},
+ sim::{
+ cell::{cell::Cell, materials::MaterialId},
+ cell_manager::manager::CellManager,
+ particle_manager::ParticleManager,
+ rb_manager::RbManager,
+ sim_manager::utils::write_rb_entity_to_world,
+ },
+};
+
+mod utils;
+
+pub struct SimManager {
+ // timing
+ pub paused: bool,
+ pub ignore_pause_next_tick: bool,
+ pub last_cell_update: Instant,
+ pub cell_updates_due: f32,
+ pub last_physics_update: Instant,
+ pub physics_updates_due: f32,
+
+ // systems
+ pub cell_manager: CellManager,
+ pub rb_manager: RbManager,
+ pub particle_manager: ParticleManager,
+}
+
+impl SimManager {
+ pub fn new() -> Self {
+ SimManager {
+ paused: false,
+ ignore_pause_next_tick: false,
+ last_cell_update: Instant::now(),
+ cell_updates_due: 0.0,
+ last_physics_update: Instant::now(),
+ physics_updates_due: 0.0,
+ cell_manager: CellManager::from_default_size(),
+ rb_manager: RbManager::new(),
+ particle_manager: ParticleManager::new(),
+ }
+ }
+
+ fn cell_update(&mut self, config: &Config) {
+ // before we tick, write all the rb entities into the sim world
+ // TODO optimize
+ let entity_ids: Vec<u32> = self.rb_manager.rb_entities.keys().copied().collect();
+ let mut cells_written_by_entity: Vec<(u32, Vec<(u8, u8, i32, i32)>)> = Vec::new();
+
+ for entity_id in entity_ids {
+ let cells_written = write_rb_entity_to_world(self, entity_id, self.cell_manager.seqno);
+ cells_written_by_entity.push((entity_id, cells_written));
+ }
+
+ self.cell_manager.tick(config.use_threading);
+
+ // after we tick, remove the written rb cells and update the entities
+ // TODO optimize
+ for (entity_id, cells_written) in cells_written_by_entity {
+ let rb_entity = self.rb_manager.rb_entities.get_mut(&entity_id).unwrap();
+ for (lx, ly, x, y) in cells_written {
+ // update the entity
+ // TODO we should skip cells that weren't changed?
+ // TODO optimize
+ let new_local_cell = self.cell_manager.get_cell_from_game_position(x, y).unwrap();
+ if new_local_cell.material != MaterialId::Void && !new_local_cell.rb() {
+ panic!(
+ "Someone swapped into this rb's cell! ({x}, {y}, {m:#?}, {f})",
+ m = new_local_cell.material,
+ f = new_local_cell.flags
+ );
+ }
+ rb_entity.set_cell_at_local_position(lx, ly, new_local_cell);
+ // update the world
+ self.cell_manager
+ .set_cell_from_game_position(x, y, Cell::void(), false);
+ }
+ }
+ }
+
+ fn physics_update(&mut self, delta_time: f32) {
+ // before we move the rigidbodies, upsert the current terrain state
+ // TODO use the chunk sleeping, and make this range dynamic
+ for cx in -5..5 {
+ for cy in -5..5 {
+ if let Some(chunk) = self
+ .cell_manager
+ .chunk_position_to_chunk_idx
+ .get(&(cx, cy))
+ .map(|&idx| &self.cell_manager.chunks[idx])
+ && !chunk.sleeping
+ {
+ self.rb_manager.upsert_chunk_collider(cx, cy, chunk);
+ }
+ }
+ }
+
+ // move the rbs
+ self.rb_manager.tick(delta_time);
+
+ // move the particles
+ self.particle_manager
+ .tick(&mut self.cell_manager, delta_time);
+ }
+
+ pub fn update(&mut self, config: &Config, _delta_time: f32) -> () {
+ let now = Instant::now();
+ let secs_since_last_cell_update = (now - self.last_cell_update).as_secs_f32();
+ let expected_secs_since_last_cell_update = 1.0 / SIM_FPS as f32;
+
+ self.last_cell_update = now;
+ if self.paused && self.ignore_pause_next_tick {
+ self.cell_update(config);
+ } else if !self.paused {
+ self.cell_updates_due +=
+ secs_since_last_cell_update / expected_secs_since_last_cell_update;
+ let mut cell_updates_done = 0;
+ // don't ever update more than 3 times per frame, or else we can get a pseudo deadlock
+ while self.cell_updates_due >= 1.0 && cell_updates_done < 3 {
+ self.cell_update(config);
+ self.cell_updates_due -= 1.0;
+ cell_updates_done += 1;
+ }
+ self.cell_updates_due = self.cell_updates_due.min(3.0);
+ }
+
+ // PHYSICS UPDATE
+ let secs_since_last_physics_update = (now - self.last_physics_update).as_secs_f32();
+ let expected_secs_since_last_physics_update = 1.0 / PHYSICS_FPS as f32;
+
+ self.last_physics_update = now;
+ if self.paused && self.ignore_pause_next_tick {
+ self.physics_update(PHYSICS_DELTA_TIME);
+ } else if !self.paused {
+ self.physics_updates_due +=
+ secs_since_last_physics_update / expected_secs_since_last_physics_update;
+ let mut updates_done = 0;
+ // don't ever update more than 3 times per frame, or else we can get a pseudo deadlock
+ while self.physics_updates_due >= 1.0 && updates_done < 3 {
+ self.physics_update(PHYSICS_DELTA_TIME);
+ self.physics_updates_due -= 1.0;
+ updates_done += 1;
+ }
+ self.physics_updates_due = self.physics_updates_due.min(3.0);
+ }
+
+ self.ignore_pause_next_tick = false;
+ }
+}
diff --git a/src/sim/sim_manager/utils.rs b/src/sim/sim_manager/utils.rs
new file mode 100644
index 0000000..b636186
--- /dev/null
+++ b/src/sim/sim_manager/utils.rs
@@ -0,0 +1,62 @@
+use crate::sim::{cell::materials::MaterialId, sim_manager::SimManager};
+
+pub fn write_rb_entity_to_world(
+ sim: &mut SimManager,
+ rb_entity_id: u32,
+ // make sure these cells will be simulated
+ seqno: u64,
+ // (entity_x, entity_y, cell_x, cell_y)
+) -> Vec<(u8, u8, i32, i32)> {
+ let mut cells_written: Vec<(u8, u8, i32, i32)> = Vec::new();
+ if let Some(rb_entity) = sim.rb_manager.rb_entities.get(&rb_entity_id)
+ && let Some((rb_x, rb_y, cos, sin)) = sim.rb_manager.get_rb_entity_transform(rb_entity_id)
+ {
+ let (half_size_x, half_size_y) =
+ (rb_entity.width as f32 / 2.0, rb_entity.height as f32 / 2.0);
+ // half-extent of the rotated grid's axis-aligned bounding box, plus a cell of margin
+ let (radius_x, radius_y) = (
+ half_size_x * (cos.abs() + sin.abs()) + 1.0,
+ half_size_y * (cos.abs() + sin.abs()) + 1.0,
+ );
+
+ let world_xl = (rb_x - radius_x).floor() as i32;
+ let world_xu = (rb_x + radius_x).ceil() as i32;
+ let world_yl = (rb_y - radius_y).floor() as i32;
+ let world_yu = (rb_y + radius_y).ceil() as i32;
+
+ for world_x in world_xl..=world_xu {
+ for world_y in world_yl..=world_yu {
+ if let Some(cur_world_cell) = sim
+ .cell_manager
+ .get_cell_from_game_position(world_x, world_y)
+ && cur_world_cell.material == MaterialId::Void
+ {
+ // same as shader
+ let d = (world_x as f32 + 0.5 - rb_x, world_y as f32 + 0.5 - rb_y);
+ let q = (d.0.floor() + 0.5, d.1.floor() + 0.5);
+ let (lx, ly) = (
+ (q.0 * cos + q.1 * sin + half_size_x).floor() as i32,
+ (-q.0 * sin + q.1 * cos + half_size_y).floor() as i32,
+ );
+
+ if lx < 0 || ly < 0 || lx >= rb_entity.width || ly >= rb_entity.height {
+ continue;
+ }
+
+ let mut cell = rb_entity.get_cell_at_local_position(lx as u8, ly as u8);
+ if cell.material == MaterialId::Void {
+ continue;
+ }
+
+ cell.match_parity(seqno);
+
+ // TODO: OPTIMIZE!!
+ sim.cell_manager
+ .set_cell_from_game_position(world_x, world_y, cell, false);
+ cells_written.push((lx as u8, ly as u8, world_x, world_y));
+ }
+ }
+ }
+ }
+ cells_written
+}