Fixed block snapping for bizarre block heights

This commit is contained in:
Joshua Barretto 2020-04-21 00:34:35 +01:00
parent 89f99dbcc9
commit 68732bebde

View File

@ -152,7 +152,7 @@ impl<'a> System<'a> for Sys {
// Function for determining whether the player at a specific position collides
// with the ground
let collision_with = |pos: Vec3<f32>, hit: fn(&Block) -> bool, near_iter| {
let collision_with = |pos: Vec3<f32>, hit: &dyn Fn(&Block) -> bool, near_iter| {
for (i, j, k) in near_iter {
let block_pos = pos.map(|e| e.floor() as i32) + Vec3::new(i, j, k);
@ -192,7 +192,7 @@ impl<'a> System<'a> for Sys {
const MAX_ATTEMPTS: usize = 16;
// While the player is colliding with the terrain...
while collision_with(pos.0, |vox| vox.is_solid(), near_iter.clone())
while collision_with(pos.0, &|block| block.is_solid(), near_iter.clone())
&& attempts < MAX_ATTEMPTS
{
// Calculate the player's AABB
@ -203,7 +203,7 @@ impl<'a> System<'a> for Sys {
// Determine the block that we are colliding with most (based on minimum
// collision axis)
let (_block_pos, block_aabb) = near_iter
let (_block_pos, block_aabb, block_height) = near_iter
.clone()
// Calculate the block's position in world space
.map(|(i, j, k)| pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k))
@ -221,15 +221,16 @@ impl<'a> System<'a> for Sys {
min: block_pos.map(|e| e as f32),
max: block_pos.map(|e| e as f32) + Vec3::new(1.0, 1.0, block.get_height()),
},
block.get_height(),
))
} else {
None
}
})
// Determine whether the block's AABB collides with the player's AABB
.filter(|(_, block_aabb)| block_aabb.collides_with_aabb(player_aabb))
.filter(|(_, block_aabb, _)| block_aabb.collides_with_aabb(player_aabb))
// Find the maximum of the minimum collision axes (this bit is weird, trust me that it works)
.min_by_key(|(_, block_aabb)| {
.min_by_key(|(_, block_aabb, _)| {
((block_aabb.center() - player_aabb.center() - Vec3::unit_z() * 0.5)
.map(|e| e.abs())
.sum()
@ -262,7 +263,7 @@ impl<'a> System<'a> for Sys {
// When the resolution direction is non-vertical, we must be colliding with a
// wall If the space above is free...
if !collision_with(Vec3::new(pos.0.x, pos.0.y, (pos.0.z + 0.1).ceil()), |vox| vox.is_solid(), near_iter.clone())
if !collision_with(Vec3::new(pos.0.x, pos.0.y, (pos.0.z + 0.1).ceil()), &|block| block.is_solid(), near_iter.clone())
// ...and we're being pushed out horizontally...
&& resolve_dir.z == 0.0
// ...and the vertical resolution direction is sufficiently great...
@ -270,17 +271,17 @@ impl<'a> System<'a> for Sys {
// ...and we're falling/standing OR there is a block *directly* beneath our current origin (note: not hitbox)...
&& (vel.0.z <= 0.0 || terrain
.get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
.map(|vox| vox.is_solid())
.map(|block| block.is_solid())
.unwrap_or(false))
// ...and there is a collision with a block beneath our current hitbox...
&& collision_with(
old_pos + resolve_dir - Vec3::unit_z() * 1.05,
|vox| vox.is_solid(),
&|block| block.is_solid(),
near_iter.clone(),
)
{
// ...block-hop!
pos.0.z = (pos.0.z + 0.1).ceil();
pos.0.z = (pos.0.z + 0.1).floor() + block_height;
vel.0.z = 0.0;
on_ground = true;
break;
@ -309,20 +310,25 @@ impl<'a> System<'a> for Sys {
// If the space below us is free, then "snap" to the ground
} else if collision_with(
pos.0 - Vec3::unit_z() * 1.05,
|vox| vox.is_solid(),
&|block| block.is_solid(),
near_iter.clone(),
) && vel.0.z < 0.0
&& vel.0.z > -1.5
&& was_on_ground
&& !terrain
.get(
Vec3::new(pos.0.x, pos.0.y, (pos.0.z - 0.05).floor())
.map(|e| e.floor() as i32),
)
.map(|vox| vox.is_solid())
.unwrap_or(false)
&& !collision_with(
pos.0 - Vec3::unit_z() * 0.05,
&|block| block.is_solid() && block.get_height() >= (pos.0.z - 0.05).rem_euclid(1.0),
near_iter.clone(),
)
{
pos.0.z = (pos.0.z - 0.05).floor();
let snap_height = terrain
.get(Vec3::new(pos.0.x, pos.0.y, pos.0.z - 0.05)
.map(|e| e.floor() as i32))
.ok()
.filter(|block| block.is_solid())
.map(|block| block.get_height())
.unwrap_or(0.0);
pos.0.z = (pos.0.z - 0.05).floor() + snap_height;
physics_state.on_ground = true;
}
@ -334,7 +340,7 @@ impl<'a> System<'a> for Sys {
];
if let (wall_dir, true) = dirs.iter().fold((Vec3::zero(), false), |(a, hit), dir| {
if collision_with(pos.0 + *dir * 0.01, |vox| vox.is_solid(), near_iter.clone()) {
if collision_with(pos.0 + *dir * 0.01, &|block| block.is_solid(), near_iter.clone()) {
(a + dir, true)
} else {
(a, hit)
@ -346,7 +352,7 @@ impl<'a> System<'a> for Sys {
}
// Figure out if we're in water
physics_state.in_fluid = collision_with(pos.0, |vox| vox.is_fluid(), near_iter.clone());
physics_state.in_fluid = collision_with(pos.0, &|block| block.is_fluid(), near_iter.clone());
let _ = physics_states.insert(entity, physics_state);
}