🦀 collision detection bugs are gone 🦀
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Sijmen 2021-06-07 19:06:16 +02:00
parent 191f9b1f28
commit 6794213f7d
Signed by: vijfhoek
GPG key ID: 82D05C89B28B0DAE
4 changed files with 64 additions and 26 deletions

View file

@ -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
} }
} }

View file

@ -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;

View file

@ -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
View 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)
}