From 80824a8b69b70e6e40577e4f0236c28c4ad5c15b Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Sun, 23 Aug 2026 02:48:43 -0700 Subject: explosions affect rigidbodies, use "world" for rapier --- src/content/entities/entity_cube.rs | 2 +- src/content/entities/entity_grenade.rs | 2 +- src/content/materials/fire.rs | 2 +- src/main.rs | 34 ++++--- src/sim/cell.rs | 87 ++++++++++++++++++ src/sim/cell/cell.rs | 87 ------------------ src/sim/cell/mod.rs | 1 - src/sim/cell_manager/chunk.rs | 2 +- src/sim/cell_manager/manager.rs | 2 +- src/sim/cell_manager/sim.rs | 2 +- src/sim/entity/mod.rs | 10 +-- src/sim/lib/force.rs | 79 ++++++++++++++++- src/sim/particle_manager/mod.rs | 10 ++- src/sim/particle_manager/particle.rs | 10 ++- src/sim/rb_manager/mod.rs | 83 ++++++----------- src/sim/sim_manager/mod.rs | 157 +++++++++++++++------------------ 16 files changed, 309 insertions(+), 261 deletions(-) create mode 100644 src/sim/cell.rs delete mode 100644 src/sim/cell/cell.rs delete mode 100644 src/sim/cell/mod.rs (limited to 'src') diff --git a/src/content/entities/entity_cube.rs b/src/content/entities/entity_cube.rs index fb5bbd0..dbbd93e 100644 --- a/src/content/entities/entity_cube.rs +++ b/src/content/entities/entity_cube.rs @@ -3,7 +3,7 @@ use glam::{IVec2, Vec2}; use crate::{ content::materials::MaterialId, sim::{ - cell::cell::Cell, + cell::Cell, entity::{EntityCells, EntityDef}, }, }; diff --git a/src/content/entities/entity_grenade.rs b/src/content/entities/entity_grenade.rs index f6c82e8..5c180b4 100644 --- a/src/content/entities/entity_grenade.rs +++ b/src/content/entities/entity_grenade.rs @@ -3,7 +3,7 @@ use glam::{IVec2, Vec2}; use crate::{ content::materials::MaterialId, sim::{ - cell::cell::Cell, + cell::Cell, entity::{EntityBehaviour, EntityCells, EntityDef, EntityUpdateCtx}, lib::force::apply_explosion, sim_manager::SimCtx, diff --git a/src/content/materials/fire.rs b/src/content/materials/fire.rs index 483afbc..2e5ef2f 100644 --- a/src/content/materials/fire.rs +++ b/src/content/materials/fire.rs @@ -3,7 +3,7 @@ use rand::RngExt; use crate::{ content::materials::MaterialId, sim::{ - cell::cell::Cell, + cell::Cell, cell_manager::sim::{PostUpdateAction, UpdateCtx}, }, }; diff --git a/src/main.rs b/src/main.rs index 492f0ba..7620f92 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,10 +28,9 @@ use crate::{ }, renderer::RendererState, sim::{ - cell::cell::Cell, + cell::Cell, cell_manager::manager::CellManager, - lib::force::apply_explosion, - particle_manager::particle::Particle, + lib::force::{apply_bullet, apply_explosion}, rb_manager::DebugRenderMode, sim_manager::{SimCtx, SimManager}, }, @@ -80,6 +79,9 @@ struct App { window: Option>, renderer_state: Option, + // tests + bullet_origin: Option, + // game input: Input, camera: Option, @@ -125,16 +127,20 @@ impl App { && let Some(lm) = self.input.last_mouse_world_pos { self.input.trigger_test_3 = false; - for _ in 0..100 { - sim.particle_manager.particles.push(Particle { - position: Vec2::new( - lm.0 + random_range(-25.0..25.0), - lm.1 + random_range(-25.0..25.0), - ), - velocity: Vec2::ZERO, - material: MaterialId::Sand, - life: 2.0, - }) + if let Some(origin) = self.bullet_origin { + apply_bullet( + &mut SimCtx { + cell_manager: &mut sim.cell_manager, + particle_manager: &mut sim.particle_manager, + rb_manager: &mut sim.rb_manager, + }, + origin, + Vec2::new(lm.0, lm.1), + 800, + ); + self.bullet_origin = None; + } else { + self.bullet_origin = Some(Vec2::new(lm.0, lm.1)); } } @@ -202,6 +208,8 @@ impl Default for App { window: None, renderer_state: None, + bullet_origin: None, + input: Input { last_mouse_pos_on_screen: None, last_mouse_world_pos: None, diff --git a/src/sim/cell.rs b/src/sim/cell.rs new file mode 100644 index 0000000..5a9fc1f --- /dev/null +++ b/src/sim/cell.rs @@ -0,0 +1,87 @@ +use crate::{config::SETTLED_THRESOHLD, content::materials::MaterialId}; + +#[derive(Clone, Copy)] +pub struct Cell { + pub material: MaterialId, + pub flags: u8, + pub data: u16, +} + +impl Cell { + // only update the cell if this matches the parity of the seqno + const FLAG_PARITY: u8 = 0b0000_0001; + // is this cell owned by an entity? + const FLAG_ENTITY_INTEGRATED: u8 = 0b0000_0010; + // how close is the cell to settling? + const MASK_SETTLED: u8 = 0b0001_1100; + + #[inline] + pub fn parity(self) -> u8 { + self.flags & Self::FLAG_PARITY + } + #[inline] + pub fn flip_parity(&mut self) { + self.flags ^= Self::FLAG_PARITY; + } + #[inline] + pub fn match_parity(&mut self, seqno: u64) { + let parity = !seqno.is_multiple_of(2); + if parity { + self.flags |= Self::FLAG_PARITY; + } else { + self.flags &= !Self::FLAG_PARITY + } + } + + #[inline] + pub fn entity_integrated(self) -> bool { + (self.flags & Self::FLAG_ENTITY_INTEGRATED) == Self::FLAG_ENTITY_INTEGRATED + } + #[inline] + pub fn set_entity_integrated(&mut self, entity_integrated: bool) { + if entity_integrated { + self.flags |= Self::FLAG_ENTITY_INTEGRATED + } else { + self.flags &= !Self::FLAG_ENTITY_INTEGRATED + } + } + + #[inline] + pub fn settled(self) -> u8 { + (self.flags & Self::MASK_SETTLED) >> 2 + } + #[inline] + fn set_settled(&mut self, settled: u8) { + debug_assert!(settled <= 7); + self.flags = (settled << 2) | (self.flags & !Self::MASK_SETTLED); + } + #[inline] + pub fn reset_settled(&mut self) { + self.flags &= !Self::MASK_SETTLED; + } + + #[inline] + pub fn increment_settled(&mut self) { + let s = self.settled(); + if s < SETTLED_THRESOHLD { + self.set_settled(s + 1); + } + } +} + +impl Cell { + pub fn void() -> Cell { + Cell { + material: MaterialId::Void, + flags: 0, + data: 0, + } + } + pub fn from_material(material: MaterialId) -> Cell { + Cell { + material, + flags: 0, + data: 0, + } + } +} diff --git a/src/sim/cell/cell.rs b/src/sim/cell/cell.rs deleted file mode 100644 index 5a9fc1f..0000000 --- a/src/sim/cell/cell.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::{config::SETTLED_THRESOHLD, content::materials::MaterialId}; - -#[derive(Clone, Copy)] -pub struct Cell { - pub material: MaterialId, - pub flags: u8, - pub data: u16, -} - -impl Cell { - // only update the cell if this matches the parity of the seqno - const FLAG_PARITY: u8 = 0b0000_0001; - // is this cell owned by an entity? - const FLAG_ENTITY_INTEGRATED: u8 = 0b0000_0010; - // how close is the cell to settling? - const MASK_SETTLED: u8 = 0b0001_1100; - - #[inline] - pub fn parity(self) -> u8 { - self.flags & Self::FLAG_PARITY - } - #[inline] - pub fn flip_parity(&mut self) { - self.flags ^= Self::FLAG_PARITY; - } - #[inline] - pub fn match_parity(&mut self, seqno: u64) { - let parity = !seqno.is_multiple_of(2); - if parity { - self.flags |= Self::FLAG_PARITY; - } else { - self.flags &= !Self::FLAG_PARITY - } - } - - #[inline] - pub fn entity_integrated(self) -> bool { - (self.flags & Self::FLAG_ENTITY_INTEGRATED) == Self::FLAG_ENTITY_INTEGRATED - } - #[inline] - pub fn set_entity_integrated(&mut self, entity_integrated: bool) { - if entity_integrated { - self.flags |= Self::FLAG_ENTITY_INTEGRATED - } else { - self.flags &= !Self::FLAG_ENTITY_INTEGRATED - } - } - - #[inline] - pub fn settled(self) -> u8 { - (self.flags & Self::MASK_SETTLED) >> 2 - } - #[inline] - fn set_settled(&mut self, settled: u8) { - debug_assert!(settled <= 7); - self.flags = (settled << 2) | (self.flags & !Self::MASK_SETTLED); - } - #[inline] - pub fn reset_settled(&mut self) { - self.flags &= !Self::MASK_SETTLED; - } - - #[inline] - pub fn increment_settled(&mut self) { - let s = self.settled(); - if s < SETTLED_THRESOHLD { - self.set_settled(s + 1); - } - } -} - -impl Cell { - pub fn void() -> Cell { - Cell { - material: MaterialId::Void, - flags: 0, - data: 0, - } - } - pub fn from_material(material: MaterialId) -> Cell { - Cell { - material, - flags: 0, - data: 0, - } - } -} diff --git a/src/sim/cell/mod.rs b/src/sim/cell/mod.rs deleted file mode 100644 index 48433da..0000000 --- a/src/sim/cell/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod cell; diff --git a/src/sim/cell_manager/chunk.rs b/src/sim/cell_manager/chunk.rs index 29e6536..463242d 100644 --- a/src/sim/cell_manager/chunk.rs +++ b/src/sim/cell_manager/chunk.rs @@ -3,7 +3,7 @@ use glam::IVec2; use crate::{ config::{CELLS_IN_CHUNK, CHUNK_SIZE}, content::materials::MaterialForm, - sim::{cell::cell::Cell, lib::marching_squares::Marchable}, + sim::{cell::Cell, lib::marching_squares::Marchable}, }; pub struct Chunk { diff --git a/src/sim/cell_manager/manager.rs b/src/sim/cell_manager/manager.rs index 094f345..8706caa 100644 --- a/src/sim/cell_manager/manager.rs +++ b/src/sim/cell_manager/manager.rs @@ -3,7 +3,7 @@ use fxhash::FxHashMap; use crate::{ config::CHUNK_SIZE, sim::{ - cell::cell::Cell, + cell::Cell, cell_manager::{chunk::Chunk, sim::sim_tick}, }, }; diff --git a/src/sim/cell_manager/sim.rs b/src/sim/cell_manager/sim.rs index 0e67cad..ffa253b 100644 --- a/src/sim/cell_manager/sim.rs +++ b/src/sim/cell_manager/sim.rs @@ -8,7 +8,7 @@ use crate::{ config::{CHUNK_SIZE, SETTLED_THRESOHLD}, content::materials::MaterialDef, sim::{ - cell::cell::Cell, + cell::Cell, cell_manager::{chunk::Chunk, manager::CellManager}, }, }; diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs index 3a3fb1d..0d8ae71 100644 --- a/src/sim/entity/mod.rs +++ b/src/sim/entity/mod.rs @@ -8,8 +8,7 @@ use crate::{ config::{CELLS_TO_METRES, MASS_SCALING}, content::materials::MaterialId, sim::{ - cell::cell::Cell, lib::marching_squares::Marchable, rb_manager::RbManager, - sim_manager::SimCtx, + cell::Cell, lib::marching_squares::Marchable, rb_manager::RbManager, sim_manager::SimCtx, }, }; @@ -77,7 +76,7 @@ impl EntityDef { .translation(position / CELLS_TO_METRES) .build(); - let collider = RbManager::convex_hull_collider_from_marchable(&cells, None) + let collider = RbManager::convex_hull_collider_from_marchable(&cells, Some(10)) .mass(mass_from_cells(&cells.cells)) .build(); @@ -128,7 +127,8 @@ impl EntityData { self.rb_h.and_then(|rb_h| { ctx.rb_manager .physics_manager - .rigid_body_set + .world + .bodies .get(rb_h) .map(|rb| { ( @@ -170,7 +170,7 @@ impl Entity { pub fn compute_collider(&self) -> Option { self.data.cells.as_ref().map(|cells| { - RbManager::convex_hull_collider_from_marchable(cells, None) + RbManager::convex_hull_collider_from_marchable(cells, Some(10)) .mass(mass_from_cells(&cells.cells)) .build() }) diff --git a/src/sim/lib/force.rs b/src/sim/lib/force.rs index db8e076..e99817c 100644 --- a/src/sim/lib/force.rs +++ b/src/sim/lib/force.rs @@ -1,9 +1,11 @@ use glam::Vec2; use rand::random_range; +use rapier2d::{dynamics::RigidBodyHandle, parry::bounding_volume::Aabb, pipeline::QueryFilter}; use crate::{ + config::CELLS_TO_METRES, content::materials::{MaterialForm, MaterialId, fire::FireCellView}, - sim::{cell::cell::Cell, particle_manager::particle::Particle, sim_manager::SimCtx}, + sim::{cell::Cell, lib::ray::AwDda, particle_manager::particle::Particle, sim_manager::SimCtx}, }; pub fn apply_explosion( @@ -15,7 +17,7 @@ pub fn apply_explosion( ) { let get_vel = |pos: Vec2| { let d = pos.distance(centre); - if d < 0.001 { + if d < 0.001 || d > radius as f32 { return Vec2::ZERO; } let dir = (pos - centre) / d; @@ -46,6 +48,7 @@ pub fn apply_explosion( vel, MaterialId::Fire, 1.0, + 0.0, )); } } else if [ @@ -64,6 +67,7 @@ pub fn apply_explosion( vel, cell.material, 5.0, + 0.0, )); } } @@ -73,4 +77,75 @@ pub fn apply_explosion( } // rigidbodies + let colliders = ctx + .rb_manager + .physics_manager + .world + .intersect_aabb_conservative( + Aabb::new( + (centre - radius as f32) / CELLS_TO_METRES, + (centre + radius as f32) / CELLS_TO_METRES, + ), + QueryFilter::only_dynamic(), + ); + + let body_handles: Vec> = colliders.map(|(_, c)| c.parent()).collect(); + + for h in body_handles { + if let Some(h) = h + && let Some(body) = ctx.rb_manager.physics_manager.world.bodies.get_mut(h) + { + // magic divisor number for good vibes + body.apply_impulse(get_vel(body.translation() * CELLS_TO_METRES) / 3.0, true); + } + } +} + +// TODO profile packing entity ID into cells? +// might improve performance by a lot if we don't have to raycast for hit entities +pub fn apply_bullet(ctx: &mut SimCtx, from: Vec2, to: Vec2, power: u32) { + let dda = AwDda::new(from, to); + let mut p = power as i32; + + let dir = (to - from).normalize(); + + for collision in dda { + if let Some(cell) = ctx + .cell_manager + .get_cell_from_game_position(collision.x, collision.y) + { + let m = cell.material.def(); + if ![ + MaterialForm::Solid, + MaterialForm::Powder, + MaterialForm::Liquid, + ] + .contains(&m.form) + { + continue; + } + + p -= m.density as i32; + if p <= 0 { + break; + } + + ctx.cell_manager.set_cell_from_game_position( + collision.x, + collision.y, + Cell::void(), + false, + ); + + if random_range(0.0..1.0) > 0.8 { + ctx.particle_manager.particles.push(Particle::new( + collision.as_vec2(), + (dir + Vec2::new(random_range(-0.15..0.15), random_range(-0.15..0.15))) * 150.0, + cell.material, + 5.0, + 0.2, + )); + } + } + } } diff --git a/src/sim/particle_manager/mod.rs b/src/sim/particle_manager/mod.rs index 052369b..559bf2c 100644 --- a/src/sim/particle_manager/mod.rs +++ b/src/sim/particle_manager/mod.rs @@ -2,7 +2,7 @@ use crate::{ config::CELLS_TO_METRES, content::materials::MaterialForm, sim::{ - cell::cell::Cell, cell_manager::manager::CellManager, lib::ray::AwDda, + cell::Cell, cell_manager::manager::CellManager, lib::ray::AwDda, particle_manager::particle::Particle, }, }; @@ -23,6 +23,7 @@ impl ParticleManager { let p = &mut self.particles[i]; p.life -= delta_time; + p.collision_grace -= delta_time; if p.life <= 0.0 { self.particles.swap_remove(i); continue 'outer; @@ -31,6 +32,13 @@ impl ParticleManager { p.velocity.y += PARTICLE_GRAVITY * delta_time; let dt_velocity = p.velocity * delta_time; + if p.collision_grace > 0.0 { + p.position += dt_velocity; + i += 1; + continue 'outer; + } + + // compute collisions let mut dda = AwDda::new(p.position, p.position + dt_velocity); if let Some(mut prev) = dda.next() { diff --git a/src/sim/particle_manager/particle.rs b/src/sim/particle_manager/particle.rs index c68d81e..279eacb 100644 --- a/src/sim/particle_manager/particle.rs +++ b/src/sim/particle_manager/particle.rs @@ -7,15 +7,23 @@ pub struct Particle { pub velocity: Vec2, pub material: MaterialId, pub life: f32, + pub collision_grace: f32, } impl Particle { - pub fn new(position: Vec2, velocity: Vec2, material: MaterialId, life: f32) -> Self { + pub fn new( + position: Vec2, + velocity: Vec2, + material: MaterialId, + life: f32, + collision_grace: f32, + ) -> Self { Particle { position, velocity, material, life, + collision_grace, } } } diff --git a/src/sim/rb_manager/mod.rs b/src/sim/rb_manager/mod.rs index a70c677..2d95eb7 100644 --- a/src/sim/rb_manager/mod.rs +++ b/src/sim/rb_manager/mod.rs @@ -2,7 +2,13 @@ pub mod debug_render; use fxhash::FxHashMap; use glam::Vec2; -use rapier2d::{geometry, glamx::vec2, prelude}; +use rapier2d::{ + dynamics::IntegrationParameters, + geometry, + glamx::vec2, + pipeline::{DebugRenderPipeline, PhysicsWorld}, + prelude, +}; use crate::{ config::{CELLS_TO_METRES, CHUNK_SIZE, PHYSICS_DELTA_TIME}, @@ -16,37 +22,23 @@ use crate::{ pub use rapier2d::pipeline::DebugRenderMode; pub struct PhysicsManager { - pub rigid_body_set: prelude::RigidBodySet, - pub collider_set: prelude::ColliderSet, - pub physics_pipeline: prelude::PhysicsPipeline, - pub integration_parameters: prelude::IntegrationParameters, - pub island_manager: prelude::IslandManager, - pub broad_phase: prelude::DefaultBroadPhase, - pub narrow_phase: prelude::NarrowPhase, - pub impulse_joint_set: prelude::ImpulseJointSet, - pub multibody_joint_set: prelude::MultibodyJointSet, - pub ccd_solver: prelude::CCDSolver, - pub debug_render_pipeline: prelude::DebugRenderPipeline, + pub world: PhysicsWorld, + pub debug_render_pipeline: DebugRenderPipeline, } impl PhysicsManager { pub fn new() -> Self { + let mut world = PhysicsWorld::new(); + let gravity = vec2(0.0, 9.81); + world.gravity = gravity; + world.integration_parameters = IntegrationParameters { + // 20 pixels <-> 1 meter + length_unit: CELLS_TO_METRES, + dt: PHYSICS_DELTA_TIME, + ..prelude::IntegrationParameters::default() + }; PhysicsManager { - rigid_body_set: prelude::RigidBodySet::new(), - collider_set: prelude::ColliderSet::new(), - physics_pipeline: prelude::PhysicsPipeline::new(), - integration_parameters: prelude::IntegrationParameters { - // 20 pixels <-> 1 meter - length_unit: CELLS_TO_METRES, - dt: PHYSICS_DELTA_TIME, - ..prelude::IntegrationParameters::default() - }, - island_manager: prelude::IslandManager::new(), - broad_phase: prelude::DefaultBroadPhase::new(), - narrow_phase: prelude::NarrowPhase::new(), - impulse_joint_set: prelude::ImpulseJointSet::new(), - multibody_joint_set: prelude::MultibodyJointSet::new(), - ccd_solver: prelude::CCDSolver::new(), + world, debug_render_pipeline: prelude::DebugRenderPipeline::new( prelude::DebugRenderStyle { sleep_color_multiplier: [1.0; 4], @@ -70,37 +62,17 @@ pub struct RbManager { impl RbManager { pub fn tick(&mut self, _delta_time: f32) { - let gravity = vec2(0.0, 9.81); - - self.physics_manager.physics_pipeline.step( - gravity, - &self.physics_manager.integration_parameters, - &mut self.physics_manager.island_manager, - &mut self.physics_manager.broad_phase, - &mut self.physics_manager.narrow_phase, - &mut self.physics_manager.rigid_body_set, - &mut self.physics_manager.collider_set, - &mut self.physics_manager.impulse_joint_set, - &mut self.physics_manager.multibody_joint_set, - &mut self.physics_manager.ccd_solver, - &(), - &(), - ); + self.physics_manager.world.step(); } pub fn debug_render(&mut self, mode: DebugRenderMode) -> &[DebugVertex] { puffin::profile_function!(); - let physics = &mut self.physics_manager; self.debug_line_buffer.vertices.clear(); - physics.debug_render_pipeline.mode = mode; - physics.debug_render_pipeline.render( + self.physics_manager.debug_render_pipeline.mode = mode; + self.physics_manager.world.debug_render( + &mut self.physics_manager.debug_render_pipeline, &mut self.debug_line_buffer, - &physics.rigid_body_set, - &physics.collider_set, - &physics.impulse_joint_set, - &physics.multibody_joint_set, - &physics.narrow_phase, ); &self.debug_line_buffer.vertices @@ -160,15 +132,10 @@ impl RbManager { ); if let Some(handle) = self.chunk_colliders.remove(&(cx, cy)) { - self.physics_manager.collider_set.remove( - handle, - &mut self.physics_manager.island_manager, - &mut self.physics_manager.rigid_body_set, - false, - ); + self.physics_manager.world.remove_collider(handle); } - let handle = self.physics_manager.collider_set.insert(collider); + let handle = self.physics_manager.world.insert_collider(collider, None); self.chunk_colliders.insert((cx, cy), handle); } diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs index 1a16cfd..855b398 100644 --- a/src/sim/sim_manager/mod.rs +++ b/src/sim/sim_manager/mod.rs @@ -7,7 +7,7 @@ use crate::{ Config, config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS}, sim::{ - cell::cell::Cell, + cell::Cell, cell_manager::manager::CellManager, entity::{Entity, EntityDef}, particle_manager::ParticleManager, @@ -47,18 +47,14 @@ pub struct SimCtx<'a> { impl SimManager { pub fn create_entity(&mut self, def: EntityDef) -> u32 { let (rb_h, collider_h) = if let Some(rb) = def.rb { - let rb_h = self.rb_manager.physics_manager.rigid_body_set.insert(rb); + let rb_h = self.rb_manager.physics_manager.world.insert_body(rb); if let Some(collider) = def.collider { let collider_h = self .rb_manager .physics_manager - .collider_set - .insert_with_parent( - collider, - rb_h, - &mut self.rb_manager.physics_manager.rigid_body_set, - ); + .world + .insert_collider(collider, Some(rb_h)); (Some(rb_h), Some(collider_h)) } else { (Some(rb_h), None) @@ -67,8 +63,8 @@ impl SimManager { let collider_h = self .rb_manager .physics_manager - .collider_set - .insert(collider); + .world + .insert_collider(collider, None); (None, Some(collider_h)) } else { (None, None) @@ -91,28 +87,19 @@ impl SimManager { pub fn destroy_entity(&mut self, id: u32) { if let Some(entity) = self.entities.get(&id) { if let Some(rb_h) = entity.data.rb_h { - self.rb_manager.physics_manager.rigid_body_set.remove( - rb_h, - &mut self.rb_manager.physics_manager.island_manager, - &mut self.rb_manager.physics_manager.collider_set, - &mut self.rb_manager.physics_manager.impulse_joint_set, - &mut self.rb_manager.physics_manager.multibody_joint_set, - true, - ); + self.rb_manager.physics_manager.world.remove_body(rb_h); } else if let Some(collider_h) = entity.data.collider_h { - self.rb_manager.physics_manager.collider_set.remove( - collider_h, - &mut self.rb_manager.physics_manager.island_manager, - &mut self.rb_manager.physics_manager.rigid_body_set, - true, - ); + self.rb_manager + .physics_manager + .world + .remove_collider(collider_h); } self.entities.remove(&id); } } - fn cell_update(&mut self, config: &Config) { + fn cell_update(&mut self, config: &Config, delta_time: f32) { // before we tick, write all the entities into the sim world // TODO optimize let entity_ids: Vec = self.entities.keys().copied().collect(); @@ -125,53 +112,68 @@ impl SimManager { self.cell_manager.tick(config.use_threading); + let entity_ids: Vec = self.entities.keys().cloned().collect(); + for id in entity_ids { + let entity = self.entities.get_mut(&id); + let mut ctx = SimCtx { + cell_manager: &mut self.cell_manager, + rb_manager: &mut self.rb_manager, + particle_manager: &mut self.particle_manager, + }; + if let Some(entity) = entity + && let Some(result) = entity.update(&mut ctx, delta_time) + { + for d in result.deferred_destructions { + self.destroy_entity(d); + } + } + } + // after we tick, remove the written entity cells and update the entities // TODO optimize for (entity_id, cells_written) in cells_written_by_entity { - let entity = self.entities.get_mut(&entity_id).unwrap(); - let entity_cells = entity.data.cells.as_mut().unwrap(); - let mut should_update_entity = false; - - for (lx, ly, x, y) in cells_written { - // update the entity - // TODO optimize - let new_local_cell = self.cell_manager.get_cell_from_game_position(x, y).unwrap(); - if !new_local_cell.entity_integrated() { - // this means that the entity changed in some way, so we should recompute its shape - // TODO wait N frames to debounce this - should_update_entity = true; + if let Some(entity) = self.entities.get_mut(&entity_id) { + let entity_cells = entity.data.cells.as_mut().unwrap(); + let mut should_update_entity = false; + + for (lx, ly, x, y) in cells_written { + // update the entity + // TODO optimize + let new_local_cell = + self.cell_manager.get_cell_from_game_position(x, y).unwrap(); + if !new_local_cell.entity_integrated() { + // this means that the entity changed in some way, so we should recompute its shape + // TODO wait N frames to debounce this + should_update_entity = true; + } + // we do this unconditionally because it's cheaper than checking if it actually needs to be updated + // and because we don't have a good way to track changes to cell state + entity_cells.set_cell_at_local_position( + IVec2::new(lx as i32, ly as i32), + new_local_cell, + ); + + // update the world + // TODO optimize + self.cell_manager + .set_cell_from_game_position(x, y, Cell::void(), false); } - // we do this unconditionally because it's cheaper than checking if it actually needs to be updated - // and because we don't have a good way to track changes to cell state - entity_cells - .set_cell_at_local_position(IVec2::new(lx as i32, ly as i32), new_local_cell); - - // update the world - // TODO optimize - self.cell_manager - .set_cell_from_game_position(x, y, Cell::void(), false); - } - if should_update_entity { - if let Some(new_collider) = entity.compute_collider() { - self.rb_manager.physics_manager.collider_set.remove( - entity.data.collider_h.unwrap(), - &mut self.rb_manager.physics_manager.island_manager, - &mut self.rb_manager.physics_manager.rigid_body_set, - true, - ); + if should_update_entity { + if let Some(new_collider) = entity.compute_collider() { + self.rb_manager + .physics_manager + .world + .remove_collider(entity.data.collider_h.unwrap()); - let new_handle = self - .rb_manager - .physics_manager - .collider_set - .insert_with_parent( - new_collider, - entity.data.rb_h.unwrap(), - &mut self.rb_manager.physics_manager.rigid_body_set, - ); - - entity.data.collider_h = Some(new_handle); + let new_handle = self + .rb_manager + .physics_manager + .world + .insert_collider(new_collider, Some(entity.data.rb_h.unwrap())); + + entity.data.collider_h = Some(new_handle); + } } } } @@ -194,7 +196,6 @@ impl SimManager { } } } - // before we move the rigidbodies, upsert the current terrain state // TODO make this range dynamic for cx in -5..5 { @@ -220,38 +221,20 @@ impl SimManager { } pub fn update(&mut self, config: &Config, delta_time: f32) { - let entity_ids: Vec = self.entities.keys().cloned().collect(); - for id in entity_ids { - if let Some(entity) = self.entities.get_mut(&id) { - let mut ctx = SimCtx { - cell_manager: &mut self.cell_manager, - rb_manager: &mut self.rb_manager, - particle_manager: &mut self.particle_manager, - }; - - entity.update(&mut ctx, delta_time); - if let Some(result) = entity.update(&mut ctx, delta_time) { - for d in result.deferred_destructions { - self.destroy_entity(d); - } - } - } - } - 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); + self.cell_update(config, delta_time); } 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_update(config, delta_time); self.cell_updates_due -= 1.0; cell_updates_done += 1; } -- cgit v1.3.1