From 6ccae593d3ef782637f24ee6cd57c647d7c0defd Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Sun, 9 Jan 2022 14:13:28 +0000 Subject: [PATCH] :recycle: refactor: extract logic step function --- src/bin/platformer/graphics.rs | 10 +- src/bin/platformer/main.rs | 252 +++++++++++++++++++-------------- src/physics.rs | 2 +- 3 files changed, 151 insertions(+), 113 deletions(-) diff --git a/src/bin/platformer/graphics.rs b/src/bin/platformer/graphics.rs index 31ed7f5..a3e1fea 100644 --- a/src/bin/platformer/graphics.rs +++ b/src/bin/platformer/graphics.rs @@ -216,7 +216,7 @@ impl Graphics { ) = camera.transform.clone ().decomposed (); let cam_trans = Vec3::from (cam_trans); - let cam_trans = Vec3::new (cam_trans.x.max (state.player.pos.x + 4.0), cam_trans.y, cam_trans.z); + let cam_trans = Vec3::new (cam_trans.x.max (state.logic.player.pos.x + 4.0), cam_trans.y, cam_trans.z); let view_mat = Mat4::from_quat (Quat::from_array (cam_rot).inverse ()) * @@ -244,7 +244,7 @@ impl Graphics { self.texture_earth.bind (); let mvp = view_mat * - Mat4::from_translation (state.player.pos) * + Mat4::from_translation (state.logic.player.pos) * Mat4::from_scale ((0.5, 0.5, 0.5).into ()); glezz::uniform_matrix_4fv (unis [&u::MVP], &mvp); glezz::uniform_3fv (unis [&u::ALBEDO], &white); @@ -340,9 +340,9 @@ impl Graphics { if true { // Raycast for player shadow let coll = opengl_rust::physics::get_candidate ( - &state.phys_tris, &state.aabbs, - state.player.pos, - state.player.pos + Vec3::new (0.0, 0.0, -100.0), + &state.static_level.tris, &[], + state.logic.player.pos, + state.logic.player.pos + Vec3::new (0.0, 0.0, -100.0), 0.0 ); diff --git a/src/bin/platformer/main.rs b/src/bin/platformer/main.rs index c8e97f5..c5b5824 100644 --- a/src/bin/platformer/main.rs +++ b/src/bin/platformer/main.rs @@ -22,19 +22,148 @@ mod graphics; mod virtual_gamepad; use graphics::Graphics; +use virtual_gamepad::VirtualGamepad; -#[derive (Default)] pub struct GameState { - player: PhysicsBody, - aabbs: Vec , - phys_tris: Vec , + logic: LogicState, + static_level: StaticLevel, } impl GameState { + fn step (&mut self, phys_params: &opengl_rust::physics::Params, p_gp: VirtualGamepad) -> LogicStepOutput + { + self.logic.step (&self.static_level, phys_params, p_gp) + } +} + +struct StaticLevel { + tris: Vec , +} + +#[derive (Clone, Default)] +struct LogicState { + player: PhysicsBody, + player_jump_vec: Option , +} + +#[derive (Clone, Copy, Default)] +struct LogicStepOutput { + reset_level: bool, +} + +impl LogicState { fn reset_level (&mut self, level: &LoadedLevel) { self.player = Default::default (); self.player.pos = level.player_spawn; } + + fn step (&mut self, static_level: &StaticLevel, phys_params: &opengl_rust::physics::Params, p_gp: VirtualGamepad) -> LogicStepOutput + { + let player_acc = 1.0; + let player_acc_air = 0.125; + let player_max_speed = 4.0; + let player_max_speed_air = 8.0; + let player_jump_speed = 12.0; + let kill_z = -3.0; + + let mut output = LogicStepOutput::default (); + let mut wanted_dir = Vec3::default (); + + if p_gp.d_left.any_press () { + wanted_dir.x -= 1.0; + } + if p_gp.d_right.any_press () { + wanted_dir.x += 1.0; + } + if p_gp.d_up.any_press () { + wanted_dir.y += 1.0; + } + if p_gp.d_down.any_press () { + wanted_dir.y -= 1.0; + } + + let wanted_dir = if wanted_dir.length_squared () >= 1.0 { + wanted_dir.normalize () + } + else { + wanted_dir + }; + + let wanted_dir = wanted_dir; + + let old_vel = self.player.vel; + let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0); + + let new_vel_2 = match self.player_jump_vec.as_ref () { + Some (v) => { + // Ground + let acc = player_acc * v.z * v.z; + let wanted_vel = wanted_dir * player_max_speed; + let diff = wanted_vel - old_vel_2; + + if diff.length_squared () < acc * acc { + // We're near the wanted velocity, so snap to it + wanted_vel + } + else { + // We're not near the wanted velocity, so accelerate + old_vel_2 + diff.normalize_or_zero () * acc + } + }, + // Air + None => { + let proposed_vel = old_vel_2 + wanted_dir * player_acc_air; + + if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air { + // Air control is normal below player_max_speed + proposed_vel + } + else { + // If the player's input would push them beyond player_max_speed, + // apply drag to preserve overall energy + proposed_vel * old_vel_2.length () / proposed_vel.length () + } + }, + }; + + self.player.vel = new_vel_2; + self.player.vel.z = old_vel.z; + + // dbg! (self.player.vel); + + if p_gp.jump.pressed { + if let Some (normal) = self.player_jump_vec.clone () { + self.player.vel.z = 0.0; + self.player.vel += normal * player_jump_speed; + } + } + + let phys_result = opengl_rust::physics::step (&phys_params, &static_level.tris, &[], 0.5, &self.player); + + self.player = phys_result.body; + if self.player.pos.z < kill_z { + output.reset_level = true; + } + + // tracing::debug! ("player pos: {}", self.player.pos); + + self.player_jump_vec = None; + for normal in &phys_result.normals_hit { + self.player_jump_vec = Some (match self.player_jump_vec { + None => *normal, + Some (old) => { + if normal.z > old.z { + *normal + } + else { + old + } + }, + }); + } + + output + } } #[tokio::main] @@ -161,23 +290,19 @@ async fn main () -> Result <()> { let mut graphics = Graphics::new (); let mut gl_state = Default::default (); - let mut game_state = GameState::default (); + let mut game_state = GameState { + logic: Default::default (), + static_level: StaticLevel { + tris: phys_tris, + }, + }; let phys_params = opengl_rust::physics::Params { dt: 1.0 / 60.0, gravity: (0.0, 0.0, -0.5).into (), margin: 0.00125, }; - let player_acc = 1.0; - let player_acc_air = 0.125; - let player_max_speed = 4.0; - let player_max_speed_air = 8.0; - let player_jump_speed = 12.0; - let kill_z = -3.0; - let mut player_jump_vec: Option = None; - - game_state.reset_level (&level); - game_state.phys_tris = phys_tris; + game_state.logic.reset_level (&level); let mut next_upf_print = 60; let mut last_upf_instant = Instant::now (); @@ -193,7 +318,7 @@ async fn main () -> Result <()> { break 'running }, Event::KeyDown { keycode: Some (Keycode::R), .. } => { - game_state.reset_level (&level); + game_state.logic.reset_level (&level); }, Event::KeyDown { scancode: Some (Scancode::Space), repeat: false, .. } => { player_gamepad.jump.pressed = true; @@ -237,99 +362,12 @@ async fn main () -> Result <()> { let p_gp = player_gamepad; - let mut wanted_dir = Vec3::default (); - - if p_gp.d_left.any_press () { - wanted_dir.x -= 1.0; - } - if p_gp.d_right.any_press () { - wanted_dir.x += 1.0; - } - if p_gp.d_up.any_press () { - wanted_dir.y += 1.0; - } - if p_gp.d_down.any_press () { - wanted_dir.y -= 1.0; + let logic_step_output = game_state.step (&phys_params, p_gp); + if logic_step_output.reset_level { + game_state.logic.reset_level (&level); } - let wanted_dir = if wanted_dir.length_squared () >= 1.0 { - wanted_dir.normalize () - } - else { - wanted_dir - }; - - let old_vel = game_state.player.vel; - let old_vel_2 = old_vel * Vec3::new (1.0, 1.0, 0.0); - - let new_vel_2 = match player_jump_vec.as_ref () { - Some (v) => { - // Ground - let acc = player_acc * v.z * v.z; - let wanted_vel = wanted_dir * player_max_speed; - let diff = wanted_vel - old_vel_2; - - if diff.length_squared () < acc * acc { - // We're near the wanted velocity, so snap to it - wanted_vel - } - else { - // We're not near the wanted velocity, so accelerate - old_vel_2 + diff.normalize_or_zero () * acc - } - }, - // Air - None => { - let proposed_vel = old_vel_2 + wanted_dir * player_acc_air; - - if old_vel_2.length_squared () < player_max_speed_air * player_max_speed_air { - // Air control is normal below player_max_speed - proposed_vel - } - else { - // If the player's input would push them beyond player_max_speed, - // apply drag to preserve overall energy - proposed_vel * old_vel_2.length () / proposed_vel.length () - } - }, - }; - - game_state.player.vel = new_vel_2; - game_state.player.vel.z = old_vel.z; - - // dbg! (game_state.player.vel); - - if p_gp.jump.pressed { - if let Some (normal) = player_jump_vec.clone () { - game_state.player.vel.z = 0.0; - game_state.player.vel += normal * player_jump_speed; - } - } - - let phys_result = opengl_rust::physics::step (&phys_params, &game_state.phys_tris, &[], 0.5, &game_state.player); - - game_state.player = phys_result.body; - if game_state.player.pos.z < kill_z { - game_state.reset_level (&level); - } - // tracing::debug! ("player pos: {}", game_state.player.pos); - - player_jump_vec = None; - for normal in &phys_result.normals_hit { - player_jump_vec = Some (match player_jump_vec { - None => *normal, - Some (old) => { - if normal.z > old.z { - *normal - } - else { - old - } - }, - }); - } - - // dbg! (game_state.player.pos); + // dbg! (game_state.logic.player.pos); window.gl_make_current (&gl_ctx).unwrap (); diff --git a/src/physics.rs b/src/physics.rs index 46b5c60..3accd8c 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,7 +1,7 @@ use glam::{Vec2, Vec3}; use partial_min_max::{min, max}; -#[derive (Debug, Default, PartialEq)] +#[derive (Clone, Copy, Debug, Default, PartialEq)] pub struct PhysicsBody { pub pos: Vec3, pub vel: Vec3,