summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/content/entities/entity_cube.rs2
-rw-r--r--src/content/entities/entity_grenade.rs9
-rw-r--r--src/sim/cell/cell.rs17
-rw-r--r--src/sim/entity/mod.rs56
-rw-r--r--src/sim/sim_manager/mod.rs61
5 files changed, 84 insertions, 61 deletions
diff --git a/src/content/entities/entity_cube.rs b/src/content/entities/entity_cube.rs
index ab93e5e..fb5bbd0 100644
--- a/src/content/entities/entity_cube.rs
+++ b/src/content/entities/entity_cube.rs
@@ -17,7 +17,7 @@ pub fn entity_cube_def(position: Vec2, material: MaterialId) -> EntityDef {
for y in 0..h {
let cell_idx = x + y * w;
raw_cells[cell_idx as usize] = Cell::from_material(material);
- raw_cells[cell_idx as usize].set_entity(true);
+ raw_cells[cell_idx as usize].set_entity_integrated(true);
}
}
diff --git a/src/content/entities/entity_grenade.rs b/src/content/entities/entity_grenade.rs
index c13c239..f6c82e8 100644
--- a/src/content/entities/entity_grenade.rs
+++ b/src/content/entities/entity_grenade.rs
@@ -15,12 +15,7 @@ struct GrenadeEntityBehaviour {
}
impl EntityBehaviour for GrenadeEntityBehaviour {
- fn update(
- &mut self,
- update_ctx: &mut EntityUpdateCtx,
- ctx: &mut SimCtx,
- delta_time: f32,
- ) {
+ fn update(&mut self, update_ctx: &mut EntityUpdateCtx, ctx: &mut SimCtx, delta_time: f32) {
self.fuse -= delta_time;
if self.fuse <= 0.0 {
apply_explosion(
@@ -44,7 +39,7 @@ pub fn entity_grenade_def(position: Vec2, fuse: f32) -> EntityDef {
for y in 0..h {
let cell_idx = x + y * w;
raw_cells[cell_idx as usize] = Cell::from_material(MaterialId::Steel);
- raw_cells[cell_idx as usize].set_entity(true);
+ raw_cells[cell_idx as usize].set_entity_integrated(true);
}
}
diff --git a/src/sim/cell/cell.rs b/src/sim/cell/cell.rs
index be2cfad..5a9fc1f 100644
--- a/src/sim/cell/cell.rs
+++ b/src/sim/cell/cell.rs
@@ -8,8 +8,11 @@ pub struct Cell {
}
impl Cell {
+ // only update the cell if this matches the parity of the seqno
const FLAG_PARITY: u8 = 0b0000_0001;
- const FLAG_ENTITY: u8 = 0b0000_0010;
+ // 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]
@@ -31,15 +34,15 @@ impl Cell {
}
#[inline]
- pub fn entity(self) -> bool {
- (self.flags & Self::FLAG_ENTITY) == Self::FLAG_ENTITY
+ pub fn entity_integrated(self) -> bool {
+ (self.flags & Self::FLAG_ENTITY_INTEGRATED) == Self::FLAG_ENTITY_INTEGRATED
}
#[inline]
- pub fn set_entity(&mut self, rb: bool) {
- if rb {
- self.flags |= Self::FLAG_ENTITY
+ 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
+ self.flags &= !Self::FLAG_ENTITY_INTEGRATED
}
}
diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs
index d8a03e0..3a3fb1d 100644
--- a/src/sim/entity/mod.rs
+++ b/src/sim/entity/mod.rs
@@ -13,6 +13,13 @@ use crate::{
},
};
+fn mass_from_cells(cells: &[Cell]) -> f32 {
+ cells
+ .iter()
+ .fold(0, |acc, cur| acc + cur.material.def().density) as f32
+ * MASS_SCALING
+}
+
pub struct EntityCells {
pub size: IVec2,
pub cells: Vec<Cell>,
@@ -43,13 +50,7 @@ impl Marchable for EntityCells {
}
pub trait EntityBehaviour {
- fn update(
- &mut self,
- _update_ctx: &mut EntityUpdateCtx,
- _ctx: &mut SimCtx,
- _delta_time: f32,
- ) {
- }
+ fn update(&mut self, _update_ctx: &mut EntityUpdateCtx, _ctx: &mut SimCtx, _delta_time: f32) {}
fn physics_update(
&mut self,
_update_ctx: &mut EntityUpdateCtx,
@@ -76,14 +77,8 @@ impl EntityDef {
.translation(position / CELLS_TO_METRES)
.build();
- let mass = cells
- .cells
- .iter()
- .fold(0, |acc, cur| acc + cur.material.def().density) as f32
- * MASS_SCALING;
-
let collider = RbManager::convex_hull_collider_from_marchable(&cells, None)
- .mass(mass)
+ .mass(mass_from_cells(&cells.cells))
.build();
EntityDef {
@@ -130,19 +125,18 @@ impl<'a> EntityUpdateCtx<'a> {
impl EntityData {
pub fn transform(&self, ctx: &SimCtx) -> Option<(Vec2, (f32, f32))> {
- self.rb_h
- .and_then(|rb_h| {
- ctx.rb_manager
- .physics_manager
- .rigid_body_set
- .get(rb_h)
- .map(|rb| {
- (
- rb.translation() * CELLS_TO_METRES,
- (rb.rotation().cos(), rb.rotation().sin()),
- )
- })
- })
+ self.rb_h.and_then(|rb_h| {
+ ctx.rb_manager
+ .physics_manager
+ .rigid_body_set
+ .get(rb_h)
+ .map(|rb| {
+ (
+ rb.translation() * CELLS_TO_METRES,
+ (rb.rotation().cos(), rb.rotation().sin()),
+ )
+ })
+ })
}
}
@@ -174,6 +168,14 @@ impl Entity {
None
}
+ pub fn compute_collider(&self) -> Option<Collider> {
+ self.data.cells.as_ref().map(|cells| {
+ RbManager::convex_hull_collider_from_marchable(cells, None)
+ .mass(mass_from_cells(&cells.cells))
+ .build()
+ })
+ }
+
pub fn new(
id: u32,
rb_h: Option<RigidBodyHandle>,
diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs
index 805d152..1a16cfd 100644
--- a/src/sim/sim_manager/mod.rs
+++ b/src/sim/sim_manager/mod.rs
@@ -6,7 +6,6 @@ use glam::IVec2;
use crate::{
Config,
config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS},
- content::materials::MaterialId,
sim::{
cell::cell::Cell,
cell_manager::manager::CellManager,
@@ -130,28 +129,51 @@ impl SimManager {
// 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 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.entity() {
- panic!(
- "Someone swapped into this entity's cell! ({x}, {y}, {m:#?}, {f})",
- m = new_local_cell.material,
- f = new_local_cell.flags
- );
- }
- if let Some(cells) = &mut entity.data.cells {
- cells.set_cell_at_local_position(
- IVec2::new(lx as i32, ly as i32),
- new_local_cell,
- );
+ 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);
}
+
+ 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,
+ );
+
+ 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);
+ }
+ }
}
}
@@ -165,15 +187,16 @@ impl SimManager {
particle_manager: &mut self.particle_manager,
};
if let Some(entity) = entity
- && let Some(result) = entity.physics_update(&mut ctx, delta_time) {
- for d in result.deferred_destructions {
- self.destroy_entity(d);
- }
+ && let Some(result) = entity.physics_update(&mut ctx, delta_time)
+ {
+ for d in result.deferred_destructions {
+ self.destroy_entity(d);
}
+ }
}
// before we move the rigidbodies, upsert the current terrain state
- // TODO use the chunk sleeping, and make this range dynamic
+ // TODO make this range dynamic
for cx in -5..5 {
for cy in -5..5 {
if let Some(chunk) = self