Fix floating when hitting the ceiling and slope slowdown
This commit is contained in:
parent
5e35fff70c
commit
0c87c2fe19
@ -1,6 +1,10 @@
|
|||||||
use std::{collections::HashSet, f32::consts::PI, ops::Neg};
|
use std::{collections::HashSet, f32::consts::PI, ops::Neg};
|
||||||
|
|
||||||
use godot::{classes::ICharacterBody3D, obj::WithBaseField, prelude::*};
|
use godot::{
|
||||||
|
classes::{ICharacterBody3D, KinematicCollision3D},
|
||||||
|
obj::WithBaseField,
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -70,25 +74,56 @@ pub trait PlayerCommon {
|
|||||||
|
|
||||||
impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
|
||||||
fn player_update(&mut self, delta: f64) {
|
fn player_update(&mut self, delta: f64) {
|
||||||
|
// Gravity
|
||||||
self.set_y_speed(self.get_y_speed() - 9.8 * delta as f32);
|
self.set_y_speed(self.get_y_speed() - 9.8 * delta as f32);
|
||||||
if self.base().is_on_floor() && self.get_y_speed() < 0. {
|
if self.base().is_on_floor() && self.get_y_speed() < 0. {
|
||||||
self.set_y_speed(0.);
|
self.set_y_speed(0.);
|
||||||
}
|
}
|
||||||
|
let vertical_velocity = Vector3::UP * self.get_y_speed();
|
||||||
|
|
||||||
let speed = Vector3::UP * self.get_y_speed()
|
// Figure out the ground plane normal (to move on the right plane)
|
||||||
+ self
|
let mut up_vector = Vector3::UP;
|
||||||
.get_movement_dir()
|
let mut most_upward_coll: Option<Gd<KinematicCollision3D>> = None;
|
||||||
.try_normalized()
|
for coll in (0..self.base().get_slide_collision_count())
|
||||||
.unwrap_or_default()
|
.flat_map(|i| self.base().get_slide_collision(i))
|
||||||
.rotated(Vector3::UP, self.base().get_rotation().y)
|
{
|
||||||
* self.get_move_speed();
|
let coll_norm_y = coll.get_normal().y;
|
||||||
|
if let Some(prev_most_upward) = &most_upward_coll {
|
||||||
|
if coll_norm_y > prev_most_upward.get_normal().y {
|
||||||
|
most_upward_coll = Some(coll);
|
||||||
|
}
|
||||||
|
} else if coll_norm_y > 0.5 {
|
||||||
|
// sin(30 deg) == 0.5, so this only accepts 30 deg or shallower slopes
|
||||||
|
most_upward_coll = Some(coll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(coll) = most_upward_coll {
|
||||||
|
up_vector = coll.get_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ground movement (along the plane the player is currently on)
|
||||||
|
let input_move_on_xz = self.get_movement_dir().try_normalized().unwrap_or_default();
|
||||||
|
let ground_plane_basis = Basis::from_axis_angle(up_vector, self.base().get_rotation().y);
|
||||||
|
let input_move_on_ground_plane = ground_plane_basis * input_move_on_xz;
|
||||||
|
|
||||||
|
let move_speed = self.get_move_speed();
|
||||||
|
let ground_plane_velocity = input_move_on_ground_plane * move_speed;
|
||||||
|
|
||||||
|
// Commit
|
||||||
if self.is_dead() {
|
if self.is_dead() {
|
||||||
self.base_mut().set_velocity(Vector3::ZERO);
|
self.base_mut().set_velocity(Vector3::ZERO);
|
||||||
} else {
|
} else {
|
||||||
self.base_mut().set_velocity(speed);
|
self.base_mut()
|
||||||
|
.set_velocity(vertical_velocity + ground_plane_velocity);
|
||||||
self.base_mut().move_and_slide();
|
self.base_mut().move_and_slide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if hitting a ceiling; if so, stop upwards velocity (done here instead of
|
||||||
|
// at the start of the next frame to get the right-after-move_and_slide state
|
||||||
|
// rather than the simulated one).
|
||||||
|
if self.base().get_velocity().y < 0.001 && self.get_y_speed() > 0.001 {
|
||||||
|
self.set_y_speed(0.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_jump(&mut self) -> bool {
|
fn try_jump(&mut self) -> bool {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user