Przeglądaj źródła

Merge pull request #54845 from nekomatata/fix-test-move-regression-3.x

Rémi Verschelde 3 lat temu
rodzic
commit
60c178c74d

+ 3 - 2
doc/classes/KinematicBody.xml

@@ -86,7 +86,7 @@
 			<argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
 			<argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
 			<argument index="3" name="test_only" type="bool" default="false" />
 			<argument index="3" name="test_only" type="bool" default="false" />
 			<description>
 			<description>
-				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.
 				If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
 			</description>
 			</description>
 		</method>
 		</method>
@@ -139,7 +139,8 @@
 			<argument index="1" name="rel_vec" type="Vector3" />
 			<argument index="1" name="rel_vec" type="Vector3" />
 			<argument index="2" name="infinite_inertia" type="bool" default="true" />
 			<argument index="2" name="infinite_inertia" type="bool" default="true" />
 			<description>
 			<description>
-				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.
 			</description>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</methods>

+ 3 - 2
doc/classes/KinematicBody2D.xml

@@ -84,7 +84,7 @@
 			<argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
 			<argument index="2" name="exclude_raycast_shapes" type="bool" default="true" />
 			<argument index="3" name="test_only" type="bool" default="false" />
 			<argument index="3" name="test_only" type="bool" default="false" />
 			<description>
 			<description>
-				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.
 				If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
 			</description>
 			</description>
 		</method>
 		</method>
@@ -129,7 +129,8 @@
 			<argument index="1" name="rel_vec" type="Vector2" />
 			<argument index="1" name="rel_vec" type="Vector2" />
 			<argument index="2" name="infinite_inertia" type="bool" default="true" />
 			<argument index="2" name="infinite_inertia" type="bool" default="true" />
 			<description>
 			<description>
-				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.
 			</description>
 			</description>
 		</method>
 		</method>
 	</methods>
 	</methods>

+ 21 - 2
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<Physics2DTestMotionResult> &p_result) {
 bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) {
 	Physics2DServer::MotionResult *r = nullptr;
 	Physics2DServer::MotionResult *r = nullptr;
+	Physics2DServer::MotionResult temp_result;
 	if (p_result.is_valid()) {
 	if (p_result.is_valid()) {
 		r = p_result->get_result_ptr();
 		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) {
 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) {
 bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) {
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 	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) {
 void KinematicBody2D::set_safe_margin(float p_margin) {

+ 9 - 1
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) {
 bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
 	ERR_FAIL_COND_V(!is_inside_tree(), false);
 	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) {
 bool KinematicBody::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) {