Browse Source

Merge pull request #54847 from nekomatata/fix-test-move-regression

Rémi Verschelde 3 years ago
parent
commit
3668312e78

+ 3 - 3
doc/classes/PhysicsBody2D.xml

@@ -30,7 +30,7 @@
 			<argument index="2" name="safe_margin" type="float" default="0.08" />
 			<description>
 				Moves the body along the vector [code]linear_velocity[/code]. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
-				The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision.
+				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.
 				[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
 			</description>
@@ -50,8 +50,8 @@
 			<argument index="3" name="safe_margin" type="float" default="0.08" />
 			<description>
 				Checks for collisions without moving the body. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
-				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]linear_velocity[/code]. Returns [code]true[/code] if a collision would occur.
-				[code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one).
+				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]linear_velocity[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+				[code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision when stopped, or when touching another body along the motion.
 				[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
 			</description>
 		</method>

+ 3 - 3
doc/classes/PhysicsBody3D.xml

@@ -38,7 +38,7 @@
 			<argument index="3" name="max_collisions" type="int" default="1" />
 			<description>
 				Moves the body along the vector [code]linear_velocity[/code]. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
-				The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
+				The body will stop if it collides. Returns a [KinematicCollision3D], 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.
 				[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
 				[code]max_collisions[/code] allows to retrieve more than one collision result.
@@ -68,8 +68,8 @@
 			<argument index="4" name="max_collisions" type="int" default="1" />
 			<description>
 				Checks for collisions without moving the body. This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
-				Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]linear_velocity[/code]. Returns [code]true[/code] if a collision would occur.
-				[code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one).
+				Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]linear_velocity[/code]. Returns [code]true[/code] if a collision would stop the body from moving along the whole path.
+				[code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision when stopped, or when touching another body along the motion.
 				[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
 				[code]max_collisions[/code] allows to retrieve more than one collision result.
 			</description>

+ 11 - 1
scene/2d/physics_body_2d.cpp

@@ -133,9 +133,12 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 
 	PhysicsServer2D::MotionResult *r = nullptr;
+	PhysicsServer2D::MotionResult temp_result;
 	if (r_collision.is_valid()) {
 		// Needs const_cast because method bindings don't support non-const Ref.
 		r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
+	} else {
+		r = &temp_result;
 	}
 
 	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky.
@@ -143,7 +146,14 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear
 
 	PhysicsServer2D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin);
 
-	return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
+	bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
+
+	if (colliding) {
+		// Don't report collision when the whole motion is done.
+		return (r->collision_safe_fraction < 1.0);
+	} else {
+		return false;
+	}
 }
 
 TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {

+ 11 - 1
scene/3d/physics_body_3d.cpp

@@ -174,9 +174,12 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 
 	PhysicsServer3D::MotionResult *r = nullptr;
+	PhysicsServer3D::MotionResult temp_result;
 	if (r_collision.is_valid()) {
 		// Needs const_cast because method bindings don't support non-const Ref.
 		r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
+	} else {
+		r = &temp_result;
 	}
 
 	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
@@ -184,7 +187,14 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear
 
 	PhysicsServer3D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin);
 
-	return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
+	bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
+
+	if (colliding) {
+		// Don't report collision when the whole motion is done.
+		return (r->collision_safe_fraction < 1.0);
+	} else {
+		return false;
+	}
 }
 
 void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {