Merge branch 'better-physics' into 'master'

FPS independent physics

See merge request veloren/veloren!168
This commit is contained in:
Joshua Barretto
2019-06-05 19:51:18 +00:00
2 changed files with 65 additions and 43 deletions

View File

@ -17,6 +17,16 @@ use crate::{
// Basic ECS AI agent system // Basic ECS AI agent system
pub struct Sys; 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 { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
@ -73,51 +83,39 @@ impl<'a> System<'a> for Sys {
continue; continue;
} }
// Handle held-down control
let on_ground = terrain let on_ground = terrain
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32)) .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
.map(|vox| !vox.is_empty()) .map(|vox| !vox.is_empty())
.unwrap_or(false) .unwrap_or(false)
&& vel.0.z <= 0.0; && vel.0.z <= 0.0;
let (gliding, friction) = if on_ground { let gliding = glides.get(entity).is_some() && vel.0.z < 0.0;
// TODO: Don't hard-code this. let move_dir = if control.move_dir.magnitude() > 1.0 {
// Apply physics to the player: acceleration and non-linear deceleration. control.move_dir.normalized()
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)
} else { } else {
// TODO: Don't hard-code this. control.move_dir
// 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::<f32>::from(vel.0 * 0.15).magnitude().min(1.0);
(true, 0.008)
} else {
(false, 0.015)
}
}; };
// Friction if on_ground {
vel.0 -= Vec2::broadcast(dt.0) // Move player according to move_dir
* 50.0 if vel.0.magnitude() < HUMANOID_SPEED {
* vel.0.map(|e| { vel.0 += Vec2::broadcast(dt.0) * move_dir * HUMANOID_ACCEL;
(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);
// 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::<f32>::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 { if vel.0.magnitude_squared() != 0.0 {
ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0); ori.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
} }

View File

@ -14,6 +14,29 @@ use vek::*;
pub struct Sys; pub struct Sys;
const GRAVITY: f32 = 9.81 * 4.0; 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<f32>, damp: f32) -> Vec3<f32> {
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 { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
@ -31,18 +54,19 @@ impl<'a> System<'a> for Sys {
continue; continue;
} }
// Gravity let on_ground = terrain
vel.0.z = (vel.0.z - GRAVITY * dt.0).max(-50.0); .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 // Movement
pos.0 += vel.0 * dt.0; pos.0 += vel.0 * dt.0;
// Don't fall into the void. // Integrate forces
// TODO: This shouldn't be needed when we have proper physics and chunk loading. // Friction is assumed to be a constant dependent on location
if pos.0.z < 0.0 { let friction = 50.0 * if on_ground { FRIC_GROUND } else { FRIC_AIR };
pos.0.z = 0.0; vel.0 = integrate_forces(dt.0, vel.0, friction);
vel.0.z = 0.0;
}
// Basic collision with terrain // Basic collision with terrain
let mut i = 0.0; let mut i = 0.0;