summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/content/entities/entity_bullet_emitter.rs79
-rw-r--r--src/content/entities/mod.rs1
-rw-r--r--src/main.rs38
-rw-r--r--src/sim/entity/mod.rs18
-rw-r--r--src/sim/sim_manager/mod.rs15
-rw-r--r--src/sim/sim_manager/utils.rs75
6 files changed, 157 insertions, 69 deletions
diff --git a/src/content/entities/entity_bullet_emitter.rs b/src/content/entities/entity_bullet_emitter.rs
new file mode 100644
index 0000000..c58bd6b
--- /dev/null
+++ b/src/content/entities/entity_bullet_emitter.rs
@@ -0,0 +1,79 @@
+use glam::{IVec2, Vec2};
+use rapier2d::dynamics::RigidBodyBuilder;
+
+use crate::{
+ content::materials::MaterialId,
+ input::Input,
+ sim::{
+ cell::Cell,
+ entity::{EntityBehaviour, EntityCells, EntityDef, EntityUpdateCtx},
+ lib::force::apply_bullet,
+ sim_manager::SimCtx,
+ },
+};
+
+struct BulletEmitterEntityBehaviour {
+ shot_timer: f32,
+ life: f32,
+ target: Option<Vec2>,
+}
+
+impl EntityBehaviour for BulletEmitterEntityBehaviour {
+ fn update(&mut self, update_ctx: &mut EntityUpdateCtx, ctx: &mut SimCtx, delta_time: f32) {
+ if self.target.is_none() && ctx.input_manager.pressed(Input::Action4) {
+ self.target = Some(ctx.input_manager.world_mouse_pos);
+ }
+
+ if let Some(target) = self.target {
+ self.shot_timer -= delta_time;
+ if self.shot_timer <= 0.0 {
+ apply_bullet(
+ ctx,
+ update_ctx.entity_data.transform(ctx).unwrap().0,
+ target,
+ 400,
+ );
+ self.shot_timer = 0.1;
+ }
+
+ self.life -= delta_time;
+ if self.life <= 0.0 {
+ update_ctx.deferred_destroy(update_ctx.entity_data.id);
+ }
+ }
+ }
+}
+
+pub fn entity_bullet_emitter_def(position: Vec2, life: f32) -> EntityDef {
+ let w = 6;
+ 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::Steel);
+ raw_cells[cell_idx as usize].set_entity_integrated(true);
+ }
+ }
+
+ let entity_cells = EntityCells {
+ cells: raw_cells,
+ size: IVec2::new(w, h),
+ };
+
+ let rb = RigidBodyBuilder::dynamic()
+ .translation(position / crate::config::CELLS_TO_METRES)
+ .gravity_scale(0.0)
+ .build();
+
+ EntityDef::from_cells_and_rb(
+ entity_cells,
+ rb,
+ Some(Box::new(BulletEmitterEntityBehaviour {
+ shot_timer: 0.0,
+ life,
+ target: None,
+ })),
+ )
+}
diff --git a/src/content/entities/mod.rs b/src/content/entities/mod.rs
index e78eb89..652ee6d 100644
--- a/src/content/entities/mod.rs
+++ b/src/content/entities/mod.rs
@@ -1,2 +1,3 @@
+pub mod entity_bullet_emitter;
pub mod entity_cube;
pub mod entity_grenade;
diff --git a/src/main.rs b/src/main.rs
index 704a276..967484f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,6 @@ mod renderer;
mod sim;
use futures::executor;
-use glam::Vec2;
use rand::random_range;
use std::{collections::VecDeque, sync::Arc, time::Instant};
use winit::{
@@ -20,7 +19,10 @@ use crate::{
camera::Camera,
config::WINDOW_TITLE,
content::{
- entities::{entity_cube::entity_cube_def, entity_grenade::entity_grenade_def},
+ entities::{
+ entity_bullet_emitter::entity_bullet_emitter_def, entity_cube::entity_cube_def,
+ entity_grenade::entity_grenade_def,
+ },
materials::MaterialId,
},
input::{
@@ -28,12 +30,7 @@ use crate::{
InputManager,
},
renderer::RendererState,
- sim::{
- cell::Cell,
- lib::force::apply_bullet,
- rb_manager::DebugRenderMode,
- sim_manager::{SimCtx, SimManager},
- },
+ sim::{cell::Cell, rb_manager::DebugRenderMode, sim_manager::SimManager},
};
pub type Error = Box<dyn std::error::Error>;
@@ -59,9 +56,6 @@ struct App {
window: Option<Arc<Window>>,
renderer_state: Option<RendererState>,
- // tests
- bullet_origin: Option<Vec2>,
-
// game
input_manager: InputManager,
camera: Option<Camera>,
@@ -98,22 +92,10 @@ impl App {
}
if self.input_manager.pressed(Input::Action3) {
- if let Some(origin) = self.bullet_origin {
- apply_bullet(
- &mut SimCtx {
- input_manager: &self.input_manager,
- cell_manager: &mut sim.cell_manager,
- particle_manager: &mut sim.particle_manager,
- rb_manager: &mut sim.rb_manager,
- },
- origin,
- self.input_manager.world_mouse_pos,
- 800,
- );
- self.bullet_origin = None;
- } else {
- self.bullet_origin = Some(self.input_manager.world_mouse_pos);
- }
+ sim.create_entity(entity_bullet_emitter_def(
+ self.input_manager.world_mouse_pos,
+ 3.0,
+ ));
}
// --TEST DRAWING--
@@ -166,8 +148,6 @@ impl Default for App {
window: None,
renderer_state: None,
- bullet_origin: None,
-
input_manager: InputManager::new(),
camera: None,
diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs
index 2a046c5..a86a51f 100644
--- a/src/sim/entity/mod.rs
+++ b/src/sim/entity/mod.rs
@@ -49,6 +49,7 @@ impl Marchable for EntityCells {
}
pub trait EntityBehaviour {
+ // TODO merge ctxs?
fn update(&mut self, _update_ctx: &mut EntityUpdateCtx, _ctx: &mut SimCtx, _delta_time: f32) {}
fn physics_update(
&mut self,
@@ -67,6 +68,23 @@ pub struct EntityDef {
}
impl EntityDef {
+ pub fn from_cells_and_rb(
+ cells: EntityCells,
+ rb: RigidBody,
+ behaviour: Option<Box<dyn EntityBehaviour>>,
+ ) -> Self {
+ let collider = RbManager::convex_hull_collider_from_marchable(&cells, Some(10))
+ .mass(mass_from_cells(&cells.cells))
+ .build();
+
+ EntityDef {
+ rb: Some(rb),
+ collider: Some(collider),
+ cells: Some(cells),
+ behaviour,
+ }
+ }
+
pub fn from_cells(
position: Vec2,
cells: EntityCells,
diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs
index be75eeb..89ae528 100644
--- a/src/sim/sim_manager/mod.rs
+++ b/src/sim/sim_manager/mod.rs
@@ -7,10 +7,12 @@ use crate::{
config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS},
sim::{
cell_manager::manager::CellManager,
- entity::{Entity, EntityDef, EntityId},
+ entity::{Entity, EntityDef, EntityId, EntityUpdateResult},
particle_manager::ParticleManager,
rb_manager::RbManager,
- sim_manager::utils::{read_back_entities_from_world, write_entities_to_world},
+ sim_manager::utils::{
+ process_entity_update_result, read_back_entities_from_world, write_entities_to_world,
+ },
},
};
@@ -112,10 +114,7 @@ impl SimManager {
if let Some(entity) = entity
&& let Some(result) = entity.update(&mut ctx, delta_time)
{
- // process entity update results
- for d in result.deferred_destructions {
- self.destroy_entity(d);
- }
+ process_entity_update_result(self, result);
}
}
@@ -136,9 +135,7 @@ impl SimManager {
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);
- }
+ process_entity_update_result(self, result);
}
}
// before we move the rigidbodies, upsert the current terrain state
diff --git a/src/sim/sim_manager/utils.rs b/src/sim/sim_manager/utils.rs
index 506844c..e77f30a 100644
--- a/src/sim/sim_manager/utils.rs
+++ b/src/sim/sim_manager/utils.rs
@@ -2,7 +2,11 @@ use glam::IVec2;
use crate::{
content::materials::MaterialId,
- sim::{cell::Cell, entity::EntityId, sim_manager::SimManager},
+ sim::{
+ cell::Cell,
+ entity::{EntityId, EntityUpdateResult},
+ sim_manager::SimManager,
+ },
};
fn write_entity_to_world(sim: &mut SimManager, entity_id: EntityId) -> Vec<(u8, u8, i32, i32)> {
@@ -82,46 +86,55 @@ pub fn read_back_entities_from_world(
cells_written_by_entity: Vec<(EntityId, Vec<(u8, u8, i32, i32)>)>,
) {
for (entity_id, cells_written) in cells_written_by_entity {
- if let Some(entity) = sim.entities.get_mut(&entity_id) {
- let entity_cells = entity.data.cells.as_mut().unwrap();
- let mut should_update_entity = false;
+ let mut entity = sim.entities.get_mut(&entity_id);
+ let mut should_update_entity = false;
- for (lx, ly, x, y) in cells_written {
- // update the entity
- // TODO optimize
- let new_local_cell = sim.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;
- }
+ for (lx, ly, x, y) in cells_written {
+ // update the entity
+ // TODO optimize
+ let new_local_cell = sim.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) = &mut entity {
+ let entity_cells = entity.data.cells.as_mut().unwrap();
// 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
- sim.cell_manager
- .set_cell_from_game_position(x, y, Cell::void(), false);
}
- if should_update_entity {
- if let Some(new_collider) = entity.compute_collider() {
- sim.rb_manager
- .physics_manager
- .world
- .remove_collider(entity.data.collider_h.unwrap());
+ // update the world
+ // TODO optimize
+ sim.cell_manager
+ .set_cell_from_game_position(x, y, Cell::void(), false);
+ }
- let new_handle = sim
- .rb_manager
- .physics_manager
- .world
- .insert_collider(new_collider, Some(entity.data.rb_h.unwrap()));
+ if let Some(entity) = &mut entity
+ && should_update_entity
+ {
+ if let Some(new_collider) = entity.compute_collider() {
+ sim.rb_manager
+ .physics_manager
+ .world
+ .remove_collider(entity.data.collider_h.unwrap());
- entity.data.collider_h = Some(new_handle);
- }
+ let new_handle = sim
+ .rb_manager
+ .physics_manager
+ .world
+ .insert_collider(new_collider, Some(entity.data.rb_h.unwrap()));
+
+ entity.data.collider_h = Some(new_handle);
}
}
}
}
+
+pub fn process_entity_update_result(sim: &mut SimManager, result: EntityUpdateResult) {
+ for d in result.deferred_destructions {
+ sim.destroy_entity(d);
+ }
+}