Properly propagate velocity steps during airship collision to avoid falling through airships

This commit is contained in:
Joshua Barretto 2021-03-13 15:36:56 +00:00 committed by Avi Weinstock
parent 26c9fd63ae
commit f768c3f853
3 changed files with 34 additions and 32 deletions

View File

@ -9,7 +9,7 @@ use vek::Vec2;
// Gravity is 9.81 * 4, so this makes gravity equal to .15 // Gravity is 9.81 * 4, so this makes gravity equal to .15
const GLIDE_ANTIGRAV: f32 = crate::consts::GRAVITY * 0.90; const GLIDE_ANTIGRAV: f32 = crate::consts::GRAVITY * 0.90;
const GLIDE_ACCEL: f32 = 8.0; const GLIDE_ACCEL: f32 = 6.0;
const GLIDE_SPEED: f32 = 16.0; const GLIDE_SPEED: f32 = 16.0;
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)] #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize, Eq, Hash)]
@ -40,13 +40,7 @@ impl CharacterBehavior for Data {
handle_climb(&data, &mut update); handle_climb(&data, &mut update);
// Move player according to movement direction vector // Move player according to movement direction vector
update.vel.0 += Vec2::broadcast(data.dt.0) update.vel.0 += Vec2::broadcast(data.dt.0) * data.inputs.move_dir * GLIDE_ACCEL;
* data.inputs.move_dir
* if data.vel.0.magnitude_squared() < GLIDE_SPEED.powi(2) {
GLIDE_ACCEL
} else {
0.0
};
// Determine orientation vector from movement direction vector // Determine orientation vector from movement direction vector
let horiz_vel = Vec2::<f32>::from(update.vel.0); let horiz_vel = Vec2::<f32>::from(update.vel.0);
@ -56,7 +50,7 @@ impl CharacterBehavior for Data {
// Apply Glide antigrav lift // Apply Glide antigrav lift
let horiz_speed_sq = horiz_vel.magnitude_squared(); let horiz_speed_sq = horiz_vel.magnitude_squared();
if horiz_speed_sq < GLIDE_SPEED.powi(2) && update.vel.0.z < 0.0 { if update.vel.0.z < 0.0 {
let lift = (GLIDE_ANTIGRAV + update.vel.0.z.powi(2) * 0.15) let lift = (GLIDE_ANTIGRAV + update.vel.0.z.powi(2) * 0.15)
* (horiz_speed_sq * f32::powf(0.075, 2.0)).clamp(0.2, 1.0); * (horiz_speed_sq * f32::powf(0.075, 2.0)).clamp(0.2, 1.0);

View File

@ -17,8 +17,8 @@ use std::time::Duration;
use vek::*; use vek::*;
pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0; pub const MOVEMENT_THRESHOLD_VEL: f32 = 3.0;
const BASE_HUMANOID_AIR_ACCEL: f32 = 0.5; const BASE_HUMANOID_AIR_ACCEL: f32 = 2.0;
const BASE_FLIGHT_ACCEL: f32 = 3.5; const BASE_FLIGHT_ACCEL: f32 = 2.0;
const BASE_HUMANOID_WATER_ACCEL: f32 = 150.0; const BASE_HUMANOID_WATER_ACCEL: f32 = 150.0;
const BASE_HUMANOID_WATER_SPEED: f32 = 180.0; const BASE_HUMANOID_WATER_SPEED: f32 = 180.0;
// const BASE_HUMANOID_CLIMB_ACCEL: f32 = 10.0; // const BASE_HUMANOID_CLIMB_ACCEL: f32 = 10.0;

View File

@ -411,7 +411,6 @@ impl<'a> PhysicsData<'a> {
)| { )| {
// defer the writes of positions to allow an inner loop over terrain-like // defer the writes of positions to allow an inner loop over terrain-like
// entities // entities
let old_pos = *pos;
let mut pos = *pos; let mut pos = *pos;
let mut vel = *vel; let mut vel = *vel;
if sticky.is_some() && physics_state.on_surface().is_some() { if sticky.is_some() && physics_state.on_surface().is_some() {
@ -469,6 +468,8 @@ impl<'a> PhysicsData<'a> {
Vec3::zero() Vec3::zero()
}; };
let mut tgt_pos = pos.0 + pos_delta;
let was_on_ground = physics_state.on_ground; let was_on_ground = physics_state.on_ground;
match &collider { match &collider {
@ -481,21 +482,22 @@ impl<'a> PhysicsData<'a> {
let radius = collider.get_radius() * scale * 0.1; let radius = collider.get_radius() * scale * 0.1;
let (z_min, z_max) = collider.get_z_limits(scale); let (z_min, z_max) = collider.get_z_limits(scale);
let mut cpos = pos;
let cylinder = (radius, z_min, z_max); let cylinder = (radius, z_min, z_max);
cylinder_voxel_collision( cylinder_voxel_collision(
cylinder, cylinder,
&*read.terrain, &*read.terrain,
entity, entity,
&mut pos, &mut cpos,
pos_delta, tgt_pos,
&mut vel, &mut vel,
&mut physics_state, &mut physics_state,
Vec3::zero(), Vec3::zero(),
&read.dt, &read.dt,
true,
was_on_ground, was_on_ground,
|entity, vel| land_on_grounds.push((entity, vel)), |entity, vel| land_on_grounds.push((entity, vel)),
); );
tgt_pos = cpos.0;
}, },
Collider::Box { Collider::Box {
radius, radius,
@ -508,20 +510,21 @@ impl<'a> PhysicsData<'a> {
let z_max = z_max.clamped(1.2, 1.95) * scale; let z_max = z_max.clamped(1.2, 1.95) * scale;
let cylinder = (radius, z_min, z_max); let cylinder = (radius, z_min, z_max);
let mut cpos = pos;
cylinder_voxel_collision( cylinder_voxel_collision(
cylinder, cylinder,
&*read.terrain, &*read.terrain,
entity, entity,
&mut pos, &mut cpos,
pos_delta, tgt_pos,
&mut vel, &mut vel,
&mut physics_state, &mut physics_state,
Vec3::zero(), Vec3::zero(),
&read.dt, &read.dt,
true,
was_on_ground, was_on_ground,
|entity, vel| land_on_grounds.push((entity, vel)), |entity, vel| land_on_grounds.push((entity, vel)),
); );
tgt_pos = cpos.0;
}, },
Collider::Point => { Collider::Point => {
let (dist, block) = read let (dist, block) = read
@ -567,6 +570,8 @@ impl<'a> PhysicsData<'a> {
.get(pos.0.map(|e| e.floor() as i32)) .get(pos.0.map(|e| e.floor() as i32))
.ok() .ok()
.and_then(|vox| vox.is_liquid().then_some(1.0)); .and_then(|vox| vox.is_liquid().then_some(1.0));
tgt_pos = pos.0;
}, },
} }
@ -632,7 +637,8 @@ impl<'a> PhysicsData<'a> {
let mut physics_state_delta = physics_state.clone(); let mut physics_state_delta = physics_state.clone();
// deliberately don't use scale yet here, because the 11.0/0.8 // deliberately don't use scale yet here, because the 11.0/0.8
// thing is in the comp::Scale for visual reasons // thing is in the comp::Scale for visual reasons
let wpos = pos.0; let mut cpos = pos;
let wpos = cpos.0;
let transform_from = let transform_from =
Mat4::<f32>::translation_3d(pos_other.0 - wpos) Mat4::<f32>::translation_3d(pos_other.0 - wpos)
* Mat4::from(ori_other.0) * Mat4::from(ori_other.0)
@ -640,20 +646,19 @@ impl<'a> PhysicsData<'a> {
let transform_to = transform_from.inverted(); let transform_to = transform_from.inverted();
let ori_from = Mat4::from(ori_other.0); let ori_from = Mat4::from(ori_other.0);
let ori_to = ori_from.inverted(); let ori_to = ori_from.inverted();
pos.0 = transform_to.mul_point(Vec3::zero()); cpos.0 = transform_to.mul_point(Vec3::zero());
vel.0 = ori_to.mul_direction(vel.0 - vel_other.0); vel.0 = ori_to.mul_direction(vel.0 - vel_other.0);
let cylinder = (radius, z_min, z_max); let cylinder = (radius, z_min, z_max);
cylinder_voxel_collision( cylinder_voxel_collision(
cylinder, cylinder,
&voxel_collider.dyna, &voxel_collider.dyna,
entity, entity,
&mut pos, &mut cpos,
transform_to.mul_direction(pos_delta), transform_to.mul_point(tgt_pos - wpos),
&mut vel, &mut vel,
&mut physics_state_delta, &mut physics_state_delta,
ori_to.mul_direction(vel_other.0), ori_to.mul_direction(vel_other.0),
&read.dt, &read.dt,
false,
was_on_ground, was_on_ground,
|entity, vel| { |entity, vel| {
land_on_grounds land_on_grounds
@ -661,8 +666,9 @@ impl<'a> PhysicsData<'a> {
}, },
); );
pos.0 = transform_from.mul_point(pos.0) + wpos; cpos.0 = transform_from.mul_point(cpos.0) + wpos;
vel.0 = ori_from.mul_direction(vel.0) + vel_other.0; vel.0 = ori_from.mul_direction(vel.0) + vel_other.0;
tgt_pos = cpos.0;
// union in the state updates, so that the state isn't just based on // union in the state updates, so that the state isn't just based on
// the most recent terrain that collision was attempted with // the most recent terrain that collision was attempted with
@ -691,8 +697,9 @@ impl<'a> PhysicsData<'a> {
} }
} }
} }
if pos != old_pos {
pos_writes.push((entity, pos)); if tgt_pos != pos.0 {
pos_writes.push((entity, Pos(tgt_pos)));
} }
if vel != old_vel { if vel != old_vel {
vel_writes.push((entity, vel)); vel_writes.push((entity, vel));
@ -771,12 +778,11 @@ fn cylinder_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
terrain: &'a T, terrain: &'a T,
entity: Entity, entity: Entity,
pos: &mut Pos, pos: &mut Pos,
mut pos_delta: Vec3<f32>, tgt_pos: Vec3<f32>,
vel: &mut Vel, vel: &mut Vel,
physics_state: &mut PhysicsState, physics_state: &mut PhysicsState,
ground_vel: Vec3<f32>, ground_vel: Vec3<f32>,
dt: &DeltaTime, dt: &DeltaTime,
apply_velocity_step: bool, // Stupid hack
was_on_ground: bool, was_on_ground: bool,
mut land_on_ground: impl FnMut(Entity, Vel), mut land_on_ground: impl FnMut(Entity, Vel),
) { ) {
@ -859,6 +865,8 @@ fn cylinder_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
let mut on_ceiling = false; let mut on_ceiling = false;
let mut attempts = 0; // Don't loop infinitely here let mut attempts = 0; // Don't loop infinitely here
let mut pos_delta = tgt_pos - pos.0;
// Don't jump too far at once // Don't jump too far at once
let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3) let increments = (pos_delta.map(|e| e.abs()).reduce_partial_max() / 0.3)
.ceil() .ceil()
@ -866,9 +874,7 @@ fn cylinder_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
let old_pos = pos.0; let old_pos = pos.0;
fn block_true(_: &Block) -> bool { true } fn block_true(_: &Block) -> bool { true }
for _ in 0..increments as usize { for _ in 0..increments as usize {
if apply_velocity_step { pos.0 += pos_delta / increments;
pos.0 += pos_delta / increments;
}
const MAX_ATTEMPTS: usize = 16; const MAX_ATTEMPTS: usize = 16;
@ -1069,7 +1075,9 @@ fn cylinder_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
} }
if physics_state.on_ground || physics_state.on_wall.is_some() { if physics_state.on_ground || physics_state.on_wall.is_some() {
vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0); if physics_state.on_ground {
vel.0 *= (1.0 - FRIC_GROUND.min(1.0)).powf(dt.0 * 60.0);
}
physics_state.ground_vel = ground_vel; physics_state.ground_vel = ground_vel;
} }