🦀 collision detection bugs are gone 🦀
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
191f9b1f28
commit
6794213f7d
4 changed files with 64 additions and 26 deletions
44
src/aabb.rs
44
src/aabb.rs
|
@ -1,11 +1,9 @@
|
||||||
use cgmath::Point3;
|
use cgmath::Point3;
|
||||||
|
|
||||||
type T = f32;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Aabb {
|
pub struct Aabb {
|
||||||
pub min: Point3<T>,
|
pub min: Point3<f32>,
|
||||||
pub max: Point3<T>,
|
pub max: Point3<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aabb {
|
impl Aabb {
|
||||||
|
@ -15,17 +13,33 @@ impl Aabb {
|
||||||
&& (self.min.z <= other.max.z && self.max.z >= other.min.z)
|
&& (self.min.z <= other.max.z && self.max.z >= other.min.z)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_corners(&self) -> [Point3<T>; 8] {
|
/// Gets the corners of the AABB that should be checked when checking
|
||||||
[
|
/// collision with the world.
|
||||||
Point3::new(self.min.x, self.min.y, self.min.z),
|
///
|
||||||
Point3::new(self.min.x, self.min.y, self.max.z),
|
/// Returns a `Vec` of all `Point3`s that cover the faces of `self` with
|
||||||
Point3::new(self.min.x, self.max.y, self.min.z),
|
/// no more than 1 unit of distance between them.
|
||||||
Point3::new(self.min.x, self.max.y, self.max.z),
|
pub fn get_corners(&self) -> Vec<Point3<f32>> {
|
||||||
Point3::new(self.max.x, self.min.y, self.min.z),
|
let mut corners = Vec::new();
|
||||||
Point3::new(self.max.x, self.min.y, self.max.z),
|
|
||||||
Point3::new(self.max.x, self.max.y, self.min.z),
|
let mut x = self.min.x;
|
||||||
Point3::new(self.max.x, self.max.y, self.max.z),
|
while x < self.max.x.ceil() {
|
||||||
]
|
let mut y = self.min.y;
|
||||||
|
while y < self.max.y.ceil() {
|
||||||
|
let mut z = self.min.z;
|
||||||
|
while z < self.max.z.ceil() {
|
||||||
|
corners.push(Point3::new(
|
||||||
|
x.min(self.max.x),
|
||||||
|
y.min(self.max.y),
|
||||||
|
z.min(self.max.z),
|
||||||
|
));
|
||||||
|
z += 1.0;
|
||||||
|
}
|
||||||
|
y += 1.0;
|
||||||
|
}
|
||||||
|
x += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
corners
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ mod time;
|
||||||
mod vertex;
|
mod vertex;
|
||||||
mod view;
|
mod view;
|
||||||
mod world;
|
mod world;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use wgpu::SwapChainError;
|
use wgpu::SwapChainError;
|
||||||
|
|
|
@ -17,6 +17,7 @@ use crate::{
|
||||||
renderable::Renderable,
|
renderable::Renderable,
|
||||||
texture::{Texture, TextureManager},
|
texture::{Texture, TextureManager},
|
||||||
time::Time,
|
time::Time,
|
||||||
|
utils,
|
||||||
vertex::{BlockVertex, Vertex},
|
vertex::{BlockVertex, Vertex},
|
||||||
view::View,
|
view::View,
|
||||||
world::World,
|
world::World,
|
||||||
|
@ -408,35 +409,38 @@ impl WorldState {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Updates the player's position by their velocity, checks for and
|
||||||
|
/// resolves any subsequent collisions, and then adds the jumping speed to
|
||||||
|
/// the velocity.
|
||||||
fn update_position(&mut self, dt: Duration) {
|
fn update_position(&mut self, dt: Duration) {
|
||||||
let dt_seconds = dt.as_secs_f32();
|
|
||||||
let (yaw_sin, yaw_cos) = self.camera.yaw.0.sin_cos();
|
let (yaw_sin, yaw_cos) = self.camera.yaw.0.sin_cos();
|
||||||
|
|
||||||
let speed = 10.0 * (self.sprinting as i32 * 2 + 1) as f32;
|
let speed = 10.0 * (self.sprinting as i32 * 2 + 1) as f32 * dt.as_secs_f32();
|
||||||
|
|
||||||
let forward_speed = self.forward_pressed as i32 - self.backward_pressed as i32;
|
let forward_speed = self.forward_pressed as i32 - self.backward_pressed as i32;
|
||||||
let forward = Vector3::new(yaw_cos, 0.0, yaw_sin);
|
let forward = Vector3::new(yaw_cos, 0.0, yaw_sin) * forward_speed as f32;
|
||||||
let forward = forward * forward_speed as f32;
|
|
||||||
|
|
||||||
let right_speed = self.right_pressed as i32 - self.left_pressed as i32;
|
let right_speed = self.right_pressed as i32 - self.left_pressed as i32;
|
||||||
let right = Vector3::new(-yaw_sin, 0.0, yaw_cos);
|
let right = Vector3::new(-yaw_sin, 0.0, yaw_cos) * right_speed as f32;
|
||||||
let right = right * right_speed as f32;
|
|
||||||
|
|
||||||
let mut velocity = forward + right;
|
let mut velocity = forward + right;
|
||||||
if velocity.magnitude2() > 1.0 {
|
if velocity.magnitude2() > 1.0 {
|
||||||
velocity = velocity.normalize();
|
velocity = velocity.normalize();
|
||||||
}
|
}
|
||||||
velocity *= speed * dt.as_secs_f32();
|
velocity *= speed;
|
||||||
|
velocity.y = self.up_speed * 10.0 * dt.as_secs_f32();
|
||||||
|
|
||||||
let mut new_position = self.camera.position;
|
let mut new_position = self.camera.position;
|
||||||
|
|
||||||
// y component (jumping)
|
// y component (jumping)
|
||||||
new_position.y += self.up_speed * speed * dt_seconds;
|
new_position.y += velocity.y;
|
||||||
if let Some(aabb) = self.check_collision(new_position) {
|
if let Some(aabb) = self.check_collision(new_position) {
|
||||||
if self.up_speed < 0.0 {
|
if self.up_speed < 0.0 {
|
||||||
new_position.y = aabb.min.y.ceil() + 1.62;
|
new_position.y = aabb.min.y.ceil() + 1.62;
|
||||||
|
new_position.y = utils::f32_successor(new_position.y);
|
||||||
} else if self.up_speed > 0.0 {
|
} else if self.up_speed > 0.0 {
|
||||||
new_position.y = aabb.max.y.floor() - 0.1801;
|
new_position.y = aabb.max.y.floor() - 0.18;
|
||||||
|
new_position.y = utils::f32_predecessor(new_position.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.up_speed = 0.0;
|
self.up_speed = 0.0;
|
||||||
|
@ -447,8 +451,10 @@ impl WorldState {
|
||||||
if let Some(aabb) = self.check_collision(new_position) {
|
if let Some(aabb) = self.check_collision(new_position) {
|
||||||
if velocity.x < 0.0 {
|
if velocity.x < 0.0 {
|
||||||
new_position.x = aabb.min.x.ceil() + 0.3;
|
new_position.x = aabb.min.x.ceil() + 0.3;
|
||||||
|
new_position.x = utils::f32_successor(new_position.x);
|
||||||
} else if velocity.x > 0.0 {
|
} else if velocity.x > 0.0 {
|
||||||
new_position.x = aabb.max.x.floor() - 0.3001;
|
new_position.x = aabb.max.x.floor() - 0.3;
|
||||||
|
new_position.x = utils::f32_predecessor(new_position.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +463,10 @@ impl WorldState {
|
||||||
if let Some(aabb) = self.check_collision(new_position) {
|
if let Some(aabb) = self.check_collision(new_position) {
|
||||||
if velocity.z < 0.0 {
|
if velocity.z < 0.0 {
|
||||||
new_position.z = aabb.min.z.ceil() + 0.3;
|
new_position.z = aabb.min.z.ceil() + 0.3;
|
||||||
|
new_position.z = utils::f32_successor(new_position.z);
|
||||||
} else if velocity.z > 0.0 {
|
} else if velocity.z > 0.0 {
|
||||||
new_position.z = aabb.max.z.floor() - 0.3001;
|
new_position.z = aabb.max.z.floor() - 0.3;
|
||||||
|
new_position.z = utils::f32_predecessor(new_position.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
15
src/utils.rs
Normal file
15
src/utils.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/// Returns `x` incremented with the lowest possible value that a
|
||||||
|
/// single-precision floating point with `x`'s value can represent.
|
||||||
|
pub fn f32_successor(x: f32) -> f32 {
|
||||||
|
let x = x.to_bits();
|
||||||
|
let x = if (x >> 31) == 0 { x + 1 } else { x - 1 };
|
||||||
|
f32::from_bits(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `x` decremented with the lowest possible value that a
|
||||||
|
/// single-precision floating point with `x`'s value can represent.
|
||||||
|
pub fn f32_predecessor(x: f32) -> f32 {
|
||||||
|
let x = x.to_bits();
|
||||||
|
let x = if (x >> 31) == 0 { x - 1 } else { x + 1 };
|
||||||
|
f32::from_bits(x)
|
||||||
|
}
|
Loading…
Reference in a new issue