diff --git a/src/bin/platformer/logic.rs b/src/bin/platformer/logic.rs new file mode 100644 index 0000000..a6ce41e --- /dev/null +++ b/src/bin/platformer/logic.rs @@ -0,0 +1,136 @@ +use opengl_rust::{ + prelude::*, + physics::PhysicsBody, +}; + +use crate::{ + LoadedLevel, + StaticLevel, + VirtualGamepad, +}; + +#[derive (Clone, Default)] +pub struct LogicState { + pub player: PhysicsBody, + player_jump_vec: Option , +} + +#[derive (Clone, Copy, Default)] +pub struct LogicStepOutput { + pub reset_level: bool, +} + +impl LogicState { + pub fn reset_level (&mut self, level: &LoadedLevel) { + self.player = Default::default (); + self.player.pos = level.player_spawn; + } + + pub 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 + } +} diff --git a/src/bin/platformer/main.rs b/src/bin/platformer/main.rs index a67937b..1daf78f 100644 --- a/src/bin/platformer/main.rs +++ b/src/bin/platformer/main.rs @@ -6,15 +6,16 @@ use anyhow::Result; use opengl_rust::{ prelude::*, - physics::PhysicsBody, }; mod graphics; mod level_loader; +mod logic; mod virtual_gamepad; use graphics::Graphics; use level_loader::LoadedLevel; +use logic::LogicState; use virtual_gamepad::VirtualGamepad; pub struct GameState { @@ -26,132 +27,6 @@ pub struct StaticLevel { tris: Vec , } -#[derive (Clone, Default)] -pub 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] async fn main () -> Result <()> { tracing_subscriber::fmt::fmt ()