diff options
| -rw-r--r-- | src/camera.rs | 153 | ||||
| -rw-r--r-- | src/input.rs | 15 | ||||
| -rw-r--r-- | src/main.rs | 109 | ||||
| -rw-r--r-- | src/renderer/mod.rs | 10 |
4 files changed, 171 insertions, 116 deletions
diff --git a/src/camera.rs b/src/camera.rs index 3de7ba7..576f12c 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,6 +1,9 @@ +use glam::{IVec2, Vec2}; + use crate::{ config::CAMERA_MOVEMENT_SPEED, input::{Input, InputManager}, + sim::{entity::EntityId, sim_manager::SimManager}, }; #[repr(C)] @@ -12,82 +15,122 @@ pub struct CameraUniform { pub struct Camera { pub zoom: f32, - pub centre: (f32, f32), - screen_size: (i32, i32), + pub centre: Vec2, + screen_size: IVec2, } impl Camera { - fn scale(&self) -> (f32, f32) { - let half_w = self.zoom * self.screen_size.0 as f32 / 2.0; - let half_h = self.zoom * self.screen_size.1 as f32 / 2.0; - (1.0 / half_w, -1.0 / half_h) - } - - // xl, xu, yl, yu - pub fn viewport_bounds_world(&self) -> (f32, f32, f32, f32) { - let (xl, yl) = self.screen_position_to_world(0.0, 0.0); - let (xu, yu) = - self.screen_position_to_world(self.screen_size.0 as f32, self.screen_size.1 as f32); - (xl, xu, yl, yu) + fn scale(&self) -> Vec2 { + let half = self.zoom * self.screen_size.as_vec2() / 2.0; + Vec2::new(1.0 / half.x, -1.0 / half.y) } - pub fn handle_camera_input(&mut self, input_manager: &InputManager, delta_time: f32) { - // wasd movement - let x: f32 = if input_manager.held(Input::CameraLeft) { - -1.0 - } else if input_manager.held(Input::CameraRight) { - 1.0 - } else { - 0.0 - }; - let y: f32 = if input_manager.held(Input::CameraDown) { - 1.0 - } else if input_manager.held(Input::CameraUp) { - -1.0 - } else { - 0.0 - }; - - if x == 0.0 && y == 0.0 { - return; - } - - let magnitude = (x.powi(2) + y.powi(2)).sqrt(); - let adjusted_x = x / magnitude * self.zoom * CAMERA_MOVEMENT_SPEED * delta_time; - let adjusted_y = y / magnitude * self.zoom * CAMERA_MOVEMENT_SPEED * delta_time; - - self.centre.0 += adjusted_x; - self.centre.1 += adjusted_y; + // (lower, upper) + pub fn viewport_bounds_world(&self) -> (Vec2, Vec2) { + let lower = self.screen_position_to_world(Vec2::ZERO); + let upper = self.screen_position_to_world(self.screen_size.as_vec2()); + (lower, upper) } - pub fn screen_position_to_world(&self, x: f32, y: f32) -> (f32, f32) { - let (scale_x, scale_y) = self.scale(); - - let ndc_x = x / self.screen_size.0 as f32 * 2.0 - 1.0; - let world_x = ndc_x / scale_x + self.centre.0; - let ndc_y = y / self.screen_size.1 as f32 * 2.0 - 1.0; - let world_y = ndc_y / -scale_y + self.centre.1; + pub fn screen_position_to_world(&self, pos: Vec2) -> Vec2 { + let scale = self.scale(); + let ndc = pos / self.screen_size.as_vec2() * 2.0 - 1.0; + let world = Vec2::new( + ndc.x / scale.x + self.centre.x, + ndc.y / -scale.y + self.centre.y, + ); - (world_x, world_y) + world } pub fn to_uniform(&self) -> CameraUniform { - let (scale_x, scale_y) = self.scale(); CameraUniform { - scale: [scale_x, scale_y], - centre: [self.centre.0, self.centre.1], + scale: self.scale().to_array(), + centre: self.centre.to_array(), } } - pub fn resize(&mut self, screen_size: (i32, i32)) { + pub fn resize(&mut self, screen_size: IVec2) { self.screen_size = screen_size; } - pub fn new(screen_size: (i32, i32)) -> Self { + pub fn new(screen_size: IVec2) -> Self { Camera { zoom: 0.12, - centre: (0.0, 0.0), + centre: Vec2::ZERO, screen_size, } } } + +pub enum CameraControllerMode { + Free, + TrackEntity(EntityId), +} + +pub struct CameraController { + camera: Camera, + mode: CameraControllerMode, +} + +impl CameraController { + pub fn track_entity(&mut self, entity_id: EntityId) { + self.mode = CameraControllerMode::TrackEntity(entity_id); + } + + pub fn free_camera(&mut self) { + self.mode = CameraControllerMode::Free; + } + + pub fn camera(&self) -> &Camera { + &self.camera + } + + pub fn camera_mut(&mut self) -> &mut Camera { + &mut self.camera + } + + pub fn update(&mut self, input_manager: &InputManager, sim: &SimManager, delta_time: f32) { + match self.mode { + CameraControllerMode::Free => { + let x: f32 = if input_manager.held(Input::CameraLeft) { + -1.0 + } else if input_manager.held(Input::CameraRight) { + 1.0 + } else { + 0.0 + }; + let y: f32 = if input_manager.held(Input::CameraDown) { + 1.0 + } else if input_manager.held(Input::CameraUp) { + -1.0 + } else { + 0.0 + }; + + if x == 0.0 && y == 0.0 { + return; + } + + let magnitude = (x.powi(2) + y.powi(2)).sqrt(); + let adjusted_x = + x / magnitude * self.camera.zoom * CAMERA_MOVEMENT_SPEED * delta_time; + let adjusted_y = + y / magnitude * self.camera.zoom * CAMERA_MOVEMENT_SPEED * delta_time; + + self.camera.centre += Vec2::new(adjusted_x, adjusted_y); + } + CameraControllerMode::TrackEntity(entity_id) => { + if let Some(entity) = sim.entities.get(&entity_id) { + let (position, _) = entity.data._transform(&sim.rb_manager).unwrap(); + self.camera.centre = position; + } + } + } + } + + pub fn new(screen_size: IVec2, mode: CameraControllerMode) -> Self { + let camera = Camera::new(screen_size); + CameraController { camera, mode } + } +} diff --git a/src/input.rs b/src/input.rs index e795a61..108514e 100644 --- a/src/input.rs +++ b/src/input.rs @@ -14,6 +14,8 @@ pub enum Input { Down, Right, + // camera + FreeCamera, CameraUp, CameraLeft, CameraDown, @@ -39,18 +41,19 @@ pub enum Input { Action6, } -const INPUT_VAR_LEN: usize = 21; +const INPUT_VAR_LEN: usize = 22; const KEYMAP: [(KeyCode, Input); INPUT_VAR_LEN] = [ (KeyCode::KeyW, Input::Up), (KeyCode::KeyA, Input::Left), (KeyCode::KeyS, Input::Down), (KeyCode::KeyD, Input::Right), + (KeyCode::KeyZ, Input::FreeCamera), (KeyCode::ArrowUp, Input::CameraUp), (KeyCode::ArrowLeft, Input::CameraLeft), (KeyCode::ArrowDown, Input::CameraDown), (KeyCode::ArrowRight, Input::CameraRight), - (KeyCode::Space, Input::Pause), + (KeyCode::KeyU, Input::Pause), (KeyCode::KeyX, Input::Step), (KeyCode::KeyC, Input::ClearGrid), (KeyCode::KeyV, Input::ClearEntities), @@ -108,14 +111,14 @@ impl InputManager { } } WindowEvent::CursorMoved { position, .. } => { - let (wp_x, wp_y) = - camera.screen_position_to_world(position.x as f32, position.y as f32); + let wp = camera + .screen_position_to_world(Vec2::new(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); + 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.world_mouse_pos = wp; self.chunk_mouse_pos = IVec2::new(cx, cy); self.local_mouse_pos = IVec2::new(lx as i32, ly as i32); } diff --git a/src/main.rs b/src/main.rs index 4d62f8c..9455ac6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ mod sprite_loader; mod vfx; use futures::executor; +use glam::IVec2; use std::{collections::VecDeque, sync::Arc, time::Instant}; use winit::{ application::ApplicationHandler, @@ -18,7 +19,7 @@ use winit::{ }; use crate::{ - camera::Camera, + camera::{Camera, CameraController}, config::WINDOW_TITLE, content::{ entities::{ @@ -35,7 +36,7 @@ use crate::{ }, proc_gen::TilesetWorldGenerator, renderer::RendererState, - sim::{entity::EntityDef, rb_manager::DebugRenderMode, sim_manager::SimManager}, + sim::{rb_manager::DebugRenderMode, sim_manager::SimManager}, vfx::VfxManager, }; @@ -66,9 +67,9 @@ struct App { // game input_manager: InputManager, - camera: Option<Camera>, - vfx_manager: Option<VfxManager>, - sim_manager: Option<SimManager>, + camera_controller: Option<CameraController>, + vfx_manager: VfxManager, + sim_manager: SimManager, world_generator: TilesetWorldGenerator, // renderer @@ -84,43 +85,47 @@ impl App { // delta time is the real seconds elapsed since the last time this was called fn update(&mut self, delta_time: f32) { // apply inputs - if let Some(camera) = &mut self.camera { - camera.handle_camera_input(&self.input_manager, delta_time) + if let Some(camera_controller) = &mut self.camera_controller { + camera_controller.update(&self.input_manager, &self.sim_manager, delta_time); } - if let Some(sim) = &mut self.sim_manager - && let Some(vfx_manager) = &mut self.vfx_manager - { - // --TEST SPAWNING-- - if self.input_manager.pressed(Input::Action1) { - sim.create_entity(entity_cube_def( - self.input_manager.world_mouse_pos, - self.config.dropper_material, - )); - } - - if self.input_manager.pressed(Input::Grenade) { - sim.create_entity(entity_grenade_def(self.input_manager.world_mouse_pos, 3.0)); - } + // --TEST SPAWNING-- + if self.input_manager.pressed(Input::Action1) { + self.sim_manager.create_entity(entity_cube_def( + self.input_manager.world_mouse_pos, + self.config.dropper_material, + )); + } - if self.input_manager.pressed(Input::Tnt) { - sim.create_entity(entity_tnt_def(self.input_manager.world_mouse_pos)); - } + if self.input_manager.pressed(Input::Grenade) { + self.sim_manager + .create_entity(entity_grenade_def(self.input_manager.world_mouse_pos, 3.0)); + } - if self.input_manager.pressed(Input::Action5) { - sim.create_entity(entity_wizard_def(self.input_manager.world_mouse_pos)); - } + if self.input_manager.pressed(Input::Tnt) { + self.sim_manager + .create_entity(entity_tnt_def(self.input_manager.world_mouse_pos)); + } - if self.input_manager.pressed(Input::Action3) { - sim.create_entity(entity_bullet_emitter_def( - self.input_manager.world_mouse_pos, - 3.0, - )); - } + if self.input_manager.pressed(Input::Action5) { + self.sim_manager + .create_entity(entity_wizard_def(self.input_manager.world_mouse_pos)); + } - sim.update(vfx_manager, &self.config, &self.input_manager, delta_time); - self.input_manager.reset_for_frame(); + if self.input_manager.pressed(Input::Action3) { + self.sim_manager.create_entity(entity_bullet_emitter_def( + self.input_manager.world_mouse_pos, + 3.0, + )); } + + self.sim_manager.update( + &mut self.vfx_manager, + &self.config, + &self.input_manager, + delta_time, + ); + self.input_manager.reset_for_frame(); } } @@ -141,10 +146,10 @@ impl Default for App { input_manager: InputManager::new(), - camera: None, + camera_controller: None, - vfx_manager: Some(VfxManager::new()), - sim_manager: Some(SimManager::new()), + vfx_manager: VfxManager::new(), + sim_manager: SimManager::new(), world_generator: TilesetWorldGenerator::new( "assets/tilesets/tileset1", Box::new(MinesBiome::new()), @@ -177,7 +182,10 @@ impl ApplicationHandler for App { self.renderer_state = Some(executor::block_on(RendererState::new(window.clone()))); let size = window.inner_size(); - self.camera = Some(Camera::new((size.width as i32, size.height as i32))); + self.camera_controller = Some(CameraController::new( + IVec2::new(size.width as i32, size.height as i32), + camera::CameraControllerMode::Free, + )); } fn window_event( @@ -196,17 +204,20 @@ impl ApplicationHandler for App { } } - if let Some(camera) = &self.camera { - self.input_manager.apply_event(&event, camera); + if let Some(camera_controller) = &self.camera_controller { + self.input_manager + .apply_event(&event, camera_controller.camera()); } match event { WindowEvent::Resized(size) => { if let Some(renderer_state) = &mut self.renderer_state - && let Some(camera) = &mut self.camera + && let Some(camera_controller) = &mut self.camera_controller { renderer_state.resize(size.width, size.height); - camera.resize((size.width as i32, size.height as i32)); + camera_controller + .camera_mut() + .resize(IVec2::new(size.width as i32, size.height as i32)); } } WindowEvent::CloseRequested => { @@ -236,21 +247,19 @@ impl ApplicationHandler for App { self.update(delta_time); if let Some(renderer_state) = &mut self.renderer_state - && let Some(sim) = &mut self.sim_manager - && let Some(vfx) = &mut self.vfx_manager - && let Some(camera) = &mut self.camera + && let Some(camera_controller) = &mut self.camera_controller { renderer_state.render( - sim, - vfx, - camera, + &mut self.sim_manager, + &self.vfx_manager, + camera_controller.camera_mut(), &mut self.config, &self.diagnostics, &self.input_manager, &self.world_generator, ); - vfx.after_render(delta_time); + self.vfx_manager.after_render(delta_time); } } _ => {} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index b806b13..2deb278 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -392,7 +392,7 @@ impl RendererState { let entity_capacity = 2048; let instance_buffer = create_instance_buffer(&device, CHUNK_SLOTS + entity_capacity); - let cell_buffer = create_cell_buffer(&device, entity_capacity + CHUNK_SLOTS ); + let cell_buffer = create_cell_buffer(&device, entity_capacity + CHUNK_SLOTS); let instance_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { label: None, @@ -920,11 +920,11 @@ impl RendererState { { puffin::profile_scope!("Build instances"); - let (xl, xu, yl, yu) = camera.viewport_bounds_world(); + let (lower, upper) = camera.viewport_bounds_world(); let ((cxl, cyl), _) = - CellManager::split_game_position(xl.floor() as i32, yl.floor() as i32); + CellManager::split_game_position(lower.x.floor() as i32, lower.y.floor() as i32); let ((cxu, cyu), _) = - CellManager::split_game_position(xu.floor() as i32, yu.floor() as i32); + CellManager::split_game_position(upper.x.floor() as i32, upper.y.floor() as i32); let half_size = [CHUNK_SIZE as f32 / 2.0, CHUNK_SIZE as f32 / 2.0]; let dims = [CHUNK_SIZE as u32, CHUNK_SIZE as u32]; @@ -985,7 +985,7 @@ impl RendererState { self.instance_buffer = create_instance_buffer(&self.device, self.entity_capacity + CHUNK_SLOTS); self.cell_buffer = - create_cell_buffer(&self.device, ((CHUNK_SLOTS + self.entity_capacity))); + create_cell_buffer(&self.device, CHUNK_SLOTS + self.entity_capacity); } self.queue |
