mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial pass for gravity and air resistance for more stable physics
This commit is contained in:
committed by
Avi Weinstock
parent
71c07734f7
commit
b8a27f493c
@ -377,10 +377,59 @@ impl<'a> PhysicsData<'a> {
|
|||||||
span!(guard, "Apply movement and terrain collision");
|
span!(guard, "Apply movement and terrain collision");
|
||||||
let (positions, velocities, previous_phys_cache, orientations) = (
|
let (positions, velocities, previous_phys_cache, orientations) = (
|
||||||
&write.positions,
|
&write.positions,
|
||||||
&write.velocities,
|
&mut write.velocities,
|
||||||
&write.previous_phys_cache,
|
&write.previous_phys_cache,
|
||||||
&write.orientations,
|
&write.orientations,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// First pass: update velocity using air resistance and gravity for each entity.
|
||||||
|
// We do this in a first pass because it helps keep things more stable for
|
||||||
|
// entities that are anchored to other entities (such as airships).
|
||||||
|
(
|
||||||
|
&read.entities,
|
||||||
|
positions,
|
||||||
|
velocities,
|
||||||
|
&write.physics_states,
|
||||||
|
!&read.mountings,
|
||||||
|
)
|
||||||
|
.par_join()
|
||||||
|
.for_each(|(entity, pos, vel, physics_state, _)| {
|
||||||
|
let in_loaded_chunk = read
|
||||||
|
.terrain
|
||||||
|
.get_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)))
|
||||||
|
.is_some();
|
||||||
|
// Integrate forces
|
||||||
|
// Friction is assumed to be a constant dependent on location
|
||||||
|
let friction = if physics_state.on_ground { 0.0 } else { FRIC_AIR }
|
||||||
|
// .max(if physics_state.on_ground {
|
||||||
|
// FRIC_GROUND
|
||||||
|
// } else {
|
||||||
|
// 0.0
|
||||||
|
// })
|
||||||
|
.max(if physics_state.in_liquid.is_some() {
|
||||||
|
FRIC_FLUID
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
});
|
||||||
|
let downward_force =
|
||||||
|
if !in_loaded_chunk {
|
||||||
|
0.0 // No gravity in unloaded chunks
|
||||||
|
} else if physics_state
|
||||||
|
.in_liquid
|
||||||
|
.map(|depth| depth > 0.75)
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
(1.0 - BOUYANCY) * GRAVITY
|
||||||
|
} else {
|
||||||
|
GRAVITY
|
||||||
|
} * read.gravities.get(entity).map(|g| g.0).unwrap_or_default();
|
||||||
|
|
||||||
|
vel.0 = integrate_forces(read.dt.0, vel.0, downward_force, friction);
|
||||||
|
});
|
||||||
|
|
||||||
|
let velocities = &write.velocities;
|
||||||
|
|
||||||
|
// Second pass: resolve collisions
|
||||||
let (pos_writes, vel_writes, land_on_grounds) = (
|
let (pos_writes, vel_writes, land_on_grounds) = (
|
||||||
&read.entities,
|
&read.entities,
|
||||||
read.scales.maybe(),
|
read.scales.maybe(),
|
||||||
@ -409,9 +458,10 @@ impl<'a> PhysicsData<'a> {
|
|||||||
_previous_cache,
|
_previous_cache,
|
||||||
_,
|
_,
|
||||||
)| {
|
)| {
|
||||||
// defer the writes of positions to allow an inner loop over terrain-like
|
// defer the writes of positions and velocities to allow an inner loop over
|
||||||
// entities
|
// terrain-like entities
|
||||||
let mut vel = *vel;
|
let mut vel = *vel;
|
||||||
|
let old_vel = vel;
|
||||||
if sticky.is_some() && physics_state.on_surface().is_some() {
|
if sticky.is_some() && physics_state.on_surface().is_some() {
|
||||||
vel.0 = physics_state.ground_vel;
|
vel.0 = physics_state.ground_vel;
|
||||||
return (pos_writes, vel_writes, land_on_grounds);
|
return (pos_writes, vel_writes, land_on_grounds);
|
||||||
@ -425,44 +475,14 @@ impl<'a> PhysicsData<'a> {
|
|||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let old_vel = vel;
|
|
||||||
// Integrate forces
|
|
||||||
// Friction is assumed to be a constant dependent on location
|
|
||||||
let friction = if physics_state.on_ground { 0.0 } else { FRIC_AIR }
|
|
||||||
// .max(if physics_state.on_ground {
|
|
||||||
// FRIC_GROUND
|
|
||||||
// } else {
|
|
||||||
// 0.0
|
|
||||||
// })
|
|
||||||
.max(if physics_state.in_liquid.is_some() {
|
|
||||||
FRIC_FLUID
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
});
|
|
||||||
let in_loaded_chunk = read
|
let in_loaded_chunk = read
|
||||||
.terrain
|
.terrain
|
||||||
.get_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)))
|
.get_key(read.terrain.pos_key(pos.0.map(|e| e.floor() as i32)))
|
||||||
.is_some();
|
.is_some();
|
||||||
let downward_force =
|
|
||||||
if !in_loaded_chunk {
|
|
||||||
0.0 // No gravity in unloaded chunks
|
|
||||||
} else if physics_state
|
|
||||||
.in_liquid
|
|
||||||
.map(|depth| depth > 0.75)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
(1.0 - BOUYANCY) * GRAVITY
|
|
||||||
} else {
|
|
||||||
GRAVITY
|
|
||||||
} * read.gravities.get(entity).map(|g| g.0).unwrap_or_default();
|
|
||||||
vel.0 = integrate_forces(read.dt.0, vel.0, downward_force, friction);
|
|
||||||
|
|
||||||
// Don't move if we're not in a loaded chunk
|
// Don't move if we're not in a loaded chunk
|
||||||
let pos_delta = if in_loaded_chunk {
|
let pos_delta = if in_loaded_chunk {
|
||||||
// this is an approximation that allows most framerates to
|
vel.0 * read.dt.0
|
||||||
// behave in a similar manner.
|
|
||||||
let dt_lerp = 0.2;
|
|
||||||
(vel.0 * dt_lerp + old_vel.0 * (1.0 - dt_lerp)) * read.dt.0
|
|
||||||
} else {
|
} else {
|
||||||
Vec3::zero()
|
Vec3::zero()
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user