From e7122195226fc9fc5a4a942b4b12713345b34666 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Tue, 24 Jan 2023 03:13:24 +0100 Subject: [PATCH 01/80] Add wall to test #426 --- examples2d/character_controller2.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/examples2d/character_controller2.rs b/examples2d/character_controller2.rs index ff500e9..4df9f51 100644 --- a/examples2d/character_controller2.rs +++ b/examples2d/character_controller2.rs @@ -88,6 +88,19 @@ pub fn init_world(testbed: &mut Testbed) { .rotation(impossible_slope_angle); colliders.insert(collider); + /* + * Create a wall we can’t climb. + */ + let wall_angle = PI / 2.; + let wall_size = 2.0; + let collider = ColliderBuilder::cuboid(wall_size, ground_height) + .translation(vector![ + ground_size + slope_size * 2.0 + impossible_slope_size + 0.35, + -ground_height + 2.5 * 2.3 + ]) + .rotation(wall_angle); + colliders.insert(collider); + /* * Create a moving platform. */ From cfb922d8110fc3404162ea63eaf6d9917b7b7a99 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 16:51:28 +0100 Subject: [PATCH 02/80] Import PI --- examples2d/character_controller2.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/examples2d/character_controller2.rs b/examples2d/character_controller2.rs index 4df9f51..e964a02 100644 --- a/examples2d/character_controller2.rs +++ b/examples2d/character_controller2.rs @@ -1,3 +1,4 @@ +use std::f32::consts::PI; use rapier2d::prelude::*; use rapier_testbed2d::Testbed; From 615b7fbf6f1cb4ee7c87e73211be75821eb96589 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 18:43:47 +0100 Subject: [PATCH 03/80] Fix not sliding down wall --- src/control/character_controller.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 3972adc..2861f78 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -254,10 +254,12 @@ impl KinematicCharacterController { if let (Some(translation_on_slope), _) = self.handle_slopes(&toi, &mut translation_remaining) { + println!("[slope] translation_on_slope: {translation_on_slope:?}"); translation_remaining = translation_on_slope; + println!("[slope] translation_remaining: {translation_remaining:?}"); } else { // If the slope is too big, try to step on the stair. - self.handle_stairs( + let stair_handled = self.handle_stairs( bodies, colliders, queries, @@ -269,6 +271,9 @@ impl KinematicCharacterController { &mut translation_remaining, &mut result, ); + if !stair_handled { + println!("[stair] translation_remaining: {translation_remaining:?}"); + } } } else { // No interference along the path. @@ -484,9 +489,11 @@ impl KinematicCharacterController { // - If there is no horizontal translation, then we only have gravity. In that case, // we take the vertical movement into account to decide if we need to slide down. let sliding_translation_remaining = if horizontal_translation_remaining != Vector::zeros() { + println!("[slope] horizontal_translation_remaining: {horizontal_translation_remaining:?}"); horizontal_translation_remaining - - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1) + - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1) + vertical_translation_remaining } else { + println!("[slope] vertical_translation_remaining: {vertical_translation_remaining:?}"); vertical_translation_remaining - *hit.normal1 * (vertical_translation_remaining).dot(&hit.normal1) }; @@ -504,6 +511,7 @@ impl KinematicCharacterController { // To avoid sliding down, we remove the sliding component due to the vertical // part of the movement but have to keep the component due to the horizontal // part of the self. + println!("[slope] Can't slide down."); *translation_remaining - (*hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1) + vertical_translation_remaining) From 000c759b78193f2e646861435aba6405eb014ed7 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 19:09:50 +0100 Subject: [PATCH 04/80] Simplify slope code --- src/control/character_controller.rs | 51 +++++++---------------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 2861f78..25fb288 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -488,50 +488,23 @@ impl KinematicCharacterController { // climb/slide down movement is decided by that translation. // - If there is no horizontal translation, then we only have gravity. In that case, // we take the vertical movement into account to decide if we need to slide down. - let sliding_translation_remaining = if horizontal_translation_remaining != Vector::zeros() { - println!("[slope] horizontal_translation_remaining: {horizontal_translation_remaining:?}"); - horizontal_translation_remaining - - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1) + vertical_translation_remaining - } else { - println!("[slope] vertical_translation_remaining: {vertical_translation_remaining:?}"); - vertical_translation_remaining - - *hit.normal1 * (vertical_translation_remaining).dot(&hit.normal1) - }; + let sliding_translation_remaining = + translation_remaining + - *hit.normal1 * (translation_remaining).dot(&hit.normal1); + + println!("[slope] sliding_translation_remaining: {sliding_translation_remaining:?}"); // Check if there is a slope we can climb. let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&sliding_translation_remaining) >= 0.0; - if !climbing { - // Moving down the slope. - let remaining = if angle_with_floor >= self.min_slope_slide_angle { - // Can slide down. - sliding_translation_remaining - } else { - // To avoid sliding down, we remove the sliding component due to the vertical - // part of the movement but have to keep the component due to the horizontal - // part of the self. - println!("[slope] Can't slide down."); - *translation_remaining - - (*hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1) - + vertical_translation_remaining) - // Remove the complete vertical part. - }; - - (Some(remaining), -angle_with_floor) - } else { - // Moving up the slope. - let remaining = if angle_with_floor <= self.max_slope_climb_angle { - // Let’s climb by cancelling from the desired movement the part that - // doesn’t line up with the slope, and continuing the loop. - Some(sliding_translation_remaining) - } else { - // The slope was too steep. - None - }; - - (remaining, angle_with_floor) - } + climbing + .then(||(angle_with_floor <= self.max_slope_climb_angle) + .then_some((Some(sliding_translation_remaining), angle_with_floor)) + .unwrap_or((None, angle_with_floor))) + .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle) + .then_some((Some(sliding_translation_remaining), -angle_with_floor)) + .unwrap_or((Some(horizontal_translation_remaining), -angle_with_floor))) } fn handle_stairs( From bf3cc98489663829e2a65405774b36a6b6942c9a Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 19:18:57 +0100 Subject: [PATCH 05/80] Simplify unused code --- src/control/character_controller.rs | 35 ++++++++++++++--------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 25fb288..37a76fe 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -251,7 +251,7 @@ impl KinematicCharacterController { toi, }); - if let (Some(translation_on_slope), _) = + if let Some(translation_on_slope) = self.handle_slopes(&toi, &mut translation_remaining) { println!("[slope] translation_on_slope: {translation_on_slope:?}"); @@ -478,33 +478,32 @@ impl KinematicCharacterController { &self, hit: &TOI, translation_remaining: &Vector, - ) -> (Option>, Real) { + ) -> Option> { let vertical_translation_remaining = *self.up * (self.up.dot(translation_remaining)); let horizontal_translation_remaining = *translation_remaining - vertical_translation_remaining; - // The idea behind this `if` statement is as follows: - // - If there is any amount of horizontal translations, then the intended - // climb/slide down movement is decided by that translation. - // - If there is no horizontal translation, then we only have gravity. In that case, - // we take the vertical movement into account to decide if we need to slide down. - let sliding_translation_remaining = - translation_remaining - - *hit.normal1 * (translation_remaining).dot(&hit.normal1); + let horizontal_translation_remaining = + horizontal_translation_remaining + - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1); - println!("[slope] sliding_translation_remaining: {sliding_translation_remaining:?}"); + let vertical_translation_remaining = + vertical_translation_remaining + - *hit.normal1 * (vertical_translation_remaining).dot(&hit.normal1); - // Check if there is a slope we can climb. + let sliding_translation_remaining = horizontal_translation_remaining + vertical_translation_remaining; + + // Check if there is a slope to climb. let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&sliding_translation_remaining) >= 0.0; climbing - .then(||(angle_with_floor <= self.max_slope_climb_angle) - .then_some((Some(sliding_translation_remaining), angle_with_floor)) - .unwrap_or((None, angle_with_floor))) - .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle) - .then_some((Some(sliding_translation_remaining), -angle_with_floor)) - .unwrap_or((Some(horizontal_translation_remaining), -angle_with_floor))) + .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? + .then_some(Some(sliding_translation_remaining)) + .unwrap_or(None)) + .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle)// Are we allowed to slide? + .then_some(Some(sliding_translation_remaining)) + .unwrap_or(Some(horizontal_translation_remaining))) } fn handle_stairs( From 075f45ca1ca80e3f1f0923c3bb00b92f29b8cb66 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 19:28:18 +0100 Subject: [PATCH 06/80] Simplify code --- src/control/character_controller.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 37a76fe..78c2403 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -273,6 +273,13 @@ impl KinematicCharacterController { ); if !stair_handled { println!("[stair] translation_remaining: {translation_remaining:?}"); + // No slopes or stairs ahead; try to move along obstacles. + let allowed_dist = + (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); + let allowed_translation = *translation_dir * allowed_dist; + result.translation += allowed_translation; + translation_remaining -= allowed_translation; + } } } else { @@ -483,27 +490,28 @@ impl KinematicCharacterController { let horizontal_translation_remaining = *translation_remaining - vertical_translation_remaining; - let horizontal_translation_remaining = + let horizontal_slope_translation = horizontal_translation_remaining - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1); - let vertical_translation_remaining = + let vertical_slope_translation = vertical_translation_remaining - *hit.normal1 * (vertical_translation_remaining).dot(&hit.normal1); - let sliding_translation_remaining = horizontal_translation_remaining + vertical_translation_remaining; + let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. let angle_with_floor = self.up.angle(&hit.normal1); - let climbing = self.up.dot(&sliding_translation_remaining) >= 0.0; + let climbing = self.up.dot(&slope_translation) >= 0.0; climbing .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? - .then_some(Some(sliding_translation_remaining)) - .unwrap_or(None)) + .then_some(slope_translation)) .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle)// Are we allowed to slide? - .then_some(Some(sliding_translation_remaining)) - .unwrap_or(Some(horizontal_translation_remaining))) + .then_some(slope_translation) + .unwrap_or(horizontal_slope_translation) + .into()) + } fn handle_stairs( From 848009e399fcbce963c86277dab869434d3bb6df Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:07:38 +0100 Subject: [PATCH 07/80] Extract function --- src/control/character_controller.rs | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 78c2403..0475a10 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -273,12 +273,6 @@ impl KinematicCharacterController { ); if !stair_handled { println!("[stair] translation_remaining: {translation_remaining:?}"); - // No slopes or stairs ahead; try to move along obstacles. - let allowed_dist = - (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); - let allowed_translation = *translation_dir * allowed_dist; - result.translation += allowed_translation; - translation_remaining -= allowed_translation; } } @@ -486,18 +480,9 @@ impl KinematicCharacterController { hit: &TOI, translation_remaining: &Vector, ) -> Option> { - let vertical_translation_remaining = *self.up * (self.up.dot(translation_remaining)); - let horizontal_translation_remaining = - *translation_remaining - vertical_translation_remaining; - - let horizontal_slope_translation = - horizontal_translation_remaining - - *hit.normal1 * (horizontal_translation_remaining).dot(&hit.normal1); - - let vertical_slope_translation = - vertical_translation_remaining - - *hit.normal1 * (vertical_translation_remaining).dot(&hit.normal1); - + let [vertical_slope_translation, horizontal_slope_translation] = + self.split_into_components(translation_remaining) + .map(|remaining| subtract_hit(remaining, hit)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. @@ -514,6 +499,13 @@ impl KinematicCharacterController { } + fn split_into_components(&self, translation: &Vector) -> [Vector; 2] { + let vertical_translation = *self.up * (self.up.dot(translation)); + let horizontal_translation = *translation - vertical_translation; + [vertical_translation, horizontal_translation] + } + + fn handle_stairs( &self, bodies: &RigidBodySet, @@ -732,3 +724,8 @@ impl KinematicCharacterController { } } } + + +fn subtract_hit(translation: Vector, hit: &TOI) -> Vector { + translation - *hit.normal1 * (translation).dot(&hit.normal1) +} \ No newline at end of file From 18c59417def70a4d93632ca37786b529b969eee3 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:28:10 +0100 Subject: [PATCH 08/80] Cleanup function calls --- src/control/character_controller.rs | 38 ++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 0475a10..9888701 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -185,11 +185,8 @@ impl KinematicCharacterController { translation: Vector::zeros(), grounded: false, }; - - let extents = character_shape.compute_local_aabb().extents(); - let up_extent = extents.dot(&self.up); - let side_extent = (extents - *self.up * up_extent).norm(); - let dims = Vector2::new(side_extent, up_extent); + let dims = self.compute_dims(character_shape); + let offset = self.offset.eval(dims.y); // 1. Check and fix penetrations. self.check_and_fix_penetrations(); @@ -214,7 +211,6 @@ impl KinematicCharacterController { let mut max_iters = 20; let mut kinematic_friction_translation = Vector::zeros(); - let offset = self.offset.eval(dims.y); while let Some((translation_dir, translation_dist)) = UnitVector::try_new_and_get(translation_remaining, 1.0e-5) @@ -252,7 +248,7 @@ impl KinematicCharacterController { }); if let Some(translation_on_slope) = - self.handle_slopes(&toi, &mut translation_remaining) + self.handle_slopes(&toi, &mut translation_remaining, offset) { println!("[slope] translation_on_slope: {translation_on_slope:?}"); translation_remaining = translation_on_slope; @@ -273,6 +269,17 @@ impl KinematicCharacterController { ); if !stair_handled { println!("[stair] translation_remaining: {translation_remaining:?}"); + // No slopes or stairs ahead; try to move along obstacles. + + let [vertical_slope_translation, horizontal_slope_translation] = + self.split_into_components(&translation_remaining) + .map(|remaining| subtract_hit(remaining, &toi, offset)); + + let horizontal_allowed_dist = + (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); + let allowed_translation = *translation_dir * allowed_dist; + result.translation += allowed_translation; + translation_remaining -= allowed_translation; } } @@ -479,10 +486,11 @@ impl KinematicCharacterController { &self, hit: &TOI, translation_remaining: &Vector, + offset: Real, ) -> Option> { let [vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, hit)); + .map(|remaining| subtract_hit(remaining, hit, offset)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. @@ -506,6 +514,13 @@ impl KinematicCharacterController { } + fn compute_dims(&self, character_shape: &dyn Shape) -> Vector2 { + let extents = character_shape.compute_local_aabb().extents(); + let up_extent = extents.dot(&self.up); + let side_extent = (extents - *self.up * up_extent).norm(); + Vector2::new(side_extent, up_extent) + } + fn handle_stairs( &self, bodies: &RigidBodySet, @@ -725,7 +740,6 @@ impl KinematicCharacterController { } } - -fn subtract_hit(translation: Vector, hit: &TOI) -> Vector { - translation - *hit.normal1 * (translation).dot(&hit.normal1) -} \ No newline at end of file +fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { + translation - *hit.normal1 * (translation).dot(&hit.normal1) * (1.0 + offset) +} From 83a9c08b2c1070bf93710cb8c01ceb371021f74e Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:32:03 +0100 Subject: [PATCH 09/80] Apply translation left --- src/control/character_controller.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 9888701..91c5a98 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -271,13 +271,12 @@ impl KinematicCharacterController { println!("[stair] translation_remaining: {translation_remaining:?}"); // No slopes or stairs ahead; try to move along obstacles. - let [vertical_slope_translation, horizontal_slope_translation] = + let allowed_translation: Vector = self.split_into_components(&translation_remaining) - .map(|remaining| subtract_hit(remaining, &toi, offset)); + .map(|remaining| subtract_hit(remaining, &toi, offset)) + .into_iter() + .sum(); - let horizontal_allowed_dist = - (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); - let allowed_translation = *translation_dir * allowed_dist; result.translation += allowed_translation; translation_remaining -= allowed_translation; From ecd57a651905c54c2bddb8dcb64770da089e9ba5 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:37:34 +0100 Subject: [PATCH 10/80] Cut off invalid values --- src/control/character_controller.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 91c5a98..fe355a4 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -271,11 +271,7 @@ impl KinematicCharacterController { println!("[stair] translation_remaining: {translation_remaining:?}"); // No slopes or stairs ahead; try to move along obstacles. - let allowed_translation: Vector = - self.split_into_components(&translation_remaining) - .map(|remaining| subtract_hit(remaining, &toi, offset)) - .into_iter() - .sum(); + let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; translation_remaining -= allowed_translation; @@ -740,5 +736,5 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - translation - *hit.normal1 * (translation).dot(&hit.normal1) * (1.0 + offset) + translation - *hit.normal1 * ((translation).dot(&hit.normal1) * (1.0 + offset)).min(0.0) } From 4fcbd53bfe7c1d624e939a72fa25b44ebf67eb98 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:41:48 +0100 Subject: [PATCH 11/80] Refactor variable --- src/control/character_controller.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index fe355a4..19943f6 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -736,5 +736,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - translation - *hit.normal1 * ((translation).dot(&hit.normal1) * (1.0 + offset)).min(0.0) + let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); + translation - *hit.normal1 * hit_normal } From 8528c6e87b98ec5b7ee6a18aea405d6064dc7f1c Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 20:44:48 +0100 Subject: [PATCH 12/80] move debug prints --- src/control/character_controller.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 19943f6..45c14b3 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -250,8 +250,8 @@ impl KinematicCharacterController { if let Some(translation_on_slope) = self.handle_slopes(&toi, &mut translation_remaining, offset) { - println!("[slope] translation_on_slope: {translation_on_slope:?}"); translation_remaining = translation_on_slope; + println!("[slope] translation_on_slope: {translation_on_slope:?}"); println!("[slope] translation_remaining: {translation_remaining:?}"); } else { // If the slope is too big, try to step on the stair. @@ -267,12 +267,11 @@ impl KinematicCharacterController { &mut translation_remaining, &mut result, ); + println!("[stair] translation_remaining: {translation_remaining:?}"); + println!("[stair]stair_handled: {stair_handled:?}"); if !stair_handled { - println!("[stair] translation_remaining: {translation_remaining:?}"); // No slopes or stairs ahead; try to move along obstacles. - let allowed_translation = subtract_hit(translation_remaining, &toi, offset); - result.translation += allowed_translation; translation_remaining -= allowed_translation; From ff85d799565ad42d906f957eb6cdaad33fdda0d3 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 21:07:44 +0100 Subject: [PATCH 13/80] Add some early returns --- src/control/character_controller.rs | 251 ++++++++++++++-------------- 1 file changed, 125 insertions(+), 126 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 45c14b3..aaf2729 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -247,36 +247,31 @@ impl KinematicCharacterController { toi, }); - if let Some(translation_on_slope) = - self.handle_slopes(&toi, &mut translation_remaining, offset) - { - translation_remaining = translation_on_slope; - println!("[slope] translation_on_slope: {translation_on_slope:?}"); - println!("[slope] translation_remaining: {translation_remaining:?}"); - } else { - // If the slope is too big, try to step on the stair. - let stair_handled = self.handle_stairs( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - handle, - &mut translation_remaining, - &mut result, - ); - println!("[stair] translation_remaining: {translation_remaining:?}"); - println!("[stair]stair_handled: {stair_handled:?}"); - if !stair_handled { + // If the slope is too big, try to step on the stair. + if !self.handle_stairs( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + handle, + &mut translation_remaining, + &mut result, + ) { + if let Some(translation_on_slope) = + self.handle_slopes(&toi, &mut translation_remaining, offset) + { + translation_remaining = translation_on_slope; + } else { // No slopes or stairs ahead; try to move along obstacles. let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; translation_remaining -= allowed_translation; - } } + } else { // No interference along the path. result.translation += translation_remaining; @@ -490,6 +485,8 @@ impl KinematicCharacterController { // Check if there is a slope to climb. let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; + println!("angle_with_floor: {}, climbing: {}", angle_with_floor, climbing); + println!("max_slope_climb_angle: {}, min_slope_slide_angle: {}", self.max_slope_climb_angle, self.min_slope_slide_angle); climbing .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? @@ -528,125 +525,127 @@ impl KinematicCharacterController { translation_remaining: &mut Vector, result: &mut EffectiveCharacterMovement, ) -> bool { - if let Some(autostep) = self.autostep { - let min_width = autostep.min_width.eval(dims.x); - let max_height = autostep.max_height.eval(dims.y); + let autostep = match self.autostep { + Some(autostep) => autostep, + None => return false, + }; + let min_width = autostep.min_width.eval(dims.x); + let max_height = autostep.max_height.eval(dims.y); - if !autostep.include_dynamic_bodies { - if colliders - .get(stair_handle) - .and_then(|co| co.parent) - .and_then(|p| bodies.get(p.handle)) - .map(|b| b.is_dynamic()) - == Some(true) - { - // The "stair" is a dynamic body, which the user wants to ignore. - return false; - } - - filter.flags |= QueryFilterFlags::EXCLUDE_DYNAMIC; + if !autostep.include_dynamic_bodies { + if colliders + .get(stair_handle) + .and_then(|co| co.parent) + .and_then(|p| bodies.get(p.handle)) + .map(|b| b.is_dynamic()) + == Some(true) + { + // The "stair" is a dynamic body, which the user wants to ignore. + return false; } - let shifted_character_pos = Translation::from(*self.up * max_height) * character_pos; + filter.flags |= QueryFilterFlags::EXCLUDE_DYNAMIC; + } - if let Some(horizontal_dir) = (*translation_remaining - - *self.up * translation_remaining.dot(&self.up)) - .try_normalize(1.0e-5) - { - if queries - .cast_shape( - bodies, - colliders, - character_pos, - &self.up, - character_shape, - max_height, - false, - filter, - ) - .is_some() - { - // We can’t go up. - return false; - } + let shifted_character_pos = Translation::from(*self.up * max_height) * character_pos; - if queries - .cast_shape( - bodies, - colliders, - &shifted_character_pos, - &horizontal_dir, - character_shape, - min_width, - false, - filter, - ) - .is_some() - { - // We don’t have enough room on the stair to stay on it. - return false; - } + let horizontal_dir = match (*translation_remaining - *self.up * translation_remaining.dot(&self.up)) + .try_normalize(1.0e-5) { + Some(dir) => dir, + None => return false, + }; - // Check that we are not getting into a ramp that is too steep - // after stepping. - if let Some((_, hit)) = queries.cast_shape( + if queries + .cast_shape( + bodies, + colliders, + character_pos, + &self.up, + character_shape, + max_height, + false, + filter, + ) + .is_some() + { + // We can’t go up. + return false; + } + + if queries + .cast_shape( + bodies, + colliders, + &shifted_character_pos, + &horizontal_dir, + character_shape, + min_width, + false, + filter, + ) + .is_some() + { + // We don’t have enough room on the stair to stay on it. + return false; + } + + // Check that we are not getting into a ramp that is too steep + // after stepping. + if let Some((_, hit)) = queries.cast_shape( + bodies, + colliders, + &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), + &-self.up, + character_shape, + max_height, + false, + filter, + ) { + let vertical_translation_remaining = + *self.up * (self.up.dot(translation_remaining)); + let horizontal_translation_remaining = + *translation_remaining - vertical_translation_remaining; + let sliding_movement = horizontal_translation_remaining + - *hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1); + + let angle_with_floor = self.up.angle(&hit.normal1); + let climbing = self.up.dot(&sliding_movement) >= 0.0; + + if climbing && angle_with_floor > self.max_slope_climb_angle { + return false; // The target ramp is too steep. + } + } + + // We can step, we need to find the actual step height. + let step_height = self.offset.eval(dims.y) + max_height + - queries + .cast_shape( bodies, colliders, - &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), + &(Translation::from(horizontal_dir * min_width) + * shifted_character_pos), &-self.up, character_shape, max_height, false, filter, - ) { - let vertical_translation_remaining = - *self.up * (self.up.dot(translation_remaining)); - let horizontal_translation_remaining = - *translation_remaining - vertical_translation_remaining; - let sliding_movement = horizontal_translation_remaining - - *hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1); + ) + .map(|hit| hit.1.toi) + .unwrap_or(max_height); - let angle_with_floor = self.up.angle(&hit.normal1); - let climbing = self.up.dot(&sliding_movement) >= 0.0; + // Remove the step height from the vertical part of the self. + *translation_remaining -= + *self.up * translation_remaining.dot(&self.up).clamp(0.0, step_height); - if climbing && angle_with_floor > self.max_slope_climb_angle { - return false; // The target ramp is too steep. - } - } + // Advance the collider on the step horizontally, to make sure further + // movement won’t just get stuck on its edge. + let horizontal_nudge = + horizontal_dir * min_width.min(horizontal_dir.dot(translation_remaining)); + *translation_remaining -= horizontal_nudge; - // We can step, we need to find the actual step height. - let step_height = self.offset.eval(dims.y) + max_height - - queries - .cast_shape( - bodies, - colliders, - &(Translation::from(horizontal_dir * min_width) - * shifted_character_pos), - &-self.up, - character_shape, - max_height, - false, - filter, - ) - .map(|hit| hit.1.toi) - .unwrap_or(max_height); + result.translation += *self.up * step_height + horizontal_nudge; + return true; - // Remove the step height from the vertical part of the self. - *translation_remaining -= - *self.up * translation_remaining.dot(&self.up).clamp(0.0, step_height); - - // Advance the collider on the step horizontally, to make sure further - // movement won’t just get stuck on its edge. - let horizontal_nudge = - horizontal_dir * min_width.min(horizontal_dir.dot(translation_remaining)); - *translation_remaining -= horizontal_nudge; - - result.translation += *self.up * step_height + horizontal_nudge; - return true; - } - } - - false } /// For a given collision between a character and its environment, this method will apply From 6701108f6f0f8b2543c503958a5d93cc1b91d71f Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 21:14:49 +0100 Subject: [PATCH 14/80] Check downwards stairs --- src/control/character_controller.rs | 37 +++++++++++++++++++---------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index aaf2729..e16ca39 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -259,7 +259,20 @@ impl KinematicCharacterController { handle, &mut translation_remaining, &mut result, - ) { + &self.up + ) && !self.handle_stairs( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + handle, + &mut translation_remaining, + &mut result, + &-self.up + ){ if let Some(translation_on_slope) = self.handle_slopes(&toi, &mut translation_remaining, offset) { @@ -524,6 +537,7 @@ impl KinematicCharacterController { stair_handle: ColliderHandle, translation_remaining: &mut Vector, result: &mut EffectiveCharacterMovement, + stair_dir: &Vector, ) -> bool { let autostep = match self.autostep { Some(autostep) => autostep, @@ -547,9 +561,9 @@ impl KinematicCharacterController { filter.flags |= QueryFilterFlags::EXCLUDE_DYNAMIC; } - let shifted_character_pos = Translation::from(*self.up * max_height) * character_pos; + let shifted_character_pos = Translation::from(*stair_dir * max_height) * character_pos; - let horizontal_dir = match (*translation_remaining - *self.up * translation_remaining.dot(&self.up)) + let horizontal_dir = match (*translation_remaining - *stair_dir * translation_remaining.dot(&stair_dir)) .try_normalize(1.0e-5) { Some(dir) => dir, None => return false, @@ -560,7 +574,7 @@ impl KinematicCharacterController { bodies, colliders, character_pos, - &self.up, + &stair_dir, character_shape, max_height, false, @@ -595,21 +609,21 @@ impl KinematicCharacterController { bodies, colliders, &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), - &-self.up, + &-stair_dir, character_shape, max_height, false, filter, ) { let vertical_translation_remaining = - *self.up * (self.up.dot(translation_remaining)); + *stair_dir * (stair_dir.dot(translation_remaining)); let horizontal_translation_remaining = *translation_remaining - vertical_translation_remaining; let sliding_movement = horizontal_translation_remaining - *hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1); - let angle_with_floor = self.up.angle(&hit.normal1); - let climbing = self.up.dot(&sliding_movement) >= 0.0; + let angle_with_floor = stair_dir.angle(&hit.normal1); + let climbing = stair_dir.dot(&sliding_movement) >= 0.0; if climbing && angle_with_floor > self.max_slope_climb_angle { return false; // The target ramp is too steep. @@ -624,7 +638,7 @@ impl KinematicCharacterController { colliders, &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), - &-self.up, + &-stair_dir, character_shape, max_height, false, @@ -635,7 +649,7 @@ impl KinematicCharacterController { // Remove the step height from the vertical part of the self. *translation_remaining -= - *self.up * translation_remaining.dot(&self.up).clamp(0.0, step_height); + *stair_dir * translation_remaining.dot(&stair_dir).clamp(0.0, step_height); // Advance the collider on the step horizontally, to make sure further // movement won’t just get stuck on its edge. @@ -643,9 +657,8 @@ impl KinematicCharacterController { horizontal_dir * min_width.min(horizontal_dir.dot(translation_remaining)); *translation_remaining -= horizontal_nudge; - result.translation += *self.up * step_height + horizontal_nudge; + result.translation += *stair_dir * step_height + horizontal_nudge; return true; - } /// For a given collision between a character and its environment, this method will apply From 3cabe58ac650fa6054af761ba59329d4d00d1154 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 21:21:09 +0100 Subject: [PATCH 15/80] Remove debug prints --- src/control/character_controller.rs | 64 ++++++++++++----------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index e16ca39..2aec8a7 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -247,42 +247,32 @@ impl KinematicCharacterController { toi, }); - // If the slope is too big, try to step on the stair. - if !self.handle_stairs( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - handle, - &mut translation_remaining, - &mut result, - &self.up - ) && !self.handle_stairs( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - handle, - &mut translation_remaining, - &mut result, - &-self.up - ){ - if let Some(translation_on_slope) = - self.handle_slopes(&toi, &mut translation_remaining, offset) - { - translation_remaining = translation_on_slope; - } else { - // No slopes or stairs ahead; try to move along obstacles. - let allowed_translation = subtract_hit(translation_remaining, &toi, offset); - result.translation += allowed_translation; - translation_remaining -= allowed_translation; - } + if ![self.up, -self.up] // Try to move up or down stairs + .iter() + .any(|up| self.handle_stairs( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + handle, + &mut translation_remaining, + &mut result, + up + )) { + // No stairs, try to move along slopes. + if let Some(translation_on_slope) = + self.handle_slopes(&toi, &mut translation_remaining, offset) + { + translation_remaining = translation_on_slope; + } else { + // No slopes or stairs ahead; try to move along obstacles. + let allowed_translation = subtract_hit(translation_remaining, &toi, offset); + result.translation += allowed_translation; + translation_remaining -= allowed_translation; + } } } else { @@ -498,8 +488,6 @@ impl KinematicCharacterController { // Check if there is a slope to climb. let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; - println!("angle_with_floor: {}, climbing: {}", angle_with_floor, climbing); - println!("max_slope_climb_angle: {}, min_slope_slide_angle: {}", self.max_slope_climb_angle, self.min_slope_slide_angle); climbing .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? From 9a0757aeae758e9ab0c576687cdc97d9f371376e Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 21:43:56 +0100 Subject: [PATCH 16/80] Fix indentation --- src/control/character_controller.rs | 39 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 2aec8a7..4e51258 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -262,17 +262,17 @@ impl KinematicCharacterController { &mut result, up )) { - // No stairs, try to move along slopes. - if let Some(translation_on_slope) = - self.handle_slopes(&toi, &mut translation_remaining, offset) - { - translation_remaining = translation_on_slope; - } else { - // No slopes or stairs ahead; try to move along obstacles. - let allowed_translation = subtract_hit(translation_remaining, &toi, offset); - result.translation += allowed_translation; - translation_remaining -= allowed_translation; - } + // No stairs, try to move along slopes. + if let Some(translation_on_slope) = + self.handle_slopes(&toi, &mut translation_remaining, offset) + { + translation_remaining = translation_on_slope; + } else { + // No slopes or stairs ahead; try to move along obstacles. + let allowed_translation = subtract_hit(translation_remaining, &toi, offset); + result.translation += allowed_translation; + translation_remaining -= allowed_translation; + } } } else { @@ -591,6 +591,7 @@ impl KinematicCharacterController { return false; } + let offset = self.offset.eval(dims.y); // Check that we are not getting into a ramp that is too steep // after stepping. if let Some((_, hit)) = queries.cast_shape( @@ -603,15 +604,13 @@ impl KinematicCharacterController { false, filter, ) { - let vertical_translation_remaining = - *stair_dir * (stair_dir.dot(translation_remaining)); - let horizontal_translation_remaining = - *translation_remaining - vertical_translation_remaining; - let sliding_movement = horizontal_translation_remaining - - *hit.normal1 * horizontal_translation_remaining.dot(&hit.normal1); + let [_vertical_slope_translation, horizontal_slope_translation] = + self.split_into_components(translation_remaining) + .map(|remaining| subtract_hit(remaining, &hit, offset)); + let angle_with_floor = stair_dir.angle(&hit.normal1); - let climbing = stair_dir.dot(&sliding_movement) >= 0.0; + let climbing = stair_dir.dot(&horizontal_slope_translation) >= 0.0; if climbing && angle_with_floor > self.max_slope_climb_angle { return false; // The target ramp is too steep. @@ -619,7 +618,7 @@ impl KinematicCharacterController { } // We can step, we need to find the actual step height. - let step_height = self.offset.eval(dims.y) + max_height + let step_height = offset + max_height - queries .cast_shape( bodies, @@ -637,7 +636,7 @@ impl KinematicCharacterController { // Remove the step height from the vertical part of the self. *translation_remaining -= - *stair_dir * translation_remaining.dot(&stair_dir).clamp(0.0, step_height); + *stair_dir * ((translation_remaining.dot(&stair_dir)).clamp(0.0, step_height) + offset); // Advance the collider on the step horizontally, to make sure further // movement won’t just get stuck on its edge. From d5946f623bef8b158e113f84701e448b07ae75b7 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 21:46:29 +0100 Subject: [PATCH 17/80] Disallow goin up/down upside-down stairs --- src/control/character_controller.rs | 49 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 4e51258..1007f1d 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -247,28 +247,26 @@ impl KinematicCharacterController { toi, }); - if ![self.up, -self.up] // Try to move up or down stairs - .iter() - .any(|up| self.handle_stairs( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - handle, - &mut translation_remaining, - &mut result, - up - )) { + // Try to go up stairs. + if !self.handle_stairs( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + handle, + &mut translation_remaining, + &mut result, + ) { // No stairs, try to move along slopes. if let Some(translation_on_slope) = self.handle_slopes(&toi, &mut translation_remaining, offset) { translation_remaining = translation_on_slope; } else { - // No slopes or stairs ahead; try to move along obstacles. + // No slopes or stairs ahead; try to move along obstacle. let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; translation_remaining -= allowed_translation; @@ -525,7 +523,6 @@ impl KinematicCharacterController { stair_handle: ColliderHandle, translation_remaining: &mut Vector, result: &mut EffectiveCharacterMovement, - stair_dir: &Vector, ) -> bool { let autostep = match self.autostep { Some(autostep) => autostep, @@ -549,9 +546,9 @@ impl KinematicCharacterController { filter.flags |= QueryFilterFlags::EXCLUDE_DYNAMIC; } - let shifted_character_pos = Translation::from(*stair_dir * max_height) * character_pos; + let shifted_character_pos = Translation::from(*self.up * max_height) * character_pos; - let horizontal_dir = match (*translation_remaining - *stair_dir * translation_remaining.dot(&stair_dir)) + let horizontal_dir = match (*translation_remaining - *self.up * translation_remaining.dot(&self.up)) .try_normalize(1.0e-5) { Some(dir) => dir, None => return false, @@ -562,7 +559,7 @@ impl KinematicCharacterController { bodies, colliders, character_pos, - &stair_dir, + &self.up, character_shape, max_height, false, @@ -598,7 +595,7 @@ impl KinematicCharacterController { bodies, colliders, &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), - &-stair_dir, + &-self.up, character_shape, max_height, false, @@ -609,8 +606,8 @@ impl KinematicCharacterController { .map(|remaining| subtract_hit(remaining, &hit, offset)); - let angle_with_floor = stair_dir.angle(&hit.normal1); - let climbing = stair_dir.dot(&horizontal_slope_translation) >= 0.0; + let angle_with_floor = self.up.angle(&hit.normal1); + let climbing = self.up.dot(&horizontal_slope_translation) >= 0.0; if climbing && angle_with_floor > self.max_slope_climb_angle { return false; // The target ramp is too steep. @@ -625,7 +622,7 @@ impl KinematicCharacterController { colliders, &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), - &-stair_dir, + &-self.up, character_shape, max_height, false, @@ -636,7 +633,7 @@ impl KinematicCharacterController { // Remove the step height from the vertical part of the self. *translation_remaining -= - *stair_dir * ((translation_remaining.dot(&stair_dir)).clamp(0.0, step_height) + offset); + *self.up * ((translation_remaining.dot(&self.up)).clamp(0.0, step_height) + offset); // Advance the collider on the step horizontally, to make sure further // movement won’t just get stuck on its edge. @@ -644,7 +641,7 @@ impl KinematicCharacterController { horizontal_dir * min_width.min(horizontal_dir.dot(translation_remaining)); *translation_remaining -= horizontal_nudge; - result.translation += *stair_dir * step_height + horizontal_nudge; + result.translation += *self.up * step_height + horizontal_nudge; return true; } From c3b0bde6b229304949255a33ceda838983570f72 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:02:36 +0100 Subject: [PATCH 18/80] Fix offset being gone after snapping to ground --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 1007f1d..6c2d89f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -342,7 +342,7 @@ impl KinematicCharacterController { filter, ) { // Apply the snap. - result.translation -= *self.up * (hit.toi - offset).max(0.0); + result.translation -= *self.up * (hit.toi - offset); result.grounded = true; return Some((hit_handle, hit)); } From 485e1d91692614f61957ea46b2e677f2e4950d27 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:10:15 +0100 Subject: [PATCH 19/80] Play around wit grounded expectation --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 6c2d89f..5b31acc 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.1; + let prediction = self.offset.eval(dims.y); // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From ff7ccc561ad88f7f068f083fa2ab6f413f5a8fb9 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:12:49 +0100 Subject: [PATCH 20/80] Remove wrong prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5b31acc..6c2d89f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y); + let prediction = self.offset.eval(dims.y) * 1.1; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From c63e2f2cbd8e88c6a22faf62fe4c6e4e7aca45e1 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:15:01 +0100 Subject: [PATCH 21/80] Fix faulty offset application --- src/control/character_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 6c2d89f..0714749 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -615,7 +615,7 @@ impl KinematicCharacterController { } // We can step, we need to find the actual step height. - let step_height = offset + max_height + let step_height = max_height - queries .cast_shape( bodies, @@ -628,12 +628,12 @@ impl KinematicCharacterController { false, filter, ) - .map(|hit| hit.1.toi) + .map(|hit| hit.1.toi + offset) .unwrap_or(max_height); // Remove the step height from the vertical part of the self. *translation_remaining -= - *self.up * ((translation_remaining.dot(&self.up)).clamp(0.0, step_height) + offset); + *self.up * ((translation_remaining.dot(&self.up)).clamp(0.0, step_height)); // Advance the collider on the step horizontally, to make sure further // movement won’t just get stuck on its edge. From 6a75ed4b63f33693d9416f6de47f9d84e5aadc9b Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:19:18 +0100 Subject: [PATCH 22/80] Try what happens without offset I think should be correct --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 0714749..b7d0503 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -628,7 +628,7 @@ impl KinematicCharacterController { false, filter, ) - .map(|hit| hit.1.toi + offset) + .map(|hit| hit.1.toi) .unwrap_or(max_height); // Remove the step height from the vertical part of the self. From b69c9c48135aafd5daf27e4ca9044048b42a5bc4 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:27:16 +0100 Subject: [PATCH 23/80] Increase prediction threshold --- src/control/character_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index b7d0503..de62011 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.1; + let prediction = self.offset.eval(dims.y) * 1.2; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -628,7 +628,7 @@ impl KinematicCharacterController { false, filter, ) - .map(|hit| hit.1.toi) + .map(|hit| hit.1.toi + offset) .unwrap_or(max_height); // Remove the step height from the vertical part of the self. @@ -664,7 +664,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent) * 1.1; + let prediction = self.offset.eval(up_extent) * 1.2; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From 6a437f47a9bc188250d9ab9d6c54a7779b8684fa Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:33:53 +0100 Subject: [PATCH 24/80] Try to fix offset --- src/control/character_controller.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index de62011..d44fd2c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.2; + let prediction = self.offset.eval(dims.y) * 1.1; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -603,7 +603,7 @@ impl KinematicCharacterController { ) { let [_vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, offset)); + .map(|remaining| subtract_hit(remaining, &hit, 0.)); let angle_with_floor = self.up.angle(&hit.normal1); @@ -628,7 +628,7 @@ impl KinematicCharacterController { false, filter, ) - .map(|hit| hit.1.toi + offset) + .map(|hit| hit.1.toi) .unwrap_or(max_height); // Remove the step height from the vertical part of the self. @@ -664,7 +664,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent) * 1.2; + let prediction = self.offset.eval(up_extent) * 1.1; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From c0c8ddb9d4703158b17f93236c7368f6460faa51 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:36:41 +0100 Subject: [PATCH 25/80] Remove offset --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index d44fd2c..1108285 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -603,7 +603,7 @@ impl KinematicCharacterController { ) { let [_vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, 0.)); + .map(|remaining| subtract_hit(remaining, &hit, offset)); let angle_with_floor = self.up.angle(&hit.normal1); @@ -731,6 +731,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); + let hit_normal = (translation.dot(&hit.normal1) * (1.0 + 0.)).min(0.0); translation - *hit.normal1 * hit_normal } From 1ff579164be0b0daa05309879f2a84ec8c08f2aa Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:39:49 +0100 Subject: [PATCH 26/80] Play with predictions --- src/control/character_controller.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 1108285..975ac91 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -228,7 +228,7 @@ impl KinematicCharacterController { &(Translation::from(result.translation) * character_pos), &translation_dir, character_shape, - translation_dist + offset, + translation_dist - offset, false, filter, ) { @@ -337,7 +337,7 @@ impl KinematicCharacterController { character_pos, &-self.up, character_shape, - snap_distance + offset, + snap_distance - offset, false, filter, ) { @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.1; + let prediction = self.offset.eval(dims.y) * 1.0; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -664,7 +664,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent) * 1.1; + let prediction = self.offset.eval(up_extent) * 1.0; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From d6ae55b4bed0c3708fb4f32a5bed196e3b335941 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:42:40 +0100 Subject: [PATCH 27/80] Add offset back in --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 975ac91..cc3624a 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -731,6 +731,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let hit_normal = (translation.dot(&hit.normal1) * (1.0 + 0.)).min(0.0); + let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); translation - *hit.normal1 * hit_normal } From 1482106a1e4283a57326e193657e3e467f3e8c0d Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:47:29 +0100 Subject: [PATCH 28/80] Play around with offset --- src/control/character_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index cc3624a..ff59d0e 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -365,7 +365,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.0; + let prediction = self.offset.eval(dims.y); // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -603,7 +603,7 @@ impl KinematicCharacterController { ) { let [_vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, offset)); + .map(|remaining| subtract_hit(remaining, &hit, 0.)); let angle_with_floor = self.up.angle(&hit.normal1); @@ -664,7 +664,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent) * 1.0; + let prediction = self.offset.eval(up_extent); // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From 848fe9f4735d776684cd5197be7f44817f4adc2a Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:51:28 +0100 Subject: [PATCH 29/80] Play around with offset --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index ff59d0e..8fb4b7f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -267,7 +267,7 @@ impl KinematicCharacterController { translation_remaining = translation_on_slope; } else { // No slopes or stairs ahead; try to move along obstacle. - let allowed_translation = subtract_hit(translation_remaining, &toi, offset); + let allowed_translation = subtract_hit(translation_remaining, &toi, 0.); result.translation += allowed_translation; translation_remaining -= allowed_translation; } From d5cd4fe4bc36feaae40a41f0d07d8bffae4383d5 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:54:51 +0100 Subject: [PATCH 30/80] Only apply snap if necessary --- src/control/character_controller.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 8fb4b7f..ef8973c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -342,7 +342,10 @@ impl KinematicCharacterController { filter, ) { // Apply the snap. - result.translation -= *self.up * (hit.toi - offset); + let snap_distance = hit.toi - offset; + if snap_distance.abs() > 1.0e-5 { + result.translation -= *self.up * snap_distance; + } result.grounded = true; return Some((hit_handle, hit)); } From 5d7fdebea43b8cd09217f2666d1ad101fa29bb9a Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Thu, 26 Jan 2023 23:55:16 +0100 Subject: [PATCH 31/80] Play around with offset --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index ef8973c..d49019c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -734,6 +734,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); + let hit_normal = (translation.dot(&hit.normal1) * (1.0 + 0.)).min(0.0); translation - *hit.normal1 * hit_normal } From 30058a61ea90cc32270763894459d40941b7dd8d Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 00:01:32 +0100 Subject: [PATCH 32/80] extend prediction --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index d49019c..a91e8b4 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -368,7 +368,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y); + let prediction = self.offset.eval(dims.y) * 1.2; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -667,7 +667,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent); + let prediction = self.offset.eval(up_extent) * 1.2; // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From e6035ed998e240bbf7092dd7ead612e766eca0d7 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 00:13:21 +0100 Subject: [PATCH 33/80] Reintroduce offset --- src/control/character_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index a91e8b4..23dd12c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -267,7 +267,7 @@ impl KinematicCharacterController { translation_remaining = translation_on_slope; } else { // No slopes or stairs ahead; try to move along obstacle. - let allowed_translation = subtract_hit(translation_remaining, &toi, 0.); + let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; translation_remaining -= allowed_translation; } @@ -606,7 +606,7 @@ impl KinematicCharacterController { ) { let [_vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, 0.)); + .map(|remaining| subtract_hit(remaining, &hit, offset)); let angle_with_floor = self.up.angle(&hit.normal1); @@ -734,6 +734,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let hit_normal = (translation.dot(&hit.normal1) * (1.0 + 0.)).min(0.0); + let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); translation - *hit.normal1 * hit_normal } From 9337093d838f6a50ccf5cf99e75ebce9e52c3619 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 00:18:57 +0100 Subject: [PATCH 34/80] Remove duplicated code --- src/control/character_controller.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 23dd12c..5ee58df 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -355,6 +355,10 @@ impl KinematicCharacterController { None } + fn predict_ground(&self, up_extends: Real) -> Real { + self.offset.eval(up_extends) * 1.3 + } + fn detect_grounded_status_and_apply_friction( &self, dt: Real, @@ -368,7 +372,7 @@ impl KinematicCharacterController { mut kinematic_friction_translation: Option<&mut Vector>, mut translation_remaining: Option<&mut Vector>, ) -> bool { - let prediction = self.offset.eval(dims.y) * 1.2; + let prediction = self.predict_ground(dims.y); // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; @@ -667,7 +671,7 @@ impl KinematicCharacterController { let up_extent = extents.dot(&self.up); let movement_to_transfer = *collision.toi.normal1 * collision.translation_remaining.dot(&collision.toi.normal1); - let prediction = self.offset.eval(up_extent) * 1.2; + let prediction = self.predict_ground(up_extent); // TODO: allow custom dispatchers. let dispatcher = DefaultQueryDispatcher; From 942cf76150c410048c13b29f1ca084896cf57f0f Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 00:22:30 +0100 Subject: [PATCH 35/80] Update prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5ee58df..39fa9b0 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.3 + self.offset.eval(up_extends) * 1.4 } fn detect_grounded_status_and_apply_friction( From eaa3d8e259925903584780f11cbfe7dcc297ac5b Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 14:10:14 +0100 Subject: [PATCH 36/80] Remove unnecessary clamp --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 39fa9b0..1b5a792 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -738,6 +738,6 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let hit_normal = (translation.dot(&hit.normal1) * (1.0 + offset)).min(0.0); - translation - *hit.normal1 * hit_normal + let surface_correction = translation.dot(&hit.normal1) * (1.0 + offset); + translation - *hit.normal1 * surface_correction } From 7bfa593d3f370afc0fe2f9680d99fa4c7bc0cee1 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 14:48:44 +0100 Subject: [PATCH 37/80] Fix slightly incorrect snapping --- src/control/character_controller.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 1b5a792..ec0e04e 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -328,20 +328,20 @@ impl KinematicCharacterController { result: &mut EffectiveCharacterMovement, ) -> Option<(ColliderHandle, TOI)> { if let Some(snap_distance) = self.snap_to_ground { - let snap_distance = snap_distance.eval(dims.y); if result.translation.dot(&self.up) < 1.0e-5 { - let offset = self.offset.eval(dims.y); + let snap_distance = snap_distance.eval(dims.y); if let Some((hit_handle, hit)) = queries.cast_shape( bodies, colliders, character_pos, &-self.up, character_shape, - snap_distance - offset, - false, + snap_distance, + true, filter, ) { // Apply the snap. + let offset = self.offset.eval(dims.y); let snap_distance = hit.toi - offset; if snap_distance.abs() > 1.0e-5 { result.translation -= *self.up * snap_distance; From 247ed510b4fa08195fd54bf8736194a8d168783b Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 15:08:41 +0100 Subject: [PATCH 38/80] Fix horizontal offset not being respected --- src/control/character_controller.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index ec0e04e..06e7ff0 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -228,13 +228,13 @@ impl KinematicCharacterController { &(Translation::from(result.translation) * character_pos), &translation_dir, character_shape, - translation_dist - offset, + translation_dist, false, filter, ) { // We hit something, compute the allowed self. let allowed_dist = - (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); + toi.toi - (toi.normal1.dot(&translation_dir)).abs() * offset; let allowed_translation = *translation_dir * allowed_dist; result.translation += allowed_translation; translation_remaining -= allowed_translation; @@ -337,7 +337,7 @@ impl KinematicCharacterController { &-self.up, character_shape, snap_distance, - true, + false, filter, ) { // Apply the snap. @@ -738,6 +738,7 @@ impl KinematicCharacterController { } fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let surface_correction = translation.dot(&hit.normal1) * (1.0 + offset); - translation - *hit.normal1 * surface_correction + let surface_correction = translation.dot(&hit.normal1).abs(); + let surface_correction = surface_correction + offset; + translation + *hit.normal1 * surface_correction } From fa9ab6c2bc80643e461b0ad5d0b9614a98831c87 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 15:50:41 +0100 Subject: [PATCH 39/80] Fix uncontrolled sliding --- src/control/character_controller.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 06e7ff0..fa352ba 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -485,9 +485,11 @@ impl KinematicCharacterController { translation_remaining: &Vector, offset: Real, ) -> Option> { + let [vertical_translation, horizontal_translation] = + self.split_into_components(translation_remaining); let [vertical_slope_translation, horizontal_slope_translation] = - self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, hit, offset)); + [vertical_translation, horizontal_translation] + .map(|remaining| subtract_hit(remaining, hit, offset)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. @@ -496,10 +498,10 @@ impl KinematicCharacterController { climbing .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? - .then_some(slope_translation)) + .then_some(horizontal_translation )) .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle)// Are we allowed to slide? - .then_some(slope_translation) - .unwrap_or(horizontal_slope_translation) + .then_some(slope_translation ) + .unwrap_or(horizontal_translation) .into()) } From 22e92711d97e5cb4bc855ee72661e5413aa9727d Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 17:08:12 +0100 Subject: [PATCH 40/80] Tweak prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index fa352ba..efa65b0 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.4 + self.offset.eval(up_extends) * 1.1 } fn detect_grounded_status_and_apply_friction( From de42b779711052d8ec02d4083be5def1b6d89040 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 17:11:36 +0100 Subject: [PATCH 41/80] Tweak prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index efa65b0..fa352ba 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.1 + self.offset.eval(up_extends) * 1.4 } fn detect_grounded_status_and_apply_friction( From 014bbba042e15c244cb51440c424bc19c7a05f15 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 17:12:49 +0100 Subject: [PATCH 42/80] Tweak prediction --- src/control/character_controller.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index fa352ba..288e834 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -330,18 +330,18 @@ impl KinematicCharacterController { if let Some(snap_distance) = self.snap_to_ground { if result.translation.dot(&self.up) < 1.0e-5 { let snap_distance = snap_distance.eval(dims.y); + let offset = self.offset.eval(dims.y); if let Some((hit_handle, hit)) = queries.cast_shape( bodies, colliders, character_pos, &-self.up, character_shape, - snap_distance, + snap_distance + offset, false, filter, ) { // Apply the snap. - let offset = self.offset.eval(dims.y); let snap_distance = hit.toi - offset; if snap_distance.abs() > 1.0e-5 { result.translation -= *self.up * snap_distance; @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.4 + self.offset.eval(up_extends) * 1.3 } fn detect_grounded_status_and_apply_friction( From b93c6b5766b7c74d9441038a54edbfce0a14796c Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 17:20:12 +0100 Subject: [PATCH 43/80] Fix missing account for offset --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 288e834..aa7a9c6 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -228,7 +228,7 @@ impl KinematicCharacterController { &(Translation::from(result.translation) * character_pos), &translation_dir, character_shape, - translation_dist, + translation_dist + offset, false, filter, ) { @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.3 + self.offset.eval(up_extends) * 1.4 } fn detect_grounded_status_and_apply_friction( From 05db3e8e0a132ac26adbe5dc4e1573a6e7e3d557 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 17:54:20 +0100 Subject: [PATCH 44/80] Stop shape cast at penetration --- src/control/character_controller.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index aa7a9c6..6108487 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -229,7 +229,7 @@ impl KinematicCharacterController { &translation_dir, character_shape, translation_dist + offset, - false, + true, filter, ) { // We hit something, compute the allowed self. @@ -338,7 +338,7 @@ impl KinematicCharacterController { &-self.up, character_shape, snap_distance + offset, - false, + true, filter, ) { // Apply the snap. @@ -571,7 +571,7 @@ impl KinematicCharacterController { &self.up, character_shape, max_height, - false, + true, filter, ) .is_some() @@ -588,7 +588,7 @@ impl KinematicCharacterController { &horizontal_dir, character_shape, min_width, - false, + true, filter, ) .is_some() @@ -607,7 +607,7 @@ impl KinematicCharacterController { &-self.up, character_shape, max_height, - false, + true, filter, ) { let [_vertical_slope_translation, horizontal_slope_translation] = @@ -634,7 +634,7 @@ impl KinematicCharacterController { &-self.up, character_shape, max_height, - false, + true, filter, ) .map(|hit| hit.1.toi) From 0f6aa4942207d81d41462dd3e782d1f23a2a2e62 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 18:02:48 +0100 Subject: [PATCH 45/80] Add debug prints to grounded --- src/control/character_controller.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 6108487..21d8835 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -346,6 +346,7 @@ impl KinematicCharacterController { if snap_distance.abs() > 1.0e-5 { result.translation -= *self.up * snap_distance; } + println!("snap"); result.grounded = true; return Some((hit_handle, hit)); } @@ -413,6 +414,7 @@ impl KinematicCharacterController { let normal2 = -normal1; if normal1.dot(&self.up) <= -1.0e-5 { + println!("Grounded 1"); grounded = true; } @@ -464,6 +466,7 @@ impl KinematicCharacterController { if normal.dot(&self.up) <= -1.0e-5 { for contact in &m.points { if contact.dist <= prediction { + println!("Grounded 2"); grounded = true; return false; // We can stop the search early. } From 29dd3189baff85196af2bf1d2a447cba0df805f4 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 18:08:12 +0100 Subject: [PATCH 46/80] Add some abs to checks --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 21d8835..48db3d4 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -413,7 +413,7 @@ impl KinematicCharacterController { let normal1 = character_pos * m.local_n1; let normal2 = -normal1; - if normal1.dot(&self.up) <= -1.0e-5 { + if normal1.dot(&self.up).abs() <= -1.0e-5 { println!("Grounded 1"); grounded = true; } @@ -463,7 +463,7 @@ impl KinematicCharacterController { for m in &manifolds { let normal = character_pos * m.local_n1; - if normal.dot(&self.up) <= -1.0e-5 { + if normal.dot(&self.up).abs() <= -1.0e-5 { for contact in &m.points { if contact.dist <= prediction { println!("Grounded 2"); From e25b61b4bb573e999b6dfe1102c5c0d157a0dfde Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 18:13:24 +0100 Subject: [PATCH 47/80] Remove debug prints --- src/control/character_controller.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 48db3d4..6108487 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -346,7 +346,6 @@ impl KinematicCharacterController { if snap_distance.abs() > 1.0e-5 { result.translation -= *self.up * snap_distance; } - println!("snap"); result.grounded = true; return Some((hit_handle, hit)); } @@ -413,8 +412,7 @@ impl KinematicCharacterController { let normal1 = character_pos * m.local_n1; let normal2 = -normal1; - if normal1.dot(&self.up).abs() <= -1.0e-5 { - println!("Grounded 1"); + if normal1.dot(&self.up) <= -1.0e-5 { grounded = true; } @@ -463,10 +461,9 @@ impl KinematicCharacterController { for m in &manifolds { let normal = character_pos * m.local_n1; - if normal.dot(&self.up).abs() <= -1.0e-5 { + if normal.dot(&self.up) <= -1.0e-5 { for contact in &m.points { if contact.dist <= prediction { - println!("Grounded 2"); grounded = true; return false; // We can stop the search early. } From f0563521a327811b5c09fdd194f115fcb2b928fc Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:10:14 +0100 Subject: [PATCH 48/80] Remove redundant ground assignment --- src/control/character_controller.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 6108487..876714f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -409,12 +409,7 @@ impl KinematicCharacterController { .filter(|rb| rb.is_kinematic()); for m in &manifolds { - let normal1 = character_pos * m.local_n1; - let normal2 = -normal1; - - if normal1.dot(&self.up) <= -1.0e-5 { - grounded = true; - } + let normal = -(character_pos * m.local_n1); if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; @@ -427,12 +422,12 @@ impl KinematicCharacterController { let target_vel = kinematic_parent.velocity_at_point(&contact_point); - let normal_target_mvt = target_vel.dot(&normal2) * dt; + let normal_target_mvt = target_vel.dot(&normal) * dt; let normal_current_mvt = - translation_remaining.dot(&normal2); + translation_remaining.dot(&normal); manifold_center += contact_point.coords; - *translation_remaining += normal2 + *translation_remaining += normal * (normal_target_mvt - normal_current_mvt).max(0.0); } } @@ -442,7 +437,7 @@ impl KinematicCharacterController { &(manifold_center / num_active_contacts as Real), ); let tangent_platform_mvt = - (target_vel - normal2 * target_vel.dot(&normal2)) * dt; + (target_vel - normal * target_vel.dot(&normal)) * dt; kinematic_friction_translation.zip_apply( &tangent_platform_mvt, |y, x| { From 5bf57c6c50204d1b057234a207c102b3f2fa69f1 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:35:26 +0100 Subject: [PATCH 49/80] Fix errors from early stops at penetration when casting --- src/control/character_controller.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 876714f..5783103 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -229,7 +229,7 @@ impl KinematicCharacterController { &translation_dir, character_shape, translation_dist + offset, - true, + false, filter, ) { // We hit something, compute the allowed self. @@ -338,7 +338,7 @@ impl KinematicCharacterController { &-self.up, character_shape, snap_distance + offset, - true, + false, filter, ) { // Apply the snap. @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.4 + self.offset.eval(up_extends) * 1.1 } fn detect_grounded_status_and_apply_friction( @@ -566,7 +566,7 @@ impl KinematicCharacterController { &self.up, character_shape, max_height, - true, + false, filter, ) .is_some() @@ -583,7 +583,7 @@ impl KinematicCharacterController { &horizontal_dir, character_shape, min_width, - true, + false, filter, ) .is_some() @@ -602,7 +602,7 @@ impl KinematicCharacterController { &-self.up, character_shape, max_height, - true, + false, filter, ) { let [_vertical_slope_translation, horizontal_slope_translation] = @@ -629,7 +629,7 @@ impl KinematicCharacterController { &-self.up, character_shape, max_height, - true, + false, filter, ) .map(|hit| hit.1.toi) From 8fa9f9cb1aac596c0f37f62013cc41ed0e13f773 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:39:05 +0100 Subject: [PATCH 50/80] Tweak prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5783103..8db603b 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.1 + self.offset.eval(up_extends) * 1.4 } fn detect_grounded_status_and_apply_friction( From e094bf8f0d9bcad4e0385a578bf35c475ce4e653 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:41:39 +0100 Subject: [PATCH 51/80] Tweak prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 8db603b..a1ea64b 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.4 + self.offset.eval(up_extends) * 2. } fn detect_grounded_status_and_apply_friction( From e7cb9bea2fd7cf5eadaefcf9d476b25fb130bb57 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:44:09 +0100 Subject: [PATCH 52/80] Tweak prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index a1ea64b..ad192fb 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 2. + self.offset.eval(up_extends) * 3. } fn detect_grounded_status_and_apply_friction( From 337a963ce39a05f3a20b7e94ac834a2e40ea0885 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Fri, 27 Jan 2023 23:58:21 +0100 Subject: [PATCH 53/80] Fix code inconsistencies --- src/control/character_controller.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index ad192fb..defa48f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -356,7 +356,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 3. + self.offset.eval(up_extends) * 1.4 } fn detect_grounded_status_and_apply_friction( @@ -532,8 +532,10 @@ impl KinematicCharacterController { Some(autostep) => autostep, None => return false, }; - let min_width = autostep.min_width.eval(dims.x); - let max_height = autostep.max_height.eval(dims.y); + + let offset = self.offset.eval(dims.y); + let min_width = autostep.min_width.eval(dims.x) + offset; + let max_height = autostep.max_height.eval(dims.y) + offset; if !autostep.include_dynamic_bodies { if colliders @@ -592,7 +594,6 @@ impl KinematicCharacterController { return false; } - let offset = self.offset.eval(dims.y); // Check that we are not getting into a ramp that is too steep // after stepping. if let Some((_, hit)) = queries.cast_shape( @@ -605,13 +606,15 @@ impl KinematicCharacterController { false, filter, ) { - let [_vertical_slope_translation, horizontal_slope_translation] = + let [vertical_slope_translation, horizontal_slope_translation] = self.split_into_components(translation_remaining) .map(|remaining| subtract_hit(remaining, &hit, offset)); + let slope_translation = horizontal_slope_translation + vertical_slope_translation; + let angle_with_floor = self.up.angle(&hit.normal1); - let climbing = self.up.dot(&horizontal_slope_translation) >= 0.0; + let climbing = self.up.dot(&slope_translation) >= 0.0; if climbing && angle_with_floor > self.max_slope_climb_angle { return false; // The target ramp is too steep. @@ -636,16 +639,16 @@ impl KinematicCharacterController { .unwrap_or(max_height); // Remove the step height from the vertical part of the self. - *translation_remaining -= - *self.up * ((translation_remaining.dot(&self.up)).clamp(0.0, step_height)); + let step = *self.up * step_height; + *translation_remaining -= step; // Advance the collider on the step horizontally, to make sure further // movement won’t just get stuck on its edge. let horizontal_nudge = - horizontal_dir * min_width.min(horizontal_dir.dot(translation_remaining)); + horizontal_dir * horizontal_dir.dot(translation_remaining).min(min_width); *translation_remaining -= horizontal_nudge; - result.translation += *self.up * step_height + horizontal_nudge; + result.translation += step + horizontal_nudge; return true; } From 9daa741af2d2efa0358db5ce94a4879e7e437b84 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:03:50 +0100 Subject: [PATCH 54/80] Fix missing ground assignment --- src/control/character_controller.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index defa48f..2649193 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -410,6 +410,9 @@ impl KinematicCharacterController { for m in &manifolds { let normal = -(character_pos * m.local_n1); + if normal.dot(&self.up) >= -1e-5 { + grounded = true; + } if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; @@ -456,7 +459,7 @@ impl KinematicCharacterController { for m in &manifolds { let normal = character_pos * m.local_n1; - if normal.dot(&self.up) <= -1.0e-5 { + if normal.dot(&self.up) <= 1.0e-5 { for contact in &m.points { if contact.dist <= prediction { grounded = true; From d4ca84539376eab5ab918f76fac914d9900cfd61 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:14:40 +0100 Subject: [PATCH 55/80] Fix faulty max --- src/control/character_controller.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 2649193..1211d2b 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -410,10 +410,6 @@ impl KinematicCharacterController { for m in &manifolds { let normal = -(character_pos * m.local_n1); - if normal.dot(&self.up) >= -1e-5 { - grounded = true; - } - if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; let mut manifold_center = Point::origin(); @@ -431,7 +427,7 @@ impl KinematicCharacterController { manifold_center += contact_point.coords; *translation_remaining += normal - * (normal_target_mvt - normal_current_mvt).max(0.0); + * (normal_target_mvt - normal_current_mvt); } } From 1a94c62a1aa5de0eedaf796f7dd5d81ce3c0ad2b Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:18:51 +0100 Subject: [PATCH 56/80] Fix missing ground check --- src/control/character_controller.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 1211d2b..438eab1 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -428,6 +428,10 @@ impl KinematicCharacterController { manifold_center += contact_point.coords; *translation_remaining += normal * (normal_target_mvt - normal_current_mvt); + + if normal.dot(&self.up) <= 1.0e-5 { + grounded = true; + } } } From e3fb4f71350a448eb5fa08b7b134d219d082d2c3 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:30:20 +0100 Subject: [PATCH 57/80] Move main ground detection duty to snapping to ground --- src/control/character_controller.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 438eab1..40338bb 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -193,8 +193,8 @@ impl KinematicCharacterController { let mut translation_remaining = desired_translation; - // Check if we are grounded at the initial position. - let grounded_at_starting_pos = self.detect_grounded_status_and_apply_friction( + // Apply friction + self.detect_grounded_status_and_apply_friction( dt, bodies, colliders, @@ -299,18 +299,17 @@ impl KinematicCharacterController { } // If needed, and if we are not already grounded, snap to the ground. - if grounded_at_starting_pos { - self.snap_to_ground( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - &mut result, - ); - } + self.snap_to_ground( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + &mut result, + ); + // Return the result. result From f1c8fdc1ecaab17e9d018ef5957736f89e5a0991 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:52:16 +0100 Subject: [PATCH 58/80] Try to fix false negatives on grounded --- src/control/character_controller.rs | 45 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 40338bb..34b02d0 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -193,8 +193,8 @@ impl KinematicCharacterController { let mut translation_remaining = desired_translation; - // Apply friction - self.detect_grounded_status_and_apply_friction( + // Check if we are grounded at the initial position. + let grounded_at_starting_pos = self.detect_grounded_status_and_apply_friction( dt, bodies, colliders, @@ -299,17 +299,18 @@ impl KinematicCharacterController { } // If needed, and if we are not already grounded, snap to the ground. - self.snap_to_ground( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - &mut result, - ); - + if grounded_at_starting_pos { + self.snap_to_ground( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + &mut result, + ); + } // Return the result. result @@ -381,7 +382,7 @@ impl KinematicCharacterController { .compute_aabb(character_pos) .loosened(prediction); - let mut grounded = false; + let mut grounded = true; queries.colliders_with_aabb_intersecting_aabb(&character_aabb, |handle| { if let Some(collider) = colliders.get(*handle) { @@ -409,6 +410,9 @@ impl KinematicCharacterController { for m in &manifolds { let normal = -(character_pos * m.local_n1); + if normal.dot(&self.up) <= 1.0e-5 { + grounded = false; + } if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; let mut manifold_center = Point::origin(); @@ -428,9 +432,6 @@ impl KinematicCharacterController { *translation_remaining += normal * (normal_target_mvt - normal_current_mvt); - if normal.dot(&self.up) <= 1.0e-5 { - grounded = true; - } } } @@ -458,13 +459,9 @@ impl KinematicCharacterController { for m in &manifolds { let normal = character_pos * m.local_n1; - if normal.dot(&self.up) <= 1.0e-5 { - for contact in &m.points { - if contact.dist <= prediction { - grounded = true; - return false; // We can stop the search early. - } - } + if normal.dot(&self.up) >= -1.0e-5 { + grounded = false; + return false; // We can stop the search early. } } } From 456c62e2ff28c16656febe4f5d388a879d709b6a Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 00:56:01 +0100 Subject: [PATCH 59/80] Try out regular snapping again --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 34b02d0..a0771b6 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -299,7 +299,7 @@ impl KinematicCharacterController { } // If needed, and if we are not already grounded, snap to the ground. - if grounded_at_starting_pos { + //if grounded_at_starting_pos { self.snap_to_ground( bodies, colliders, @@ -310,7 +310,7 @@ impl KinematicCharacterController { filter, &mut result, ); - } + //} // Return the result. result From 3b537a20c27ed2c964737de72b00c422a74bcdff Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 01:08:22 +0100 Subject: [PATCH 60/80] Remove unused variables --- src/control/character_controller.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index a0771b6..72e3d77 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -193,8 +193,7 @@ impl KinematicCharacterController { let mut translation_remaining = desired_translation; - // Check if we are grounded at the initial position. - let grounded_at_starting_pos = self.detect_grounded_status_and_apply_friction( + self.detect_grounded_status_and_apply_friction( dt, bodies, colliders, @@ -298,19 +297,17 @@ impl KinematicCharacterController { } } - // If needed, and if we are not already grounded, snap to the ground. - //if grounded_at_starting_pos { - self.snap_to_ground( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - &mut result, - ); - //} + // If needed, snap to the ground. + self.snap_to_ground( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + &mut result, + ); // Return the result. result From 220d2b09ab3f4ba7d63be23a0f5b1c4176424411 Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 28 Jan 2023 01:09:19 +0100 Subject: [PATCH 61/80] Fiddle with prediction --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 72e3d77..f0c5b94 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -353,7 +353,7 @@ impl KinematicCharacterController { } fn predict_ground(&self, up_extends: Real) -> Real { - self.offset.eval(up_extends) * 1.4 + self.offset.eval(up_extends) * 1.1 } fn detect_grounded_status_and_apply_friction( From da671fd99a737efb754139120a112e5532ab85ed Mon Sep 17 00:00:00 2001 From: Jan Nils Ferner Date: Sat, 4 Feb 2023 18:12:15 +0100 Subject: [PATCH 62/80] Fix formatting --- examples2d/character_controller2.rs | 2 +- src/control/character_controller.rs | 48 ++++++++++++++--------------- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/examples2d/character_controller2.rs b/examples2d/character_controller2.rs index e964a02..8ecd23c 100644 --- a/examples2d/character_controller2.rs +++ b/examples2d/character_controller2.rs @@ -1,6 +1,6 @@ -use std::f32::consts::PI; use rapier2d::prelude::*; use rapier_testbed2d::Testbed; +use std::f32::consts::PI; pub fn init_world(testbed: &mut Testbed) { /* diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index f0c5b94..372dc66 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -232,8 +232,7 @@ impl KinematicCharacterController { filter, ) { // We hit something, compute the allowed self. - let allowed_dist = - toi.toi - (toi.normal1.dot(&translation_dir)).abs() * offset; + let allowed_dist = toi.toi - (toi.normal1.dot(&translation_dir)).abs() * offset; let allowed_translation = *translation_dir * allowed_dist; result.translation += allowed_translation; translation_remaining -= allowed_translation; @@ -271,7 +270,6 @@ impl KinematicCharacterController { translation_remaining -= allowed_translation; } } - } else { // No interference along the path. result.translation += translation_remaining; @@ -422,13 +420,11 @@ impl KinematicCharacterController { kinematic_parent.velocity_at_point(&contact_point); let normal_target_mvt = target_vel.dot(&normal) * dt; - let normal_current_mvt = - translation_remaining.dot(&normal); + let normal_current_mvt = translation_remaining.dot(&normal); manifold_center += contact_point.coords; - *translation_remaining += normal - * (normal_target_mvt - normal_current_mvt); - + *translation_remaining += + normal * (normal_target_mvt - normal_current_mvt); } } @@ -480,7 +476,7 @@ impl KinematicCharacterController { self.split_into_components(translation_remaining); let [vertical_slope_translation, horizontal_slope_translation] = [vertical_translation, horizontal_translation] - .map(|remaining| subtract_hit(remaining, hit, offset)); + .map(|remaining| subtract_hit(remaining, hit, offset)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. @@ -488,13 +484,16 @@ impl KinematicCharacterController { let climbing = self.up.dot(&slope_translation) >= 0.0; climbing - .then(||(angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? - .then_some(horizontal_translation )) - .unwrap_or_else(|| (angle_with_floor >= self.min_slope_slide_angle)// Are we allowed to slide? - .then_some(slope_translation ) - .unwrap_or(horizontal_translation) - .into()) - + .then(|| { + (angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? + .then_some(horizontal_translation) + }) + .unwrap_or_else(|| { + (angle_with_floor >= self.min_slope_slide_angle) // Are we allowed to slide? + .then_some(slope_translation) + .unwrap_or(horizontal_translation) + .into() + }) } fn split_into_components(&self, translation: &Vector) -> [Vector; 2] { @@ -503,7 +502,6 @@ impl KinematicCharacterController { [vertical_translation, horizontal_translation] } - fn compute_dims(&self, character_shape: &dyn Shape) -> Vector2 { let extents = character_shape.compute_local_aabb().extents(); let up_extent = extents.dot(&self.up); @@ -550,8 +548,10 @@ impl KinematicCharacterController { let shifted_character_pos = Translation::from(*self.up * max_height) * character_pos; - let horizontal_dir = match (*translation_remaining - *self.up * translation_remaining.dot(&self.up)) - .try_normalize(1.0e-5) { + let horizontal_dir = match (*translation_remaining + - *self.up * translation_remaining.dot(&self.up)) + .try_normalize(1.0e-5) + { Some(dir) => dir, None => return false, }; @@ -602,13 +602,12 @@ impl KinematicCharacterController { false, filter, ) { - let [vertical_slope_translation, horizontal_slope_translation] = - self.split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, offset)); + let [vertical_slope_translation, horizontal_slope_translation] = self + .split_into_components(translation_remaining) + .map(|remaining| subtract_hit(remaining, &hit, offset)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; - let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; @@ -623,8 +622,7 @@ impl KinematicCharacterController { .cast_shape( bodies, colliders, - &(Translation::from(horizontal_dir * min_width) - * shifted_character_pos), + &(Translation::from(horizontal_dir * min_width) * shifted_character_pos), &-self.up, character_shape, max_height, From 6c5713aa0c8317e2ac428a546ae1ff0e1445e1e1 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 19:14:05 +0100 Subject: [PATCH 63/80] Remove anti-jitter check --- src/control/character_controller.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 372dc66..24ccc6c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -338,9 +338,7 @@ impl KinematicCharacterController { ) { // Apply the snap. let snap_distance = hit.toi - offset; - if snap_distance.abs() > 1.0e-5 { - result.translation -= *self.up * snap_distance; - } + result.translation -= *self.up * snap_distance; result.grounded = true; return Some((hit_handle, hit)); } From b461d028df09f8715646ca476e30693121777f31 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 19:41:01 +0100 Subject: [PATCH 64/80] Remove overzealous ground-snapping --- src/control/character_controller.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 24ccc6c..5812d2e 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -193,7 +193,7 @@ impl KinematicCharacterController { let mut translation_remaining = desired_translation; - self.detect_grounded_status_and_apply_friction( + let grounded_at_starting_pos = self.detect_grounded_status_and_apply_friction( dt, bodies, colliders, @@ -294,18 +294,19 @@ impl KinematicCharacterController { break; } } - - // If needed, snap to the ground. - self.snap_to_ground( - bodies, - colliders, - queries, - character_shape, - &(Translation::from(result.translation) * character_pos), - &dims, - filter, - &mut result, - ); + // If needed, and if we are not already grounded, snap to the ground. + if grounded_at_starting_pos { + self.snap_to_ground( + bodies, + colliders, + queries, + character_shape, + &(Translation::from(result.translation) * character_pos), + &dims, + filter, + &mut result, + ); + } // Return the result. result From 7a2759c52feae6379da51fbf44584ea2c0b76c0c Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 19:55:05 +0100 Subject: [PATCH 65/80] Revert grounded checks to not be grounded by default again --- src/control/character_controller.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5812d2e..5467a4a 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -376,7 +376,7 @@ impl KinematicCharacterController { .compute_aabb(character_pos) .loosened(prediction); - let mut grounded = true; + let mut grounded = false; queries.colliders_with_aabb_intersecting_aabb(&character_aabb, |handle| { if let Some(collider) = colliders.get(*handle) { @@ -404,9 +404,10 @@ impl KinematicCharacterController { for m in &manifolds { let normal = -(character_pos * m.local_n1); - if normal.dot(&self.up) <= 1.0e-5 { - grounded = false; + if normal.dot(&self.up) >= -1.0e-5 { + grounded = true; } + if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; let mut manifold_center = Point::origin(); @@ -451,9 +452,13 @@ impl KinematicCharacterController { for m in &manifolds { let normal = character_pos * m.local_n1; - if normal.dot(&self.up) >= -1.0e-5 { - grounded = false; - return false; // We can stop the search early. + if normal.dot(&self.up) <= 1.0e-5 { + for contact in &m.points { + if contact.dist <= prediction { + grounded = true; + return false; // We can stop the search early. + } + } } } } From 52910c9c59f91bd2c37d0608e3cd7269edef1da2 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 20:11:04 +0100 Subject: [PATCH 66/80] Optimistically add normalization --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5467a4a..e72e5b3 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -403,7 +403,7 @@ impl KinematicCharacterController { .filter(|rb| rb.is_kinematic()); for m in &manifolds { - let normal = -(character_pos * m.local_n1); + let normal = -(character_pos * m.local_n1).normalize(); if normal.dot(&self.up) >= -1.0e-5 { grounded = true; } @@ -450,7 +450,7 @@ impl KinematicCharacterController { *kinematic_friction_translation - init_kinematic_friction_translation; } else { for m in &manifolds { - let normal = character_pos * m.local_n1; + let normal = (character_pos * m.local_n1).normalize(); if normal.dot(&self.up) <= 1.0e-5 { for contact in &m.points { From 9e89a71257a2d2fa78c2c97449280100f3a94725 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 20:15:34 +0100 Subject: [PATCH 67/80] Revert "Optimistically add normalization" This reverts commit 52910c9c59f91bd2c37d0608e3cd7269edef1da2. --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index e72e5b3..5467a4a 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -403,7 +403,7 @@ impl KinematicCharacterController { .filter(|rb| rb.is_kinematic()); for m in &manifolds { - let normal = -(character_pos * m.local_n1).normalize(); + let normal = -(character_pos * m.local_n1); if normal.dot(&self.up) >= -1.0e-5 { grounded = true; } @@ -450,7 +450,7 @@ impl KinematicCharacterController { *kinematic_friction_translation - init_kinematic_friction_translation; } else { for m in &manifolds { - let normal = (character_pos * m.local_n1).normalize(); + let normal = character_pos * m.local_n1; if normal.dot(&self.up) <= 1.0e-5 { for contact in &m.points { From 39998e96e8f887afdf79c02c7873d7c70bf1530c Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 20:27:27 +0100 Subject: [PATCH 68/80] Fix grounded false positives when normal is [0, 0] --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 5467a4a..49373d1 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -404,7 +404,7 @@ impl KinematicCharacterController { for m in &manifolds { let normal = -(character_pos * m.local_n1); - if normal.dot(&self.up) >= -1.0e-5 { + if normal.dot(&self.up) >= 1.0e-5 { grounded = true; } From f9a50856be6c4976c3a1379570bf46b01b421054 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 20:35:42 +0100 Subject: [PATCH 69/80] Add debug messages --- src/control/character_controller.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 49373d1..c258b7a 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -406,6 +406,14 @@ impl KinematicCharacterController { let normal = -(character_pos * m.local_n1); if normal.dot(&self.up) >= 1.0e-5 { grounded = true; + println!("grounded!"); + println!("normal: {:?}", normal); + println!("up: {:?}", self.up); + println!("dot: {:?}", normal.dot(&self.up)); + println!("character_pos: {:?}", character_pos); + println!("m.local_n1: {:?}", m.local_n1); + println!("m.local_n2: {:?}", m.local_n2); + println!(); } if let Some(kinematic_parent) = kinematic_parent { From 8d182cef7d30f1c81e447a475ab916137a567b4d Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 20:59:35 +0100 Subject: [PATCH 70/80] Fix inconsistency in grounded detection at manifold --- src/control/character_controller.rs | 43 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index c258b7a..abccfee 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -403,22 +403,14 @@ impl KinematicCharacterController { .filter(|rb| rb.is_kinematic()); for m in &manifolds { - let normal = -(character_pos * m.local_n1); - if normal.dot(&self.up) >= 1.0e-5 { + if self.is_grounded_at_contact_manifold(m, character_pos, dims) { grounded = true; - println!("grounded!"); - println!("normal: {:?}", normal); - println!("up: {:?}", self.up); - println!("dot: {:?}", normal.dot(&self.up)); - println!("character_pos: {:?}", character_pos); - println!("m.local_n1: {:?}", m.local_n1); - println!("m.local_n2: {:?}", m.local_n2); - println!(); } if let Some(kinematic_parent) = kinematic_parent { let mut num_active_contacts = 0; let mut manifold_center = Point::origin(); + let normal = -(character_pos * m.local_n1); for contact in &m.points { if contact.dist <= prediction { @@ -458,15 +450,9 @@ impl KinematicCharacterController { *kinematic_friction_translation - init_kinematic_friction_translation; } else { for m in &manifolds { - let normal = character_pos * m.local_n1; - - if normal.dot(&self.up) <= 1.0e-5 { - for contact in &m.points { - if contact.dist <= prediction { - grounded = true; - return false; // We can stop the search early. - } - } + if self.is_grounded_at_contact_manifold(m, character_pos, dims) { + grounded = true; + return false; // We can stop the search early. } } } @@ -478,6 +464,25 @@ impl KinematicCharacterController { grounded } + fn is_grounded_at_contact_manifold( + &self, + manifold: &ContactManifold, + character_pos: &Isometry, + dims: &Vector2, + ) -> bool { + let normal = -(character_pos * manifold.local_n1); + + if normal.dot(&self.up) >= 1.0e-5 { + let prediction = self.predict_ground(dims.y); + for contact in &manifold.points { + if contact.dist <= prediction { + return true; + } + } + } + false + } + fn handle_slopes( &self, hit: &TOI, From 760ea8d498c7dfc99d59342c8ec492de193ffed9 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 21:05:54 +0100 Subject: [PATCH 71/80] Fix moving along obstacle twice per iteration --- src/control/character_controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index abccfee..b6d2dcc 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -263,8 +263,8 @@ impl KinematicCharacterController { self.handle_slopes(&toi, &mut translation_remaining, offset) { translation_remaining = translation_on_slope; - } else { - // No slopes or stairs ahead; try to move along obstacle. + } else if allowed_dist < 1.0e5 { + // No slopes or stairs ahead, but we didn't move yet; try to move along obstacle. let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; translation_remaining -= allowed_translation; From 7e1fb6f8770ee41a2f5a66ee2c8b15e61ddac6a4 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 21:41:50 +0100 Subject: [PATCH 72/80] Fix snap to ground being triggered on exactly perpendicular movement --- src/control/character_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index b6d2dcc..7b60e82 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -324,7 +324,7 @@ impl KinematicCharacterController { result: &mut EffectiveCharacterMovement, ) -> Option<(ColliderHandle, TOI)> { if let Some(snap_distance) = self.snap_to_ground { - if result.translation.dot(&self.up) < 1.0e-5 { + if result.translation.dot(&self.up) < -1.0e-5 { let snap_distance = snap_distance.eval(dims.y); let offset = self.offset.eval(dims.y); if let Some((hit_handle, hit)) = queries.cast_shape( From c9462e0818aca202f63fa3c931e3a119aa252a55 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 22:31:27 +0100 Subject: [PATCH 73/80] Fix jittering on jointed platform, but result in violating offset --- src/control/character_controller.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 7b60e82..f009cf6 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -232,7 +232,8 @@ impl KinematicCharacterController { filter, ) { // We hit something, compute the allowed self. - let allowed_dist = toi.toi - (toi.normal1.dot(&translation_dir)).abs() * offset; + let allowed_dist = + (toi.toi - (-toi.normal1.dot(&translation_dir)) * offset).max(0.0); let allowed_translation = *translation_dir * allowed_dist; result.translation += allowed_translation; translation_remaining -= allowed_translation; @@ -263,7 +264,7 @@ impl KinematicCharacterController { self.handle_slopes(&toi, &mut translation_remaining, offset) { translation_remaining = translation_on_slope; - } else if allowed_dist < 1.0e5 { + } else if allowed_dist.abs() < 1.0e5 { // No slopes or stairs ahead, but we didn't move yet; try to move along obstacle. let allowed_translation = subtract_hit(translation_remaining, &toi, offset); result.translation += allowed_translation; From 95a7894b3c898ce4bb55754630630a65eb66c3dd Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 23:16:05 +0100 Subject: [PATCH 74/80] Remove dead code --- src/control/character_controller.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index f009cf6..e128e5f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -206,8 +206,6 @@ impl KinematicCharacterController { None, ); - // println!("Init grounded status: {grounded_at_starting_pos}"); - let mut max_iters = 20; let mut kinematic_friction_translation = Vector::zeros(); From 4ed3adda6ef243ccdba1752bb59f6ff40bd1881f Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sat, 4 Feb 2023 23:42:04 +0100 Subject: [PATCH 75/80] Make clippy happier --- src/control/character_controller.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index e128e5f..7ae0d5f 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -199,7 +199,7 @@ impl KinematicCharacterController { colliders, queries, character_shape, - &character_pos, + character_pos, &dims, filter, None, @@ -259,7 +259,7 @@ impl KinematicCharacterController { ) { // No stairs, try to move along slopes. if let Some(translation_on_slope) = - self.handle_slopes(&toi, &mut translation_remaining, offset) + self.handle_slopes(&toi, &translation_remaining, offset) { translation_remaining = translation_on_slope; } else if allowed_dist.abs() < 1.0e5 { @@ -499,17 +499,16 @@ impl KinematicCharacterController { let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; - climbing - .then(|| { - (angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? - .then_some(horizontal_translation) - }) - .unwrap_or_else(|| { - (angle_with_floor >= self.min_slope_slide_angle) // Are we allowed to slide? - .then_some(slope_translation) - .unwrap_or(horizontal_translation) - .into() - }) + if climbing { + // Are we allowed to climb? + (angle_with_floor <= self.max_slope_climb_angle).then_some(slope_translation) + } + // Are we forced to slide? + else if angle_with_floor >= self.min_slope_slide_angle { + slope_translation.into() + } else { + horizontal_translation.into() + } } fn split_into_components(&self, translation: &Vector) -> [Vector; 2] { @@ -659,7 +658,7 @@ impl KinematicCharacterController { *translation_remaining -= horizontal_nudge; result.translation += step + horizontal_nudge; - return true; + true } /// For a given collision between a character and its environment, this method will apply From fac561c902ec3d004d3f95df137beb3450231bc6 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sun, 5 Feb 2023 02:18:43 +0100 Subject: [PATCH 76/80] Fix erroneous sliding --- src/control/character_controller.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 7ae0d5f..f7f7e2c 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -499,16 +499,20 @@ impl KinematicCharacterController { let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; - if climbing { - // Are we allowed to climb? - (angle_with_floor <= self.max_slope_climb_angle).then_some(slope_translation) - } - // Are we forced to slide? - else if angle_with_floor >= self.min_slope_slide_angle { - slope_translation.into() - } else { - horizontal_translation.into() - } + climbing + .then(|| { + (angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? + .then_some(horizontal_translation) + }) + .unwrap_or_else(|| { + // Are we allowed to slide? + if angle_with_floor >= self.min_slope_slide_angle { + slope_translation + } else { + horizontal_translation + } + .into() + }) } fn split_into_components(&self, translation: &Vector) -> [Vector; 2] { From 93d0e625c758a8429f1a1e56ea3b6f8f4982a017 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Sun, 5 Feb 2023 02:52:50 +0100 Subject: [PATCH 77/80] Simplify code --- src/control/character_controller.rs | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index f7f7e2c..31f19c7 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -499,20 +499,16 @@ impl KinematicCharacterController { let angle_with_floor = self.up.angle(&hit.normal1); let climbing = self.up.dot(&slope_translation) >= 0.0; - climbing - .then(|| { - (angle_with_floor <= self.max_slope_climb_angle) // Are we allowed to climb? - .then_some(horizontal_translation) - }) - .unwrap_or_else(|| { - // Are we allowed to slide? - if angle_with_floor >= self.min_slope_slide_angle { - slope_translation - } else { - horizontal_translation - } - .into() - }) + if climbing { + // Are we allowed to climb? + (angle_with_floor <= self.max_slope_climb_angle).then_some(horizontal_translation) + } + // Are we allowed to slide? + else if angle_with_floor >= self.min_slope_slide_angle { + Some(slope_translation) + } else { + Some(horizontal_translation) + } } fn split_into_components(&self, translation: &Vector) -> [Vector; 2] { From 1b449fc31df6b9ecb8d339a5ff5fb2c1763a7978 Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Wed, 8 Feb 2023 22:17:04 +0100 Subject: [PATCH 78/80] Fix faulty snap distance --- src/control/character_controller.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 31f19c7..66d2d11 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -186,7 +186,6 @@ impl KinematicCharacterController { grounded: false, }; let dims = self.compute_dims(character_shape); - let offset = self.offset.eval(dims.y); // 1. Check and fix penetrations. self.check_and_fix_penetrations(); @@ -208,6 +207,7 @@ impl KinematicCharacterController { let mut max_iters = 20; let mut kinematic_friction_translation = Vector::zeros(); + let offset = self.offset.eval(dims.y); while let Some((translation_dir, translation_dist)) = UnitVector::try_new_and_get(translation_remaining, 1.0e-5) @@ -337,8 +337,7 @@ impl KinematicCharacterController { filter, ) { // Apply the snap. - let snap_distance = hit.toi - offset; - result.translation -= *self.up * snap_distance; + result.translation -= *self.up * (hit.toi - offset).max(0.0); result.grounded = true; return Some((hit_handle, hit)); } From dd195a47203ec4d9540f1a656ac53859372d353f Mon Sep 17 00:00:00 2001 From: Jan Hohenheim Date: Thu, 9 Feb 2023 00:56:16 +0100 Subject: [PATCH 79/80] Fix horizontal jittering along walls in 3D --- src/control/character_controller.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 66d2d11..0de897b 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -259,12 +259,12 @@ impl KinematicCharacterController { ) { // No stairs, try to move along slopes. if let Some(translation_on_slope) = - self.handle_slopes(&toi, &translation_remaining, offset) + self.handle_slopes(&toi, &translation_remaining) { translation_remaining = translation_on_slope; } else if allowed_dist.abs() < 1.0e5 { // No slopes or stairs ahead, but we didn't move yet; try to move along obstacle. - let allowed_translation = subtract_hit(translation_remaining, &toi, offset); + let allowed_translation = subtract_hit(translation_remaining, &toi); result.translation += allowed_translation; translation_remaining -= allowed_translation; } @@ -485,13 +485,12 @@ impl KinematicCharacterController { &self, hit: &TOI, translation_remaining: &Vector, - offset: Real, ) -> Option> { let [vertical_translation, horizontal_translation] = self.split_into_components(translation_remaining); let [vertical_slope_translation, horizontal_slope_translation] = [vertical_translation, horizontal_translation] - .map(|remaining| subtract_hit(remaining, hit, offset)); + .map(|remaining| subtract_hit(remaining, hit)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; // Check if there is a slope to climb. @@ -618,7 +617,7 @@ impl KinematicCharacterController { ) { let [vertical_slope_translation, horizontal_slope_translation] = self .split_into_components(translation_remaining) - .map(|remaining| subtract_hit(remaining, &hit, offset)); + .map(|remaining| subtract_hit(remaining, &hit)); let slope_translation = horizontal_slope_translation + vertical_slope_translation; @@ -745,8 +744,9 @@ impl KinematicCharacterController { } } -fn subtract_hit(translation: Vector, hit: &TOI, offset: Real) -> Vector { - let surface_correction = translation.dot(&hit.normal1).abs(); - let surface_correction = surface_correction + offset; +fn subtract_hit(translation: Vector, hit: &TOI) -> Vector { + let surface_correction = (-translation).dot(&hit.normal1).max(0.0); + // This fixes some instances of moving through walls + let surface_correction = surface_correction * (1.0 + 1.0e-5); translation + *hit.normal1 * surface_correction } From 798d764fc10642c91b12e4f18d0e354c23ae5463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Sun, 26 Feb 2023 17:49:16 +0100 Subject: [PATCH 80/80] Fix climbing small slopes when autostepping is disabled --- src/control/character_controller.rs | 46 +++++++++++------------------ 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/control/character_controller.rs b/src/control/character_controller.rs index 0de897b..c919064 100644 --- a/src/control/character_controller.rs +++ b/src/control/character_controller.rs @@ -258,16 +258,7 @@ impl KinematicCharacterController { &mut result, ) { // No stairs, try to move along slopes. - if let Some(translation_on_slope) = - self.handle_slopes(&toi, &translation_remaining) - { - translation_remaining = translation_on_slope; - } else if allowed_dist.abs() < 1.0e5 { - // No slopes or stairs ahead, but we didn't move yet; try to move along obstacle. - let allowed_translation = subtract_hit(translation_remaining, &toi); - result.translation += allowed_translation; - translation_remaining -= allowed_translation; - } + translation_remaining = self.handle_slopes(&toi, &translation_remaining); } } else { // No interference along the path. @@ -481,31 +472,30 @@ impl KinematicCharacterController { false } - fn handle_slopes( - &self, - hit: &TOI, - translation_remaining: &Vector, - ) -> Option> { + fn handle_slopes(&self, hit: &TOI, translation_remaining: &Vector) -> Vector { let [vertical_translation, horizontal_translation] = self.split_into_components(translation_remaining); - let [vertical_slope_translation, horizontal_slope_translation] = - [vertical_translation, horizontal_translation] - .map(|remaining| subtract_hit(remaining, hit)); - let slope_translation = horizontal_slope_translation + vertical_slope_translation; + let slope_translation = subtract_hit(*translation_remaining, hit); // Check if there is a slope to climb. let angle_with_floor = self.up.angle(&hit.normal1); - let climbing = self.up.dot(&slope_translation) >= 0.0; + // We are climbing if the movement along the slope goes upward, and the angle with the + // floor is smaller than pi/2 (in which case we hit some some sort of ceiling). + // + // NOTE: part of the slope will already be handled by auto-stepping if it was enabled. + // Therefore, `climbing` may not always be `true` when climbing on a slope at + // slow speed. + let climbing = self.up.dot(&slope_translation) >= 0.0 && self.up.dot(&hit.normal1) > 0.0; - if climbing { - // Are we allowed to climb? - (angle_with_floor <= self.max_slope_climb_angle).then_some(horizontal_translation) - } - // Are we allowed to slide? - else if angle_with_floor >= self.min_slope_slide_angle { - Some(slope_translation) + if climbing && angle_with_floor >= self.max_slope_climb_angle { + // Prevent horizontal movement from pushing through the slope. + vertical_translation + } else if !climbing && angle_with_floor <= self.min_slope_slide_angle { + // Prevent the vertical movement from sliding down. + horizontal_translation } else { - Some(horizontal_translation) + // Let it slide + slope_translation } }