From 6794213f7defe0eb4d0995af8a2108c57b62f0ec Mon Sep 17 00:00:00 2001 From: Vijfhoek Date: Mon, 7 Jun 2021 19:06:16 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=80=20collision=20detection=20bugs=20a?= =?UTF-8?q?re=20gone=20=F0=9F=A6=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aabb.rs | 44 ++++++++++++++++++++++++++-------------- src/main.rs | 1 + src/state/world_state.rs | 30 +++++++++++++++++---------- src/utils.rs | 15 ++++++++++++++ 4 files changed, 64 insertions(+), 26 deletions(-) create mode 100644 src/utils.rs diff --git a/src/aabb.rs b/src/aabb.rs index e913365..9cf338e 100644 --- a/src/aabb.rs +++ b/src/aabb.rs @@ -1,11 +1,9 @@ use cgmath::Point3; -type T = f32; - #[derive(Debug)] pub struct Aabb { - pub min: Point3, - pub max: Point3, + pub min: Point3, + pub max: Point3, } impl Aabb { @@ -15,17 +13,33 @@ impl Aabb { && (self.min.z <= other.max.z && self.max.z >= other.min.z) } - pub fn get_corners(&self) -> [Point3; 8] { - [ - Point3::new(self.min.x, self.min.y, self.min.z), - Point3::new(self.min.x, self.min.y, self.max.z), - Point3::new(self.min.x, self.max.y, self.min.z), - Point3::new(self.min.x, self.max.y, self.max.z), - Point3::new(self.max.x, self.min.y, self.min.z), - Point3::new(self.max.x, self.min.y, self.max.z), - Point3::new(self.max.x, self.max.y, self.min.z), - Point3::new(self.max.x, self.max.y, self.max.z), - ] + /// Gets the corners of the AABB that should be checked when checking + /// collision with the world. + /// + /// Returns a `Vec` of all `Point3`s that cover the faces of `self` with + /// no more than 1 unit of distance between them. + pub fn get_corners(&self) -> Vec> { + let mut corners = Vec::new(); + + let mut x = self.min.x; + 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 } } diff --git a/src/main.rs b/src/main.rs index e27b0ef..7afd006 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ mod time; mod vertex; mod view; mod world; +mod utils; use std::time::{Duration, Instant}; use wgpu::SwapChainError; diff --git a/src/state/world_state.rs b/src/state/world_state.rs index cfcc2ed..459e944 100644 --- a/src/state/world_state.rs +++ b/src/state/world_state.rs @@ -17,6 +17,7 @@ use crate::{ renderable::Renderable, texture::{Texture, TextureManager}, time::Time, + utils, vertex::{BlockVertex, Vertex}, view::View, world::World, @@ -408,35 +409,38 @@ impl WorldState { 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) { - let dt_seconds = dt.as_secs_f32(); 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 = Vector3::new(yaw_cos, 0.0, yaw_sin); - let forward = forward * forward_speed as f32; + let forward = Vector3::new(yaw_cos, 0.0, yaw_sin) * forward_speed as f32; 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 = right * right_speed as f32; + let right = Vector3::new(-yaw_sin, 0.0, yaw_cos) * right_speed as f32; let mut velocity = forward + right; if velocity.magnitude2() > 1.0 { 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; // 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 self.up_speed < 0.0 { 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 { - 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; @@ -447,8 +451,10 @@ impl WorldState { if let Some(aabb) = self.check_collision(new_position) { if velocity.x < 0.0 { new_position.x = aabb.min.x.ceil() + 0.3; + new_position.x = utils::f32_successor(new_position.x); } 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 velocity.z < 0.0 { new_position.z = aabb.min.z.ceil() + 0.3; + new_position.z = utils::f32_successor(new_position.z); } 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); } } diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..96d10ef --- /dev/null +++ b/src/utils.rs @@ -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) +}