Resolved collision bugs with prioritised collision system

This commit is contained in:
Joshua Barretto 2019-06-26 10:40:07 +01:00
parent ae168711d7
commit 44f4031e58
2 changed files with 52 additions and 57 deletions

View File

@ -1,3 +1,4 @@
#![type_length_limit="1615607"]
#![feature(
euclidean_division,
duration_float,

View File

@ -159,19 +159,11 @@ impl<'a> System<'a> for Sys {
let player_rad = 0.3; // half-width of the player's AABB
let player_height = 1.7;
// Iterate through nearby blocks, prioritise closer ones
let near_iter = (0..5)
.map(move |dist| {
(-dist..=dist).map(move |x| {
(-dist..=dist).map(move |y| {
(-dist..=dist)
.map(move |z| Vec3::new(x, y, z))
.filter(move |p| p.map(|e: i32| e.abs()).reduce_max() == dist)
.map(|p| p.into_tuple())
})
})
})
.flatten()
let dist = 2;
let near_iter = (-dist..=dist)
.map(move |i| (-dist..=dist)
.map(move |j| (-dist..=dist)
.map(move |k| (i, j, k))))
.flatten()
.flatten();
@ -185,7 +177,7 @@ impl<'a> System<'a> for Sys {
.map(|vox| !vox.is_empty())
.unwrap_or(false)
{
let this_aabb = Aabb {
let player_aabb = Aabb {
min: pos + Vec3::new(-player_rad, -player_rad, 0.0),
max: pos + Vec3::new(player_rad, player_rad, player_height),
};
@ -194,7 +186,7 @@ impl<'a> System<'a> for Sys {
max: block_pos.map(|e| e as f32) + 1.0,
};
if this_aabb.collides_with_aabb(block_aabb) {
if player_aabb.collides_with_aabb(block_aabb) {
return true;
}
}
@ -205,51 +197,53 @@ impl<'a> System<'a> for Sys {
on_grounds.remove(entity);
pos.0.z -= 0.0001; // To force collision with the floor
// For every nearby block...
let mut on_ground = false;
for (i, j, k) in near_iter.clone() {
let block_pos = pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k);
while collision_with(pos.0, near_iter.clone()) {
let player_aabb = Aabb {
min: pos.0 + Vec3::new(-player_rad, -player_rad, 0.0),
max: pos.0 + Vec3::new(player_rad, player_rad, player_height),
};
// ...check to see whether it is solid...
if terrain
.get(block_pos)
.map(|vox| !vox.is_empty())
.unwrap_or(false)
let (block_pos, block_aabb) = near_iter
.clone()
.map(|(i, j, k)| pos.0.map(|e| e.floor() as i32) + Vec3::new(i, j, k))
.map(|block_pos| {
let block_aabb = Aabb {
min: block_pos.map(|e| e as f32),
max: block_pos.map(|e| e as f32) + 1.0,
};
(block_pos, block_aabb)
})
.filter(|(_, block_aabb)| block_aabb.collides_with_aabb(player_aabb))
.filter(|(block_pos, _)| terrain
.get(*block_pos)
.map(|vox| !vox.is_empty())
.unwrap_or(false))
.max_by_key(|(_, block_aabb)| ((player_aabb.collision_vector_with_aabb(*block_aabb) * Vec3::new(1.0, 1.0, 10.0)).map(|e| e.abs()).reduce_partial_min() * 200.0) as i32)
.expect("Collision detected, but no colliding blocks found!");
let dir = player_aabb.collision_vector_with_aabb(block_aabb);
let max_axis = dir.map(|e| e.abs()).reduce_partial_min();
let resolve_dir = -dir.map(|e| if e.abs() == max_axis { e } else { 0.0 });
// When the resolution direction is pointing upwards, we must be on the ground
if resolve_dir.z > 0.0 {
on_ground = true;
}
if resolve_dir.z == 0.0
&& !collision_with(pos.0 + Vec3::unit_z() * 1.1, near_iter.clone())
{
// ...and calculate bounding boxes for both the player's body and the block.
let this_aabb = Aabb {
min: pos.0 + Vec3::new(-player_rad, -player_rad, 0.0),
max: pos.0 + Vec3::new(player_rad, player_rad, player_height),
};
let block_aabb = Aabb {
min: block_pos.map(|e| e as f32),
max: block_pos.map(|e| e as f32) + 1.0,
};
// If the bounding boxes collide, resolve the collision
if this_aabb.collides_with_aabb(block_aabb) {
let dir = this_aabb.collision_vector_with_aabb(block_aabb);
let max_axis = dir.map(|e| e.abs()).reduce_partial_min();
let resolve_dir = -dir.map(|e| if e.abs() == max_axis { e } else { 0.0 });
// When the resolution direction is pointing upwards, we must be on the ground
if resolve_dir.z > 0.0 {
on_ground = true;
}
if resolve_dir.z == 0.0
&& !collision_with(pos.0 + Vec3::unit_z() * 1.0, near_iter.clone())
{
pos.0.z += 1.0;
break;
} else {
pos.0 += resolve_dir;
vel.0 = vel
.0
.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 });
}
}
pos.0.z += 1.0;
on_ground = true;
break;
} else {
pos.0 += resolve_dir;
vel.0 = vel
.0
.map2(resolve_dir, |e, d| if d == 0.0 { e } else { 0.0 });
}
}