diff options
| -rw-r--r-- | src/main.rs | 23 | ||||
| -rw-r--r-- | src/renderer/mod.rs | 19 | ||||
| -rw-r--r-- | src/sim/entity/entities/entity_grenade.rs | 64 | ||||
| -rw-r--r-- | src/sim/entity/entities/mod.rs | 1 | ||||
| -rw-r--r-- | src/sim/entity/mod.rs | 85 | ||||
| -rw-r--r-- | src/sim/lib/force.rs | 16 | ||||
| -rw-r--r-- | src/sim/sim_manager/mod.rs | 49 | ||||
| -rw-r--r-- | src/sim/sim_manager/utils.rs | 8 |
8 files changed, 222 insertions, 43 deletions
diff --git a/src/main.rs b/src/main.rs index 372ef4e..adb723c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,11 +25,11 @@ use crate::{ sim::{ cell::{cell::Cell, materials::MaterialId}, cell_manager::manager::CellManager, - entity::entities::entity_cube::entity_cube_def, + entity::entities::{entity_cube::entity_cube_def, entity_grenade::entity_grenade_def}, lib::force::apply_explosion, particle_manager::particle::Particle, rb_manager::DebugRenderMode, - sim_manager::SimManager, + sim_manager::{SimCtx, SimManager}, }, }; @@ -110,6 +110,13 @@ impl App { )); } + if self.input.trigger_test_2 + && let Some(lm) = self.input.last_mouse_world_pos + { + self.input.trigger_test_2 = false; + sim.create_entity(entity_grenade_def(Vec2::new(lm.0, lm.1), 3.0)); + } + if self.input.trigger_test_3 && let Some(lm) = self.input.last_mouse_world_pos { @@ -132,7 +139,17 @@ impl App { { let mouse = Vec2::new(lm.0, lm.1); self.input.trigger_test_4 = false; - apply_explosion(sim, mouse, 30, Vec2::new(0.0, -0.6), 300.0); + apply_explosion( + &mut SimCtx { + cell_manager: &mut sim.cell_manager, + particle_manager: &mut sim.particle_manager, + rb_manager: &mut sim.rb_manager, + }, + mouse, + 30, + Vec2::new(0.0, -0.6), + 300.0, + ); } // --TEST DRAWING-- diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 291b6d4..2df15e6 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -11,8 +11,11 @@ use crate::{ config::{CELLS_IN_CHUNK, CHUNK_SIZE}, renderer::ui::draw_egui, sim::{ - cell::materials::MaterialId, cell_manager::manager::CellManager, entity::Entity, - rb_manager::debug_render::DebugVertex, sim_manager::SimManager, + cell::materials::MaterialId, + cell_manager::manager::CellManager, + entity::Entity, + rb_manager::debug_render::DebugVertex, + sim_manager::{SimCtx, SimManager}, }, }; @@ -692,7 +695,7 @@ impl RendererState { self.renderer_rb_entities.drain(); for entity in sim.entities.values() { // TODO add "needs texture update"? - if let Some(cells) = &entity.cells { + if let Some(cells) = &entity.data.cells { for i in 0..cells.cells.len() { cell_buffer[i] = cells.cells[i].material as u8; } @@ -700,7 +703,7 @@ impl RendererState { let next_slot = CHUNK_SLOTS + self.renderer_rb_entities.len(); let slot = *self .renderer_rb_entities - .entry(entity.id) + .entry(entity.data.id) .or_insert(next_slot); self.queue.write_buffer( @@ -743,8 +746,12 @@ impl RendererState { for (id, slot) in &self.renderer_rb_entities { if let Some(entity) = sim.entities.get(id) - && let Some(cells) = &entity.cells - && let Some((pos, (cos, sin))) = entity.transform(sim) + && let Some(cells) = &entity.data.cells + && let Some((pos, (cos, sin))) = entity.data.transform(&mut SimCtx { + cell_manager: &mut sim.cell_manager, + particle_manager: &mut sim.particle_manager, + rb_manager: &mut sim.rb_manager, + }) { instances.push(RendererInstance { centre: pos.to_array(), diff --git a/src/sim/entity/entities/entity_grenade.rs b/src/sim/entity/entities/entity_grenade.rs new file mode 100644 index 0000000..eead416 --- /dev/null +++ b/src/sim/entity/entities/entity_grenade.rs @@ -0,0 +1,64 @@ +use glam::{IVec2, Vec2}; + +use crate::sim::{ + cell::{cell::Cell, materials::MaterialId}, + entity::{EntityBehaviour, EntityCells, EntityDef, EntityUpdateCtx, SimCtx}, + lib::force::apply_explosion, +}; + +struct GrenadeEntityBehaviour { + pub fuse: f32, +} + +impl EntityBehaviour for GrenadeEntityBehaviour { + fn physics_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( + ctx, + update_ctx.entity_data.transform(ctx).unwrap().0, + 15, + Vec2::new(0.0, -0.6), + 200.0, + ); + update_ctx.deferred_destroy(update_ctx.entity_data.id); + } + } +} + +pub fn entity_grenade_def(position: Vec2, fuse: f32) -> EntityDef { + let w = 3; + let h = 3; + let mut raw_cells = vec![Cell::void(); (w * h) as usize]; + + for x in 0..w { + for y in 0..h { + let cell_idx = x + y * w; + raw_cells[cell_idx as usize] = Cell::from_material(MaterialId::Wood); + raw_cells[cell_idx as usize].set_entity(true); + } + } + + let entity_cells = EntityCells { + cells: raw_cells, + size: IVec2::new(w, h), + }; + + EntityDef::from_cells( + position, + entity_cells, + Some(Box::new(GrenadeEntityBehaviour { fuse })), + ) +} diff --git a/src/sim/entity/entities/mod.rs b/src/sim/entity/entities/mod.rs index 449b068..e78eb89 100644 --- a/src/sim/entity/entities/mod.rs +++ b/src/sim/entity/entities/mod.rs @@ -1 +1,2 @@ pub mod entity_cube; +pub mod entity_grenade; diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs index b648f1d..c6c350e 100644 --- a/src/sim/entity/mod.rs +++ b/src/sim/entity/mod.rs @@ -10,7 +10,7 @@ use crate::{ cell::{cell::Cell, materials::MaterialId}, lib::marching_squares::Marchable, rb_manager::RbManager, - sim_manager::SimManager, + sim_manager::SimCtx, }, }; @@ -46,12 +46,17 @@ impl Marchable for EntityCells { } pub trait EntityBehaviour { - fn update(&mut self, sim: &mut SimManager, delta_time: f32) -> (); - fn physics_update(&mut self, sim: &mut SimManager, 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, + ctx: &mut SimCtx, + delta_time: f32, + ) -> (); } pub struct EntityDef { - pub position: Vec2, pub rb: Option<RigidBody>, pub collider: Option<Collider>, pub cells: Option<EntityCells>, @@ -71,7 +76,6 @@ impl EntityDef { let collider = RbManager::convex_hull_collider_from_marchable(&cells, None).build(); EntityDef { - position, rb: Some(rb), collider: Some(collider), cells: Some(cells), @@ -80,19 +84,44 @@ impl EntityDef { } } -pub struct Entity { +pub struct EntityData { pub id: u32, pub rb_h: Option<RigidBodyHandle>, pub collider_h: Option<ColliderHandle>, pub cells: Option<EntityCells>, - behaviour: Option<Box<dyn EntityBehaviour>>, } -impl Entity { - pub fn transform(&self, sim: &SimManager) -> Option<(Vec2, (f32, f32))> { +pub struct EntityUpdateResult { + pub deferred_destructions: Vec<u32>, +} + +pub struct EntityUpdateCtx<'a> { + pub entity_data: &'a mut EntityData, + deferred_destructions: Vec<u32>, +} + +impl<'a> EntityUpdateCtx<'a> { + pub fn from_entity_data(entity_data: &'a mut EntityData) -> Self { + EntityUpdateCtx { + entity_data, + deferred_destructions: Vec::new(), + } + } + pub fn deferred_destroy(&mut self, entity_id: u32) { + self.deferred_destructions.push(entity_id); + } + pub fn to_result(self) -> EntityUpdateResult { + EntityUpdateResult { + deferred_destructions: self.deferred_destructions, + } + } +} + +impl EntityData { + pub fn transform(&self, ctx: &SimCtx) -> Option<(Vec2, (f32, f32))> { self.rb_h .map(|rb_h| { - sim.rb_manager + ctx.rb_manager .physics_manager .rigid_body_set .get(rb_h) @@ -105,20 +134,34 @@ impl Entity { }) .flatten() } +} - // TODO use drop? - pub fn destroy(&mut self, sim: &mut SimManager) -> () {} +pub struct Entity { + pub data: EntityData, + behaviour: Option<Box<dyn EntityBehaviour>>, +} - pub fn update(&mut self, sim: &mut SimManager, delta_time: f32) -> () { +impl Entity { + pub fn update(&mut self, ctx: &mut SimCtx, delta_time: f32) -> Option<EntityUpdateResult> { if let Some(behaviour) = &mut self.behaviour { - behaviour.update(sim, delta_time); + let mut ectx = EntityUpdateCtx::from_entity_data(&mut self.data); + behaviour.update(&mut ectx, ctx, delta_time); + return Some(ectx.to_result()); } + None } - pub fn physics_update(&mut self, sim: &mut SimManager, delta_time: f32) -> () { + pub fn physics_update( + &mut self, + ctx: &mut SimCtx, + delta_time: f32, + ) -> Option<EntityUpdateResult> { if let Some(behaviour) = &mut self.behaviour { - behaviour.physics_update(sim, delta_time); + let mut ectx = EntityUpdateCtx::from_entity_data(&mut self.data); + behaviour.physics_update(&mut ectx, ctx, delta_time); + return Some(ectx.to_result()); } + None } pub fn new( @@ -129,10 +172,12 @@ impl Entity { behaviour: Option<Box<dyn EntityBehaviour>>, ) -> Self { Entity { - id, - rb_h, - collider_h, - cells, + data: EntityData { + id, + rb_h, + collider_h, + cells, + }, behaviour, } } diff --git a/src/sim/lib/force.rs b/src/sim/lib/force.rs index e8f7e90..8acfa15 100644 --- a/src/sim/lib/force.rs +++ b/src/sim/lib/force.rs @@ -7,11 +7,11 @@ use crate::sim::{ materials::{MaterialId, fire::FireCellView}, }, particle_manager::particle::Particle, - sim_manager::SimManager, + sim_manager::SimCtx, }; pub fn apply_explosion( - sim: &mut SimManager, + ctx: &mut SimCtx, centre: Vec2, radius: i32, force_offset: Vec2, @@ -34,18 +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) = sim.cell_manager.get_cell_from_game_position(ipos.x, ipos.y) { + if let Some(cell) = ctx.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(sim.cell_manager.seqno); + fire.match_parity(ctx.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 { - sim.cell_manager + ctx.cell_manager .set_cell_from_game_position(ipos.x, ipos.y, fire, false); } else { let vel = get_vel(pos); - sim.particle_manager.particles.push(Particle::new( + ctx.particle_manager.particles.push(Particle::new( pos, vel, MaterialId::Fire, @@ -53,11 +53,11 @@ pub fn apply_explosion( )); } } else { - sim.cell_manager + ctx.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); - sim.particle_manager.particles.push(Particle::new( + ctx.particle_manager.particles.push(Particle::new( pos, vel, cell.material, diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs index b6d2528..2b8bead 100644 --- a/src/sim/sim_manager/mod.rs +++ b/src/sim/sim_manager/mod.rs @@ -38,6 +38,12 @@ pub struct SimManager { pub entities: FxHashMap<u32, Entity>, } +pub struct SimCtx<'a> { + pub cell_manager: &'a mut CellManager, + pub rb_manager: &'a mut RbManager, + pub particle_manager: &'a mut ParticleManager, +} + impl SimManager { pub fn create_entity(&mut self, def: EntityDef) -> u32 { let (rb_h, collider_h) = if let Some(rb) = def.rb { @@ -84,7 +90,7 @@ impl SimManager { pub fn destroy_entity(&mut self, id: u32) { if let Some(entity) = self.entities.get(&id) { - if let Some(rb_h) = entity.rb_h { + 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, @@ -93,7 +99,7 @@ impl SimManager { &mut self.rb_manager.physics_manager.multibody_joint_set, true, ); - } else if let Some(collider_h) = entity.collider_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, @@ -135,7 +141,7 @@ impl SimManager { f = new_local_cell.flags ); } - if let Some(cells) = &mut entity.cells { + 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, @@ -149,6 +155,23 @@ impl SimManager { } fn physics_update(&mut self, delta_time: f32) { + let entity_ids: Vec<u32> = 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 { + if 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 for cx in -5..5 { @@ -173,7 +196,25 @@ impl SimManager { .tick(&mut self.cell_manager, delta_time); } - pub fn update(&mut self, config: &Config, _delta_time: f32) -> () { + pub fn update(&mut self, config: &Config, delta_time: f32) -> () { + let entity_ids: Vec<u32> = 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; diff --git a/src/sim/sim_manager/utils.rs b/src/sim/sim_manager/utils.rs index 1565ced..97bc1f3 100644 --- a/src/sim/sim_manager/utils.rs +++ b/src/sim/sim_manager/utils.rs @@ -11,8 +11,12 @@ pub fn write_entity_to_world( ) -> Vec<(u8, u8, i32, i32)> { let mut cells_written: Vec<(u8, u8, i32, i32)> = Vec::new(); if let Some(entity) = sim.entities.get(&entity_id) - && let Some(cells) = &entity.cells - && let Some((pos, (cos, sin))) = entity.transform(sim) + && let Some(cells) = &entity.data.cells + && let Some((pos, (cos, sin))) = entity.data.transform(&super::SimCtx { + cell_manager: &mut sim.cell_manager, + rb_manager: &mut sim.rb_manager, + particle_manager: &mut sim.particle_manager, + }) { let (half_size_x, half_size_y) = (cells.size.x as f32 / 2.0, cells.size.y as f32 / 2.0); // half-extent of the rotated grid's axis-aligned bounding box, plus a cell of margin |
