diff --git a/doc/classes/KinematicBody.xml b/doc/classes/KinematicBody.xml
index a5ec96a153a..7390d26a28f 100644
--- a/doc/classes/KinematicBody.xml
+++ b/doc/classes/KinematicBody.xml
@@ -86,7 +86,7 @@
- Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision], which contains information about the collision.
+ Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision], which contains information about the collision when stopped, or when touching another body along the motion.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
@@ -139,7 +139,8 @@
- Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
+ Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+ Use [method move_and_collide] instead for detecting collision with touching bodies.
diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index 774df9f99a7..8aaa743653f 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -84,7 +84,7 @@
- Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision.
+ Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision when stopped, or when touching another body along the motion.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
@@ -129,7 +129,8 @@
- Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
+ Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+ Use [method move_and_collide] instead for detecting collision with touching bodies.
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 59eb41c4eca..4190d60b66d 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -345,10 +345,21 @@ struct _RigidBody2DInOut {
bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref &p_result) {
Physics2DServer::MotionResult *r = nullptr;
+ Physics2DServer::MotionResult temp_result;
if (p_result.is_valid()) {
r = p_result->get_result_ptr();
+ } else {
+ r = &temp_result;
+ }
+
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r);
+
+ if (colliding) {
+ // Don't report collision when the whole motion is done.
+ return (r->collision_safe_fraction < 1.0);
+ } else {
+ return false;
}
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r);
}
void RigidBody2D::_direct_state_changed(Object *p_state) {
@@ -1299,7 +1310,15 @@ Vector2 KinematicBody2D::get_floor_velocity() const {
bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin);
+ Physics2DServer::MotionResult result;
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin, &result);
+
+ if (colliding) {
+ // Don't report collision when the whole motion is done.
+ return (result.collision_safe_fraction < 1.0);
+ } else {
+ return false;
+ }
}
void KinematicBody2D::set_safe_margin(float p_margin) {
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 18a0cff3511..1aa8bcbd5a3 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -1259,7 +1259,15 @@ Vector3 KinematicBody::get_floor_velocity() const {
bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
+ PhysicsServer::MotionResult result;
+ bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, &result);
+
+ if (colliding) {
+ // Don't report collision when the whole motion is done.
+ return (result.collision_safe_fraction < 1.0);
+ } else {
+ return false;
+ }
}
bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {