summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Stevenson <kai@kaistevenson.com>2026-08-23 14:33:23 -0700
committerKai Stevenson <kai@kaistevenson.com>2026-08-23 14:33:23 -0700
commitda45c5a7dbb017c8e579d0ab66a2259a70b28f40 (patch)
tree938c0be6bd6b938cb8788456ce759b784ee74f5c
parentc4c26f03e3eb18a76f9c2756076030dc52a667fa (diff)
input manager
-rw-r--r--src/camera.rs15
-rw-r--r--src/input.rs159
-rw-r--r--src/main.rs187
-rw-r--r--src/renderer/mod.rs12
-rw-r--r--src/renderer/ui.rs81
-rw-r--r--src/sim/entity/mod.rs22
-rw-r--r--src/sim/sim_manager/mod.rs19
-rw-r--r--src/sim/sim_manager/utils.rs6
8 files changed, 275 insertions, 226 deletions
diff --git a/src/camera.rs b/src/camera.rs
index 13c5ec9..0fe9f22 100644
--- a/src/camera.rs
+++ b/src/camera.rs
@@ -1,4 +1,7 @@
-use crate::{Input, config::CAMERA_MOVEMENT_SPEED};
+use crate::{
+ config::CAMERA_MOVEMENT_SPEED,
+ input::{Input, InputManager},
+};
#[repr(C)]
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
@@ -28,18 +31,18 @@ impl Camera {
(xl, xu, yl, yu)
}
- pub fn handle_camera_input(&mut self, input: &Input, delta_time: f32) {
+ pub fn handle_camera_input(&mut self, input_manager: &InputManager, delta_time: f32) {
// wasd movement
- let x: f32 = if input.is_left_pressed {
+ let x: f32 = if input_manager.held(Input::Left) {
-1.0
- } else if input.is_right_pressed {
+ } else if input_manager.held(Input::Right) {
1.0
} else {
0.0
};
- let y: f32 = if input.is_down_pressed {
+ let y: f32 = if input_manager.held(Input::Down) {
1.0
- } else if input.is_up_pressed {
+ } else if input_manager.held(Input::Up) {
-1.0
} else {
0.0
diff --git a/src/input.rs b/src/input.rs
new file mode 100644
index 0000000..dd49cd0
--- /dev/null
+++ b/src/input.rs
@@ -0,0 +1,159 @@
+use glam::{IVec2, Vec2};
+use winit::{
+ event::{KeyEvent, MouseButton, WindowEvent},
+ keyboard::{KeyCode, PhysicalKey},
+};
+
+use crate::{camera::Camera, sim::cell_manager::manager::CellManager};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum Input {
+ // movement
+ Up,
+ Left,
+ Down,
+ Right,
+
+ // sim management
+ Pause,
+ Step,
+ ClearGrid,
+ ClearEntities,
+ ClearParticles,
+
+ // placeholder actions
+ Action1,
+ Action2,
+ Action3,
+ Action4,
+ Action5,
+ Action6,
+}
+
+const INPUT_VAR_LEN: usize = 17;
+
+const KEYMAP: [(KeyCode, Input); 15] = [
+ (KeyCode::KeyW, Input::Up),
+ (KeyCode::KeyA, Input::Left),
+ (KeyCode::KeyS, Input::Down),
+ (KeyCode::KeyD, Input::Right),
+ (KeyCode::Space, Input::Pause),
+ (KeyCode::KeyX, Input::Step),
+ (KeyCode::KeyC, Input::ClearGrid),
+ (KeyCode::KeyV, Input::ClearEntities),
+ (KeyCode::KeyP, Input::ClearParticles),
+ (KeyCode::Digit1, Input::Action1),
+ (KeyCode::Digit2, Input::Action2),
+ (KeyCode::Digit3, Input::Action3),
+ (KeyCode::Digit4, Input::Action4),
+ (KeyCode::Digit5, Input::Action5),
+ (KeyCode::Digit6, Input::Action6),
+];
+
+pub struct InputManager {
+ pub screen_mouse_pos: Vec2,
+ pub world_mouse_pos: Vec2,
+ pub chunk_mouse_pos: IVec2,
+ pub local_mouse_pos: IVec2,
+
+ pub lmb_pressed: bool,
+ pub lmb_held: bool,
+ pub rmb_pressed: bool,
+ pub rmb_held: bool,
+ pressed: [bool; INPUT_VAR_LEN],
+ held: [bool; INPUT_VAR_LEN],
+}
+
+impl InputManager {
+ pub fn reset_for_frame(&mut self) {
+ self.pressed = [false; INPUT_VAR_LEN];
+ self.lmb_pressed = false;
+ self.rmb_pressed = false;
+ }
+
+ pub fn apply_event(&mut self, event: &WindowEvent, camera: &Camera) {
+ match event {
+ WindowEvent::KeyboardInput {
+ event:
+ KeyEvent {
+ physical_key: PhysicalKey::Code(code),
+ repeat: false,
+ state,
+ ..
+ },
+ ..
+ } => {
+ if let Some(&(_, input)) = KEYMAP.iter().find(|m| m.0 == *code) {
+ if state.is_pressed() {
+ self.held[input as usize] = true;
+ self.pressed[input as usize] = true;
+ } else {
+ self.held[input as usize] = false;
+ }
+ }
+ }
+ WindowEvent::CursorMoved { position, .. } => {
+ let (wp_x, wp_y) =
+ camera.screen_position_to_world(position.x as f32, position.y as f32);
+
+ let ((cx, cy), (lx, ly)) =
+ CellManager::split_game_position(wp_x.round() as i32, wp_y.round() as i32);
+
+ self.screen_mouse_pos = Vec2::new(position.x as f32, position.y as f32);
+ self.world_mouse_pos = Vec2::new(wp_x, wp_y);
+ self.chunk_mouse_pos = IVec2::new(cx, cy);
+ self.local_mouse_pos = IVec2::new(lx as i32, ly as i32);
+ }
+ WindowEvent::MouseInput { state, button, .. } => {
+ if *button == MouseButton::Left {
+ if state.is_pressed() {
+ self.lmb_pressed = true;
+ self.lmb_held = true;
+ } else {
+ self.lmb_held = false;
+ }
+ } else if *button == MouseButton::Right {
+ if state.is_pressed() {
+ self.rmb_pressed = true;
+ self.rmb_held = true;
+ } else {
+ self.rmb_held = false;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ pub fn pressed(&self, input: Input) -> bool {
+ if input as usize >= INPUT_VAR_LEN {
+ false
+ } else {
+ self.pressed[input as usize]
+ }
+ }
+
+ pub fn held(&self, input: Input) -> bool {
+ if input as usize >= INPUT_VAR_LEN {
+ false
+ } else {
+ self.held[input as usize]
+ }
+ }
+
+ pub fn new() -> Self {
+ InputManager {
+ screen_mouse_pos: Vec2::ZERO,
+ world_mouse_pos: Vec2::ZERO,
+ chunk_mouse_pos: IVec2::ZERO,
+ local_mouse_pos: IVec2::ZERO,
+
+ lmb_pressed: false,
+ lmb_held: false,
+ rmb_pressed: false,
+ rmb_held: false,
+ pressed: [false; INPUT_VAR_LEN],
+ held: [false; INPUT_VAR_LEN],
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 0daef91..704a276 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,7 @@
mod camera;
mod config;
mod content;
+mod input;
mod renderer;
mod sim;
@@ -10,12 +11,8 @@ use rand::random_range;
use std::{collections::VecDeque, sync::Arc, time::Instant};
use winit::{
application::ApplicationHandler,
- event::{
- ElementState, KeyEvent, MouseButton,
- WindowEvent::{self},
- },
+ event::WindowEvent::{self},
event_loop::{ActiveEventLoop, ControlFlow, EventLoop},
- keyboard::{KeyCode, PhysicalKey},
window::Window,
};
@@ -26,12 +23,14 @@ use crate::{
entities::{entity_cube::entity_cube_def, entity_grenade::entity_grenade_def},
materials::MaterialId,
},
+ input::{
+ Input::{self},
+ InputManager,
+ },
renderer::RendererState,
sim::{
cell::Cell,
- cell_manager::manager::CellManager,
- entity::EntityId,
- lib::force::{apply_bullet, apply_explosion},
+ lib::force::apply_bullet,
rb_manager::DebugRenderMode,
sim_manager::{SimCtx, SimManager},
},
@@ -50,26 +49,6 @@ struct Config {
debug_render_mode: DebugRenderMode,
}
-struct Input {
- last_mouse_pos_on_screen: Option<(f32, f32)>,
- last_mouse_world_pos: Option<(f32, f32)>,
- last_mouse_chunk_pos: Option<(i32, i32)>,
- last_mouse_local_pos: Option<(u8, u8)>,
- is_lmb_pressed: bool,
- is_rmb_pressed: bool,
- trigger_test_1: bool,
- trigger_test_2: bool,
- trigger_test_3: bool,
- trigger_test_4: bool,
- trigger_test_5: bool,
-
- // keybindings
- is_up_pressed: bool,
- is_left_pressed: bool,
- is_down_pressed: bool,
- is_right_pressed: bool,
-}
-
struct Diagnostics {
frame_times: VecDeque<f32>,
fps: f32,
@@ -84,7 +63,7 @@ struct App {
bullet_origin: Option<Vec2>,
// game
- input: Input,
+ input_manager: InputManager,
camera: Option<Camera>,
sim_manager: Option<SimManager>,
@@ -102,87 +81,64 @@ impl App {
fn update(&mut self, delta_time: f32) {
// apply inputs
if let Some(camera) = &mut self.camera {
- camera.handle_camera_input(&self.input, delta_time)
+ camera.handle_camera_input(&self.input_manager, delta_time)
}
if let Some(sim) = &mut self.sim_manager {
// --TEST SPAWNING--
- if self.input.trigger_test_1
- && let Some(lm) = self.input.last_mouse_world_pos
- {
- self.input.trigger_test_1 = false;
+ if self.input_manager.pressed(Input::Action1) {
sim.create_entity(entity_cube_def(
- Vec2::new(lm.0, lm.1),
+ self.input_manager.world_mouse_pos,
self.config.dropper_material,
));
}
- 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_manager.pressed(Input::Action2) {
+ sim.create_entity(entity_grenade_def(self.input_manager.world_mouse_pos, 3.0));
}
- if self.input.trigger_test_3
- && let Some(lm) = self.input.last_mouse_world_pos
- {
- self.input.trigger_test_3 = false;
+ 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,
- Vec2::new(lm.0, lm.1),
+ self.input_manager.world_mouse_pos,
800,
);
self.bullet_origin = None;
} else {
- self.bullet_origin = Some(Vec2::new(lm.0, lm.1));
+ self.bullet_origin = Some(self.input_manager.world_mouse_pos);
}
}
- if self.input.trigger_test_4
- && let Some(lm) = self.input.last_mouse_world_pos
- {
- let mouse = Vec2::new(lm.0, lm.1);
- self.input.trigger_test_4 = false;
- 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--
- if (self.input.is_lmb_pressed || self.input.is_rmb_pressed)
- && let Some(lm) = self.input.last_mouse_world_pos
- {
+ if self.input_manager.lmb_held || self.input_manager.rmb_held {
// start with the bounding box of the drawing brush circle + some margin
// clamp the bounding box to the board sie
- let bb_xl = (lm.0 - self.config.brush_radius).round() as i32;
- let bb_xu = (lm.0 + self.config.brush_radius).round() as i32;
- let bb_yl = (lm.1 - self.config.brush_radius).round() as i32;
- let bb_yu = (lm.1 + self.config.brush_radius).round() as i32;
+ let bb_xl = (self.input_manager.world_mouse_pos.x - self.config.brush_radius)
+ .round() as i32;
+ let bb_xu = (self.input_manager.world_mouse_pos.x + self.config.brush_radius)
+ .round() as i32;
+ let bb_yl = (self.input_manager.world_mouse_pos.y - self.config.brush_radius)
+ .round() as i32;
+ let bb_yu = (self.input_manager.world_mouse_pos.y + self.config.brush_radius)
+ .round() as i32;
// for each point, check if the distance is less than the brush size and write the pixel
for x in bb_xl..bb_xu {
for y in bb_yl..bb_yu {
let r = random_range(0.0..1.0);
- if ((x - lm.0.round() as i32).pow(2) + (y - lm.1.round() as i32).pow(2))
+ if ((x - self.input_manager.world_mouse_pos.x.round() as i32).pow(2)
+ + (y - self.input_manager.world_mouse_pos.y.round() as i32).pow(2))
< (self.config.brush_radius as i32).pow(2)
&& r > 0.9
{
- let cell = if self.input.is_lmb_pressed {
+ let cell = if self.input_manager.lmb_held {
let mut cell = Cell::from_material(self.config.brush_material);
// ensure we simulate on the first tick
cell.match_parity(sim.cell_manager.seqno);
@@ -198,7 +154,8 @@ impl App {
}
}
- sim.update(&self.config, delta_time);
+ sim.update(&self.config, &self.input_manager, delta_time);
+ self.input_manager.reset_for_frame();
}
}
}
@@ -211,24 +168,7 @@ impl Default for App {
bullet_origin: None,
- input: Input {
- last_mouse_pos_on_screen: None,
- last_mouse_world_pos: None,
- last_mouse_chunk_pos: None,
- last_mouse_local_pos: None,
-
- trigger_test_1: false,
- trigger_test_2: false,
- trigger_test_3: false,
- trigger_test_4: false,
- trigger_test_5: false,
- is_lmb_pressed: false,
- is_rmb_pressed: false,
- is_up_pressed: false,
- is_left_pressed: false,
- is_down_pressed: false,
- is_right_pressed: false,
- },
+ input_manager: InputManager::new(),
camera: None,
@@ -290,64 +230,11 @@ impl ApplicationHandler for App {
}
}
- match event {
- WindowEvent::KeyboardInput {
- event:
- KeyEvent {
- physical_key: PhysicalKey::Code(code),
- state,
- repeat,
- ..
- },
- ..
- } => {
- if let Some(sim) = &mut self.sim_manager {
- let pressed = state.is_pressed();
- match code {
- KeyCode::KeyW => self.input.is_up_pressed = pressed,
- KeyCode::KeyA => self.input.is_left_pressed = pressed,
- KeyCode::KeyS => self.input.is_down_pressed = pressed,
- KeyCode::KeyD => self.input.is_right_pressed = pressed,
- KeyCode::KeyC => sim.cell_manager = CellManager::from_default_size(),
- KeyCode::KeyP => sim.particle_manager.particles = Vec::new(),
- KeyCode::KeyV => {
- let ids: Vec<EntityId> = sim.entities.keys().cloned().collect();
- for id in ids {
- sim.destroy_entity(id);
- }
- }
- KeyCode::Space if pressed => sim.paused = !sim.paused,
- KeyCode::KeyX if pressed => sim.ignore_pause_next_tick = true,
- KeyCode::Digit1 if pressed && !repeat => self.input.trigger_test_1 = true,
- KeyCode::Digit2 if pressed && !repeat => self.input.trigger_test_2 = true,
- KeyCode::Digit3 if pressed && !repeat => self.input.trigger_test_3 = true,
- KeyCode::Digit4 if pressed && !repeat => self.input.trigger_test_4 = true,
- KeyCode::Digit5 if pressed && !repeat => self.input.trigger_test_5 = true,
- _ => {}
- }
- }
- }
- WindowEvent::CursorMoved { position, .. } => {
- self.input.last_mouse_pos_on_screen = Some((position.x as f32, position.y as f32));
-
- if let Some(camera) = &mut self.camera {
- let world_pos =
- camera.screen_position_to_world(position.x as f32, position.y as f32);
+ if let Some(camera) = &self.camera {
+ self.input_manager.apply_event(&event, &camera);
+ }
- self.input.last_mouse_world_pos = Some(world_pos);
- let ((cx, cy), (lx, ly)) =
- CellManager::split_game_position(world_pos.0 as i32, world_pos.1 as i32);
- self.input.last_mouse_chunk_pos = Some((cx, cy));
- self.input.last_mouse_local_pos = Some((lx, ly));
- }
- }
- WindowEvent::MouseInput { state, button, .. } => {
- if button == MouseButton::Left {
- self.input.is_lmb_pressed = state == ElementState::Pressed
- } else if button == MouseButton::Right {
- self.input.is_rmb_pressed = state == ElementState::Pressed
- }
- }
+ match event {
WindowEvent::Resized(size) => {
if let Some(renderer_state) = &mut self.renderer_state
&& let Some(camera) = &mut self.camera
@@ -391,7 +278,7 @@ impl ApplicationHandler for App {
camera,
&mut self.config,
&self.diagnostics,
- &self.input,
+ &self.input_manager,
);
}
}
diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs
index 54a6667..b37dc09 100644
--- a/src/renderer/mod.rs
+++ b/src/renderer/mod.rs
@@ -6,7 +6,7 @@ use fxhash::FxHashMap;
use winit::window::Window;
use crate::{
- Config, Diagnostics, Input,
+ Config, Diagnostics, InputManager,
camera::Camera,
config::{CELLS_IN_CHUNK, CHUNK_SIZE},
content::materials::MaterialId,
@@ -578,7 +578,7 @@ impl RendererState {
camera: &mut Camera,
config: &mut Config,
diagnostics: &Diagnostics,
- input: &Input,
+ input_manager: &InputManager,
) {
puffin::profile_function!();
@@ -626,7 +626,7 @@ impl RendererState {
.resizable(false)
// TODO collapse button
.show_collapsible(ui, &mut true, |panel_ui| {
- draw_egui(panel_ui, config, camera, diagnostics, input, sim)
+ draw_egui(panel_ui, config, camera, diagnostics, input_manager, sim)
});
});
@@ -747,11 +747,7 @@ impl RendererState {
for (id, slot) in &self.renderer_rb_entities {
if let Some(entity) = sim.entities.get(id)
&& let Some(cells) = &entity.data.cells
- && let Some((pos, (cos, sin))) = entity.data.transform(&SimCtx {
- cell_manager: &mut sim.cell_manager,
- particle_manager: &mut sim.particle_manager,
- rb_manager: &mut sim.rb_manager,
- })
+ && let Some((pos, (cos, sin))) = entity.data._transform(&sim.rb_manager)
{
instances.push(RendererInstance {
centre: pos.to_array(),
diff --git a/src/renderer/ui.rs b/src/renderer/ui.rs
index a7395a0..46fb853 100644
--- a/src/renderer/ui.rs
+++ b/src/renderer/ui.rs
@@ -1,8 +1,9 @@
use egui::{Color32, Stroke, Ui, epaint::CircleShape};
use crate::{
- Camera, Config, Diagnostics, Input,
+ Camera, Config, Diagnostics,
content::materials::MaterialId,
+ input::InputManager,
sim::{rb_manager::DebugRenderMode, sim_manager::SimManager},
};
@@ -20,7 +21,7 @@ pub fn draw_egui<'a>(
config: &mut Config,
camera: &mut Camera,
diagnostics: &Diagnostics,
- input: &Input,
+ input_manager: &InputManager,
sim: &SimManager,
) {
puffin::profile_function!();
@@ -104,44 +105,50 @@ pub fn draw_egui<'a>(
ui.add(egui::Slider::new(&mut camera.zoom, 0.0..=10.0).text("Zoom"));
ui.heading("Input");
- input
- .last_mouse_world_pos
- .map(|p| ui.label(format!("Mouse (world): x,y=({x}, {y})", x = p.0, y = p.1,)));
+ ui.label(format!(
+ "Mouse (world): x,y=({x}, {y})",
+ x = input_manager.world_mouse_pos.x,
+ y = input_manager.world_mouse_pos.y
+ ));
- if let Some(p) = input.last_mouse_chunk_pos {
- ui.label(format!("Mouse (chunk): x,y=({x}, {y})", x = p.0, y = p.1,));
- if let Some(&chunk) = sim.cell_manager.chunk_position_to_chunk_idx.get(&p) {
- ui.label(format!(
- "Sleeping={}",
- sim.cell_manager.chunks[chunk].sleeping
- ));
- }
+ ui.label(format!(
+ "Mouse (chunk): x,y=({x}, {y})",
+ x = input_manager.chunk_mouse_pos.x,
+ y = input_manager.chunk_mouse_pos.y
+ ));
+
+ if let Some(&chunk) = sim.cell_manager.chunk_position_to_chunk_idx.get(&(
+ input_manager.chunk_mouse_pos.x,
+ input_manager.chunk_mouse_pos.y,
+ )) {
+ ui.label(format!(
+ "Sleeping={}",
+ sim.cell_manager.chunks[chunk].sleeping
+ ));
}
- input
- .last_mouse_local_pos
- .map(|p| ui.label(format!("Mouse (local): x,y=({x}, {y})", x = p.0, y = p.1,)));
+ ui.label(format!(
+ "Mouse (local): x,y=({x}, {y})",
+ x = input_manager.local_mouse_pos.x,
+ y = input_manager.local_mouse_pos.y
+ ));
- if let Some((x, y)) = input.last_mouse_world_pos {
- ui.heading("Entity");
- if let Some(cell) = sim
- .cell_manager
- .get_cell_from_game_position(x.round() as i32, y.round() as i32)
- {
- let material = cell.material.def();
- let cell_label = ui.label(
- egui::RichText::new(format!("Cell: {}", material.name)).color(Color32::LIGHT_BLUE),
- );
- ui.painter().add(egui::Shape::Circle(CircleShape {
- center: cell_label.rect.right_center() + egui::vec2(10.0, 0.0),
- radius: cell_label.rect.height() / 2.5,
- stroke: Stroke::NONE,
- fill: Color32::from_rgb(material.color.0, material.color.1, material.color.2),
- }));
- ui.label(
- egui::RichText::new(format!("Flags: {:b}", cell.flags)).color(Color32::YELLOW),
- );
- ui.label(egui::RichText::new(format!("Data: {:b}", cell.data)).color(Color32::RED));
- }
+ ui.heading("Entity");
+ if let Some(cell) = sim.cell_manager.get_cell_from_game_position(
+ input_manager.world_mouse_pos.x.round() as i32,
+ input_manager.world_mouse_pos.y.round() as i32,
+ ) {
+ let material = cell.material.def();
+ let cell_label = ui.label(
+ egui::RichText::new(format!("Cell: {}", material.name)).color(Color32::LIGHT_BLUE),
+ );
+ ui.painter().add(egui::Shape::Circle(CircleShape {
+ center: cell_label.rect.right_center() + egui::vec2(10.0, 0.0),
+ radius: cell_label.rect.height() / 2.5,
+ stroke: Stroke::NONE,
+ fill: Color32::from_rgb(material.color.0, material.color.1, material.color.2),
+ }));
+ ui.label(egui::RichText::new(format!("Flags: {:b}", cell.flags)).color(Color32::YELLOW));
+ ui.label(egui::RichText::new(format!("Data: {:b}", cell.data)).color(Color32::RED));
}
}
diff --git a/src/sim/entity/mod.rs b/src/sim/entity/mod.rs
index 044d07c..2a046c5 100644
--- a/src/sim/entity/mod.rs
+++ b/src/sim/entity/mod.rs
@@ -126,21 +126,19 @@ impl<'a> EntityUpdateCtx<'a> {
}
impl EntityData {
- pub fn transform(&self, ctx: &SimCtx) -> Option<(Vec2, (f32, f32))> {
+ pub fn _transform(&self, rb_manager: &RbManager) -> Option<(Vec2, (f32, f32))> {
self.rb_h.and_then(|rb_h| {
- ctx.rb_manager
- .physics_manager
- .world
- .bodies
- .get(rb_h)
- .map(|rb| {
- (
- rb.translation() * CELLS_TO_METRES,
- (rb.rotation().cos(), rb.rotation().sin()),
- )
- })
+ rb_manager.physics_manager.world.bodies.get(rb_h).map(|rb| {
+ (
+ rb.translation() * CELLS_TO_METRES,
+ (rb.rotation().cos(), rb.rotation().sin()),
+ )
+ })
})
}
+ pub fn transform(&self, ctx: &SimCtx) -> Option<(Vec2, (f32, f32))> {
+ self._transform(ctx.rb_manager)
+ }
}
pub struct Entity {
diff --git a/src/sim/sim_manager/mod.rs b/src/sim/sim_manager/mod.rs
index 74c21fa..be75eeb 100644
--- a/src/sim/sim_manager/mod.rs
+++ b/src/sim/sim_manager/mod.rs
@@ -3,7 +3,7 @@ use std::time::Instant;
use fxhash::FxHashMap;
use crate::{
- Config,
+ Config, InputManager,
config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS},
sim::{
cell_manager::manager::CellManager,
@@ -37,6 +37,7 @@ pub struct SimManager {
}
pub struct SimCtx<'a> {
+ pub input_manager: &'a InputManager,
pub cell_manager: &'a mut CellManager,
pub rb_manager: &'a mut RbManager,
pub particle_manager: &'a mut ParticleManager,
@@ -91,7 +92,7 @@ impl SimManager {
}
}
- fn cell_update(&mut self, config: &Config, delta_time: f32) {
+ fn cell_update(&mut self, config: &Config, input_manager: &InputManager, delta_time: f32) {
// before we tick, write all the entities into the sim world
let cells_written_by_entity = write_entities_to_world(self);
@@ -103,6 +104,7 @@ impl SimManager {
for id in entity_ids {
let entity = self.entities.get_mut(&id);
let mut ctx = SimCtx {
+ input_manager,
cell_manager: &mut self.cell_manager,
rb_manager: &mut self.rb_manager,
particle_manager: &mut self.particle_manager,
@@ -121,11 +123,12 @@ impl SimManager {
read_back_entities_from_world(self, cells_written_by_entity);
}
- fn physics_update(&mut self, delta_time: f32) {
+ fn physics_update(&mut self, input_manager: &InputManager, delta_time: f32) {
let entity_ids: Vec<EntityId> = self.entities.keys().cloned().collect();
for id in entity_ids {
let entity = self.entities.get_mut(&id);
let mut ctx = SimCtx {
+ input_manager,
cell_manager: &mut self.cell_manager,
rb_manager: &mut self.rb_manager,
particle_manager: &mut self.particle_manager,
@@ -162,21 +165,21 @@ 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, input_manager: &InputManager, 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, delta_time);
+ self.cell_update(config, input_manager, 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, delta_time);
+ self.cell_update(config, input_manager, delta_time);
self.cell_updates_due -= 1.0;
cell_updates_done += 1;
}
@@ -189,14 +192,14 @@ impl SimManager {
self.last_physics_update = now;
if self.paused && self.ignore_pause_next_tick {
- self.physics_update(PHYSICS_DELTA_TIME);
+ self.physics_update(input_manager, 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_update(input_manager, PHYSICS_DELTA_TIME);
self.physics_updates_due -= 1.0;
updates_done += 1;
}
diff --git a/src/sim/sim_manager/utils.rs b/src/sim/sim_manager/utils.rs
index 413e709..506844c 100644
--- a/src/sim/sim_manager/utils.rs
+++ b/src/sim/sim_manager/utils.rs
@@ -9,11 +9,7 @@ fn write_entity_to_world(sim: &mut SimManager, entity_id: EntityId) -> Vec<(u8,
let mut cells_written: Vec<(u8, u8, i32, i32)> = Vec::new();
if let Some(entity) = sim.entities.get(&entity_id)
&& 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 Some((pos, (cos, sin))) = entity.data._transform(&sim.rb_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