summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs389
1 files changed, 103 insertions, 286 deletions
diff --git a/src/main.rs b/src/main.rs
index caedc23..3976d71 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,8 +4,8 @@ mod renderer;
mod sim;
use futures::executor;
-use glam::{IVec2, Vec2};
-use rand::{random_range, random_ratio};
+use glam::Vec2;
+use rand::random_range;
use std::{collections::VecDeque, sync::Arc, time::Instant};
use winit::{
application::ApplicationHandler,
@@ -20,18 +20,15 @@ use winit::{
use crate::{
camera::Camera,
- config::{PHYSICS_DELTA_TIME, PHYSICS_FPS, SIM_FPS, WINDOW_TITLE},
+ config::WINDOW_TITLE,
renderer::RendererState,
sim::{
- cell::{
- cell::Cell,
- materials::{MaterialId, fire::FireCellView},
- },
- cell_sim::{sim::sim_tick, world::World},
+ cell::{cell::Cell, materials::MaterialId},
+ cell_manager::manager::CellManager,
lib::force::apply_explosion,
- particle_sim::{ParticleManager, particle::Particle},
- rb_sim::{DebugRenderMode, RbSimManager, debug_ops::DebugOperator},
- write_rb_entity_to_world,
+ particle_manager::particle::Particle,
+ rb_manager::{DebugRenderMode, debug_ops::DebugOperator},
+ sim_manager::SimManager,
},
};
@@ -74,34 +71,19 @@ struct Diagnostics {
}
struct App {
+ // core
window: Option<Arc<Window>>,
renderer_state: Option<RendererState>,
+ // game
input: Input,
-
camera: Option<Camera>,
+ sim_manager: Option<SimManager>,
- // grid
- world: Option<World>,
-
- // physics
- rb_sim_manager: Option<RbSimManager>,
- particle_manager: Option<ParticleManager>,
-
- // sim state
- // the last/current (not yet completed) seqno
- sim_seqno: u64,
- sim_paused: bool,
- ignore_pause_next_tick: bool,
- last_sim_update: Instant,
- sim_updates_due: f32,
-
- // physics state
- last_physics_update: Instant,
- physics_updates_due: f32,
-
+ // renderer
last_render: Instant,
+ // state
config: Config,
diagnostics: Diagnostics,
}
@@ -115,171 +97,85 @@ impl App {
camera.handle_camera_input(&self.input, delta_time)
}
- // --TEST SPAWNING--
- if self.input.trigger_test_1
- && let Some(lm) = self.input.last_mouse_world_pos
- && let Some(rbsm) = &mut self.rb_sim_manager
- {
- self.input.trigger_test_1 = false;
- rbsm.test_spawn_box(lm.0, lm.1, self.config.dropper_material);
- }
-
- if self.input.trigger_test_2
- && let Some(lm) = self.input.last_mouse_world_pos
- && let Some(rbsm) = &mut self.rb_sim_manager
- {
- self.input.trigger_test_2 = false;
- rbsm.test_spawn_ball(lm.0, lm.1, self.config.dropper_material);
- }
-
- if self.input.trigger_test_3
- && let Some(lm) = self.input.last_mouse_world_pos
- && let Some(pm) = &mut self.particle_manager
- {
- self.input.trigger_test_3 = false;
- for i in 0..100 {
- pm.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(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;
+ sim.rb_manager
+ .test_spawn_box(lm.0, lm.1, self.config.dropper_material);
}
- }
- if self.input.trigger_test_4
- && let Some(lm) = self.input.last_mouse_world_pos
- && let Some(world) = &mut self.world
- && let Some(pm) = &mut self.particle_manager
- && let Some(rbsm) = &mut self.rb_sim_manager
- {
- let mouse = Vec2::new(lm.0, lm.1);
- self.input.trigger_test_4 = false;
- apply_explosion(
- mouse,
- 30,
- Vec2::new(0.0, -0.6),
- 300.0,
- self.sim_seqno,
- pm,
- world,
- rbsm,
- );
- }
-
- // --TEST DRAWING--
- if (self.input.is_lmb_pressed || self.input.is_rmb_pressed)
- && let Some(lm) = self.input.last_mouse_world_pos
- {
- // 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;
+ if self.input.trigger_test_2
+ && let Some(lm) = self.input.last_mouse_world_pos
+ {
+ self.input.trigger_test_2 = false;
+ sim.rb_manager
+ .test_spawn_ball(lm.0, lm.1, self.config.dropper_material);
+ }
- // 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))
- < (self.config.brush_radius as i32).pow(2)
- && r > 0.9
- {
- let cell = if self.input.is_lmb_pressed {
- let mut cell = Cell::from_material(self.config.brush_material);
- cell.match_parity(self.sim_seqno);
- cell
- } else {
- Cell::void()
- };
- // ensure we simulate on the first tick
- if let Some(world) = &mut self.world {
- world.set_cell_from_game_position(
- x, y, cell, false, // wake the chunk
- )
- }
- }
+ if self.input.trigger_test_3
+ && 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,
+ })
}
}
- }
- }
- // called SIM_FPS times per second
- // will be called before the render and before the physics update(s)
- // may be called multiple times if the sim time is behind
- fn sim_update(&mut self) {
- if let Some(world) = &mut self.world
- && let Some(rbsm) = &mut self.rb_sim_manager
- {
- // before we tick, write all the rb entities into the sim world
- // TODO optimize
- let entity_ids: Vec<u32> = rbsm.rb_entities.keys().copied().collect();
- let mut cells_written_by_entity: Vec<(u32, Vec<(u8, u8, i32, i32)>)> = Vec::new();
- for entity_id in entity_ids {
- let cells_written =
- write_rb_entity_to_world(world, rbsm, entity_id, self.sim_seqno);
- cells_written_by_entity.push((entity_id, cells_written));
+ 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(sim, mouse, 30, Vec2::new(0.0, -0.6), 300.0);
}
- sim_tick(world, self.sim_seqno, self.config.use_threading);
- self.sim_seqno += 1;
+ // --TEST DRAWING--
+ if (self.input.is_lmb_pressed || self.input.is_rmb_pressed)
+ && let Some(lm) = self.input.last_mouse_world_pos
+ {
+ // 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;
- // after we tick, remove the written rb cells and update the entities
- // TODO optimize
- for (entity_id, cells_written) in cells_written_by_entity {
- let rb_entity = rbsm.rb_entities.get_mut(&entity_id).unwrap();
- 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 = world.get_cell_from_game_position(x, y).unwrap();
- if new_local_cell.material != MaterialId::Void && !new_local_cell.rb() {
- panic!(
- "Someone swapped into this rb's cell! ({x}, {y}, {m:#?}, {f})",
- m = new_local_cell.material,
- f = new_local_cell.flags
- );
- }
- rb_entity.set_cell_at_local_position(lx, ly, new_local_cell);
- // update the world
- world.set_cell_from_game_position(x, y, Cell::void(), false);
- }
- }
- }
- }
- // called PHYSICS_FPS times per second
- // will be called before the render
- // may be called multiple times if the physics time is behind
- // physics_delta_time is statically 1/PHYSICS_FPS
- fn physics_update(&mut self, physics_delta_time: f32) {
- // before we move the rigidbodies, upsert the current terrain state
- // TODO use the chunk sleeping, and make this range dynamic
- if let Some(physics_manager) = &mut self.rb_sim_manager {
- if let Some(world) = &self.world {
- for cx in -5..5 {
- for cy in -5..5 {
- if let Some(chunk) = world
- .chunk_position_to_chunk_idx
- .get(&(cx, cy))
- .map(|&idx| &world.chunks[idx])
- && !chunk.sleeping
+ // 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))
+ < (self.config.brush_radius as i32).pow(2)
+ && r > 0.9
{
- physics_manager.upsert_chunk_collider(cx, cy, chunk);
+ let cell = if self.input.is_lmb_pressed {
+ let mut cell = Cell::from_material(self.config.brush_material);
+ // ensure we simulate on the first tick
+ cell.match_parity(sim.cell_manager.seqno);
+ cell
+ } else {
+ Cell::void()
+ };
+ sim.cell_manager.set_cell_from_game_position(
+ x, y, cell, false, // wake the chunk
+ )
}
}
}
}
- physics_manager.rb_tick(physics_delta_time);
- }
- // move the particles
- if let Some(particle_manager) = &mut self.particle_manager
- && let Some(world) = &mut self.world
- {
- particle_manager.particle_tick(world, physics_delta_time);
+
+ sim.update(&self.config, delta_time);
}
}
}
@@ -311,19 +207,7 @@ impl Default for App {
camera: None,
- world: Some(World::from_default_size()),
-
- rb_sim_manager: Some(RbSimManager::new()),
- particle_manager: Some(ParticleManager::new()),
-
- sim_seqno: 0,
- sim_paused: false,
- ignore_pause_next_tick: false,
- last_sim_update: Instant::now(),
- sim_updates_due: 0.0,
-
- last_physics_update: Instant::now(),
- physics_updates_due: 0.0,
+ sim_manager: Some(SimManager::new()),
last_render: Instant::now(),
@@ -392,51 +276,31 @@ impl ApplicationHandler for App {
},
..
} => {
- 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 => self.world = Some(World::from_default_size()),
- KeyCode::KeyP => {
- self.particle_manager
- .as_mut()
- .map(|pm| pm.particles = Vec::new());
- }
- KeyCode::KeyV => {
- if let Some(rbsm) = self.rb_sim_manager.as_mut() {
- let entity_ids: Vec<u32> = rbsm.rb_entities.keys().copied().collect();
+ 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 entity_ids: Vec<u32> =
+ sim.rb_manager.rb_entities.keys().copied().collect();
for entity_id in entity_ids {
- rbsm.destroy_rb_entity(entity_id);
+ sim.rb_manager.destroy_rb_entity(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,
+ _ => {}
}
- KeyCode::KeyP if pressed && !repeat => {
- if let Some(rbsm) = self.rb_sim_manager.as_mut() {
- for &id in rbsm.rb_entities.keys() {
- write_rb_entity_to_world(
- self.world.as_mut().unwrap(),
- rbsm,
- id,
- self.sim_seqno,
- );
- }
-
- let entity_ids: Vec<u32> = rbsm.rb_entities.keys().copied().collect();
- for entity_id in entity_ids {
- rbsm.destroy_rb_entity(entity_id);
- }
- }
- }
- KeyCode::Space if pressed => self.sim_paused = !self.sim_paused,
- KeyCode::KeyX if pressed => self.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, .. } => {
@@ -448,7 +312,7 @@ impl ApplicationHandler for App {
self.input.last_mouse_world_pos = Some(world_pos);
let ((cx, cy), (lx, ly)) =
- World::split_game_position(world_pos.0 as i32, world_pos.1 as i32);
+ 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));
}
@@ -492,61 +356,14 @@ impl ApplicationHandler for App {
self.diagnostics.fps = 1.0 / average_frame_time;
- // UPDATE
self.update(delta_time);
- // SIM UPDATE
- let secs_since_last_sim_update = (now - self.last_sim_update).as_secs_f32();
- let expected_secs_since_last_sim_update = 1.0 / SIM_FPS as f32;
-
- self.last_sim_update = now;
- if self.sim_paused && self.ignore_pause_next_tick {
- self.sim_update();
- } else if !self.sim_paused {
- self.sim_updates_due +=
- secs_since_last_sim_update / expected_secs_since_last_sim_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.sim_updates_due >= 1.0 && updates_done < 3 {
- self.sim_update();
- self.sim_updates_due -= 1.0;
- updates_done += 1;
- }
- self.sim_updates_due = self.sim_updates_due.min(3.0);
- }
-
- // PHYSICS UPDATE
- let secs_since_last_physics_update = (now - self.last_physics_update).as_secs_f32();
- let expected_secs_since_last_physics_update = 1.0 / PHYSICS_FPS as f32;
-
- self.last_physics_update = now;
- if self.sim_paused && self.ignore_pause_next_tick {
- self.physics_update(PHYSICS_DELTA_TIME);
- } else if !self.sim_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_updates_due -= 1.0;
- updates_done += 1;
- }
- self.physics_updates_due = self.physics_updates_due.min(3.0);
- }
-
- self.ignore_pause_next_tick = false;
-
if let Some(renderer_state) = &mut self.renderer_state
- && let Some(world) = &mut self.world
- && let Some(rb_sim_manager) = &mut self.rb_sim_manager
- && let Some(particle_manager) = &mut self.particle_manager
+ && let Some(sim) = &mut self.sim_manager
&& let Some(camera) = &mut self.camera
{
renderer_state.render(
- world,
- rb_sim_manager,
- particle_manager,
+ sim,
camera,
&mut self.config,
&self.diagnostics,