diff --git a/common/src/sys/inputs.rs b/common/src/sys/inputs.rs index 7e1f1216ee..a1df384374 100644 --- a/common/src/sys/inputs.rs +++ b/common/src/sys/inputs.rs @@ -17,6 +17,16 @@ use crate::{ // Basic ECS AI agent system pub struct Sys; +const HUMANOID_ACCEL: f32 = 100.0; +const HUMANOID_SPEED: f32 = 500.0; +const HUMANOID_AIR_ACCEL: f32 = 10.0; +const HUMANOID_AIR_SPEED: f32 = 100.0; +const HUMANOID_JUMP_ACCEL: f32 = 16.0; +const GLIDE_ACCEL: f32 = 15.0; +const GLIDE_SPEED: f32 = 45.0; +// Gravity is 9.81 * 4, so this makes gravity equal to .15 +const GLIDE_ANTIGRAV: f32 = 9.81 * 3.95; + impl<'a> System<'a> for Sys { type SystemData = ( Entities<'a>, @@ -73,51 +83,39 @@ impl<'a> System<'a> for Sys { continue; } - // Handle held-down control let on_ground = terrain .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) .map(|vox| !vox.is_empty()) .unwrap_or(false) && vel.0.z <= 0.0; - let (gliding, friction) = if on_ground { - // TODO: Don't hard-code this. - // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 200.0; - - if jumps.get(entity).is_some() { - vel.0.z += 16.0; - jumps.remove(entity); - } - - (false, 0.15) + let gliding = glides.get(entity).is_some() && vel.0.z < 0.0; + let move_dir = if control.move_dir.magnitude() > 1.0 { + control.move_dir.normalized() } else { - // TODO: Don't hard-code this. - // Apply physics to the player: acceleration and non-linear deceleration. - vel.0 += Vec2::broadcast(dt.0) * control.move_dir * 10.0; - - if glides.get(entity).is_some() && vel.0.z < 0.0 { - // TODO: Don't hard-code this. - let anti_grav = 9.81 * 3.95 + vel.0.z.powf(2.0) * 0.2; - vel.0.z += - dt.0 * anti_grav * Vec2::::from(vel.0 * 0.15).magnitude().min(1.0); - - (true, 0.008) - } else { - (false, 0.015) - } + control.move_dir }; - // Friction - vel.0 -= Vec2::broadcast(dt.0) - * 50.0 - * vel.0.map(|e| { - (e.abs() * friction * (vel.0.magnitude() * 0.1 + 0.5)) - .min(e.abs() * dt.0 * 50.0) - .copysign(e) - }) - * Vec3::new(1.0, 1.0, 0.0); + if on_ground { + // Move player according to move_dir + if vel.0.magnitude() < HUMANOID_SPEED { + vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_ACCEL; + } + // Jump + if jumps.get(entity).is_some() && vel.0.z <= 0.0 { + vel.0.z = HUMANOID_JUMP_ACCEL; + jumps.remove(entity); + } + } else if gliding && vel.0.magnitude() < GLIDE_SPEED { + let anti_grav = GLIDE_ANTIGRAV + vel.0.z.powf(2.0) * 0.2; + vel.0.z += dt.0 * anti_grav * Vec2::::from(vel.0 * 0.15).magnitude().min(1.0); + vel.0 += Vec2::broadcast(dt.0) * move_dir * GLIDE_ACCEL; + } else if vel.0.magnitude() < HUMANOID_AIR_SPEED { + vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_AIR_ACCEL; + } + + // Set direction based on velocity if vel.0.magnitude_squared() != 0.0 { ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); } diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs index 8325431c68..796b3310e2 100644 --- a/common/src/sys/phys.rs +++ b/common/src/sys/phys.rs @@ -14,6 +14,29 @@ use vek::*; pub struct Sys; const GRAVITY: f32 = 9.81 * 4.0; +const FRIC_GROUND: f32 = 0.15; +const FRIC_AIR: f32 = 0.015; + +// Integrates forces, calculates the new velocity based off of the old velocity +// dt = delta time +// lv = linear velocity +// damp = linear damping +// Friction is a type of damping. +fn integrate_forces(dt: f32, mut lv: Vec3, damp: f32) -> Vec3 { + lv.z -= (GRAVITY * dt).max(-50.0); + + let mut linear_damp = 1.0 - dt * damp; + + if linear_damp < 0.0 + // reached zero in the given time + { + linear_damp = 0.0; + } + + lv *= linear_damp; + + lv +} impl<'a> System<'a> for Sys { type SystemData = ( @@ -31,18 +54,19 @@ impl<'a> System<'a> for Sys { continue; } - // Gravity - vel.0.z = (vel.0.z - GRAVITY * dt.0).max(-50.0); + let on_ground = terrain + .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) + .map(|vox| !vox.is_empty()) + .unwrap_or(false) + && vel.0.z <= 0.0; // Movement pos.0 += vel.0 * dt.0; - // Don't fall into the void. - // TODO: This shouldn't be needed when we have proper physics and chunk loading. - if pos.0.z < 0.0 { - pos.0.z = 0.0; - vel.0.z = 0.0; - } + // Integrate forces + // Friction is assumed to be a constant dependent on location + let friction = 50.0 * if on_ground { FRIC_GROUND } else { FRIC_AIR }; + vel.0 = integrate_forces(dt.0, vel.0, friction); // Basic collision with terrain let mut i = 0.0;