Merge pull request #33864 from madmiraal/partial-revert-20908

Ensure move_and_slide() is consistent between the 2D and 3D versions.
This commit is contained in:
Rémi Verschelde 2019-12-02 09:50:58 +01:00 committed by GitHub
commit 9607fc48a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 39 deletions

View file

@ -1214,18 +1214,20 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_
Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector2 floor_motion = floor_velocity; Vector2 body_velocity = p_linear_velocity;
Vector2 body_velocity_normal = body_velocity.normalized();
Vector2 current_floor_velocity = floor_velocity;
if (on_floor && on_floor_body.is_valid()) { if (on_floor && on_floor_body.is_valid()) {
//this approach makes sure there is less delay between the actual body velocity and the one we saved //this approach makes sure there is less delay between the actual body velocity and the one we saved
Physics2DDirectBodyState *bs = Physics2DServer::get_singleton()->body_get_direct_state(on_floor_body); Physics2DDirectBodyState *bs = Physics2DServer::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) { if (bs) {
floor_motion = bs->get_linear_velocity(); current_floor_velocity = bs->get_linear_velocity();
} }
} }
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
Vector2 motion = (floor_motion + p_linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); Vector2 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
Vector2 lv = p_linear_velocity;
on_floor = false; on_floor = false;
on_floor_body = RID(); on_floor_body = RID();
@ -1234,14 +1236,12 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
colliders.clear(); colliders.clear();
floor_velocity = Vector2(); floor_velocity = Vector2();
Vector2 lv_n = p_linear_velocity.normalized();
while (p_max_slides) { while (p_max_slides) {
Collision collision; Collision collision;
bool found_collision = false; bool found_collision = false;
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; ++i) {
bool collided; bool collided;
if (i == 0) { //collide if (i == 0) { //collide
collided = move_and_collide(motion, p_infinite_inertia, collision); collided = move_and_collide(motion, p_infinite_inertia, collision);
@ -1273,14 +1273,13 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
floor_velocity = collision.collider_vel; floor_velocity = collision.collider_vel;
if (p_stop_on_slope) { if (p_stop_on_slope) {
if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { if ((body_velocity_normal + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) {
Transform2D gt = get_global_transform(); Transform2D gt = get_global_transform();
gt.elements[2] -= collision.travel.project(p_floor_direction.tangent()); gt.elements[2] -= collision.travel.slide(p_floor_direction);
set_global_transform(gt); set_global_transform(gt);
return Vector2(); return Vector2();
} }
} }
} else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true; on_ceiling = true;
} else { } else {
@ -1288,21 +1287,18 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
} }
} }
Vector2 n = collision.normal; motion = motion.slide(collision.normal);
motion = motion.slide(n); body_velocity = body_velocity.slide(collision.normal);
lv = lv.slide(n);
} }
} }
if (!found_collision) { if (!found_collision || motion == Vector2())
break;
}
p_max_slides--;
if (motion == Vector2())
break; break;
--p_max_slides;
} }
return lv; return body_velocity;
} }
Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {

View file

@ -1142,25 +1142,34 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in
Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {
Vector3 lv = p_linear_velocity; Vector3 body_velocity = p_linear_velocity;
Vector3 body_velocity_normal = body_velocity.normalized();
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) { if (locked_axis & (1 << i)) {
lv[i] = 0; body_velocity[i] = 0;
}
}
Vector3 current_floor_velocity = floor_velocity;
if (on_floor && on_floor_body.is_valid()) {
//this approach makes sure there is less delay between the actual body velocity and the one we saved
PhysicsDirectBodyState *bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
current_floor_velocity = bs->get_linear_velocity();
} }
} }
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
Vector3 motion = (floor_velocity + lv) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); Vector3 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
on_floor = false; on_floor = false;
on_floor_body = RID();
on_ceiling = false; on_ceiling = false;
on_wall = false; on_wall = false;
colliders.clear(); colliders.clear();
floor_velocity = Vector3(); floor_velocity = Vector3();
Vector3 lv_n = p_linear_velocity.normalized();
while (p_max_slides) { while (p_max_slides) {
Collision collision; Collision collision;
@ -1187,7 +1196,6 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
colliders.push_back(collision); colliders.push_back(collision);
motion = collision.remainder; motion = collision.remainder;
bool is_on_slope = false;
if (p_floor_direction == Vector3()) { if (p_floor_direction == Vector3()) {
//all is a wall //all is a wall
on_wall = true; on_wall = true;
@ -1199,16 +1207,13 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
floor_velocity = collision.collider_vel; floor_velocity = collision.collider_vel;
if (p_stop_on_slope) { if (p_stop_on_slope) {
if ((lv_n + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) { if ((body_velocity_normal + p_floor_direction).length() < 0.01 && collision.travel.length() < 1) {
Transform gt = get_global_transform(); Transform gt = get_global_transform();
gt.origin -= collision.travel.slide(p_floor_direction); gt.origin -= collision.travel.slide(p_floor_direction);
set_global_transform(gt); set_global_transform(gt);
return Vector3(); return Vector3();
} }
} }
is_on_slope = true;
} else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling } else if (Math::acos(collision.normal.dot(-p_floor_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true; on_ceiling = true;
} else { } else {
@ -1216,18 +1221,12 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
} }
} }
if (p_stop_on_slope && is_on_slope) { motion = motion.slide(collision.normal);
motion = motion.slide(p_floor_direction); body_velocity = body_velocity.slide(collision.normal);
lv = lv.slide(p_floor_direction);
} else {
Vector3 n = collision.normal;
motion = motion.slide(n);
lv = lv.slide(n);
}
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
if (locked_axis & (1 << j)) { if (locked_axis & (1 << j)) {
lv[j] = 0; body_velocity[j] = 0;
} }
} }
} }
@ -1239,7 +1238,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
--p_max_slides; --p_max_slides;
} }
return lv; return body_velocity;
} }
Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) {