Port recent move_and_slide fixes to 3D

Improves stop on slopes, sliding on walls and gravity handling by
porting existing changes from CharacterBody2D to CharacterBody3D.

Co-authored-by: fabriceci <fabricecipolla@gmail.com>
This commit is contained in:
PouleyKetchoupp 2021-08-19 17:20:34 -07:00
parent 770a1d00a3
commit bae06008c8
1 changed files with 29 additions and 30 deletions

View File

@ -1080,8 +1080,6 @@ void RigidBody3D::_reload_physics_characteristics() {
#define FLOOR_ANGLE_THRESHOLD 0.01
bool CharacterBody3D::move_and_slide() {
Vector3 body_velocity_normal = linear_velocity.normalized();
bool was_on_floor = on_floor;
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
@ -1111,7 +1109,7 @@ bool CharacterBody3D::move_and_slide() {
floor_normal = Vector3();
floor_velocity = Vector3();
if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) {
if (!current_floor_velocity.is_equal_approx(Vector3()) && on_floor_body.is_valid()) {
PhysicsServer3D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(on_floor_body);
@ -1130,39 +1128,35 @@ bool CharacterBody3D::move_and_slide() {
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result;
bool found_collision = false;
bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
if (!collided) {
motion = Vector3(); //clear because no collision happened and motion completed
} else {
found_collision = true;
if (collided) {
motion_results.push_back(result);
_set_collision_direction(result);
if (on_floor && floor_stop_on_slope) {
if ((body_velocity_normal + up_direction).length() < 0.01) {
Transform3D gt = get_global_transform();
if (result.travel.length() > margin) {
gt.origin -= result.travel.slide(up_direction);
} else {
gt.origin -= result.travel;
}
set_global_transform(gt);
linear_velocity = Vector3();
return true;
if (on_floor && floor_stop_on_slope && (linear_velocity.normalized() + up_direction).length() < 0.01) {
Transform3D gt = get_global_transform();
if (result.travel.length() > margin) {
gt.origin -= result.travel.slide(up_direction);
} else {
gt.origin -= result.travel;
}
set_global_transform(gt);
linear_velocity = Vector3();
motion = Vector3();
break;
}
if (result.remainder.is_equal_approx(Vector3())) {
motion = Vector3();
break;
}
if (sliding_enabled || !on_floor) {
motion = result.remainder.slide(result.collision_normal);
linear_velocity = linear_velocity.slide(result.collision_normal);
for (int j = 0; j < 3; j++) {
if (locked_axis & (1 << j)) {
linear_velocity[j] = 0.0;
}
Vector3 slide_motion = result.remainder.slide(result.collision_normal);
if (slide_motion.dot(linear_velocity) > 0.0) {
motion = slide_motion;
} else {
motion = Vector3();
}
} else {
motion = result.remainder;
@ -1171,12 +1165,12 @@ bool CharacterBody3D::move_and_slide() {
sliding_enabled = true;
if (!found_collision || motion == Vector3()) {
if (!collided || motion.is_equal_approx(Vector3())) {
break;
}
}
if (was_on_floor && snap != Vector3()) {
if (was_on_floor && !on_floor && !snap.is_equal_approx(Vector3())) {
// Apply snap.
Transform3D gt = get_global_transform();
PhysicsServer3D::MotionResult result;
@ -1213,6 +1207,11 @@ bool CharacterBody3D::move_and_slide() {
linear_velocity += current_floor_velocity;
}
// Reset the gravity accumulation when touching the ground.
if (on_floor && linear_velocity.dot(up_direction) <= 0) {
linear_velocity = linear_velocity.slide(up_direction);
}
return motion_results.size() > 0;
}