Browse Source

Merge pull request #53174 from fabriceci/apply-delta-move-and-collide

Physic API change: apply the delta in move and collide like move and slide
Camille Mohr-Daurat 3 years ago
parent
commit
c38ef94951

+ 6 - 4
doc/classes/PhysicsBody2D.xml

@@ -25,11 +25,12 @@
 		</method>
 		<method name="move_and_collide">
 			<return type="KinematicCollision2D" />
-			<argument index="0" name="rel_vec" type="Vector2" />
+			<argument index="0" name="linear_velocity" type="Vector2" />
 			<argument index="1" name="test_only" type="bool" default="false" />
 			<argument index="2" name="safe_margin" type="float" default="0.08" />
 			<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]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.
 				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>
@@ -44,11 +45,12 @@
 		<method name="test_move">
 			<return type="bool" />
 			<argument index="0" name="from" type="Transform2D" />
-			<argument index="1" name="rel_vec" type="Vector2" />
+			<argument index="1" name="linear_velocity" type="Vector2" />
 			<argument index="2" name="collision" type="KinematicCollision2D" default="null" />
 			<argument index="3" name="safe_margin" type="float" default="0.08" />
 			<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. 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).
 				[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details).
 			</description>

+ 6 - 4
doc/classes/PhysicsBody3D.xml

@@ -32,12 +32,13 @@
 		</method>
 		<method name="move_and_collide">
 			<return type="KinematicCollision3D" />
-			<argument index="0" name="rel_vec" type="Vector3" />
+			<argument index="0" name="linear_velocity" type="Vector3" />
 			<argument index="1" name="test_only" type="bool" default="false" />
 			<argument index="2" name="safe_margin" type="float" default="0.001" />
 			<argument index="3" name="max_collisions" type="int" default="1" />
 			<description>
-				Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
+				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.
 				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.
@@ -61,12 +62,13 @@
 		<method name="test_move">
 			<return type="bool" />
 			<argument index="0" name="from" type="Transform3D" />
-			<argument index="1" name="rel_vec" type="Vector3" />
+			<argument index="1" name="linear_velocity" type="Vector3" />
 			<argument index="2" name="collision" type="KinematicCollision3D" default="null" />
 			<argument index="3" name="safe_margin" type="float" default="0.001" />
 			<argument index="4" name="max_collisions" type="int" default="1" />
 			<description>
-				Checks for collisions without moving the body. 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]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
+				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).
 				[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.

+ 10 - 4
scene/2d/physics_body_2d.cpp

@@ -34,8 +34,8 @@
 #include "scene/scene_string_names.h"
 
 void PhysicsBody2D::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
-	ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
+	ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(false), DEFVAL(0.08));
+	ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(Variant()), DEFVAL(0.08));
 
 	ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions);
 	ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with);
@@ -57,7 +57,10 @@ PhysicsBody2D::~PhysicsBody2D() {
 Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) {
 	PhysicsServer2D::MotionResult result;
 
-	if (move_and_collide(p_motion, result, p_margin, p_test_only)) {
+	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky.
+	double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+	if (move_and_collide(p_motion * delta, result, p_margin, p_test_only)) {
 		// Create a new instance when the cached reference is invalid or still in use in script.
 		if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
 			motion_cache.instantiate();
@@ -133,7 +136,10 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
 		r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result);
 	}
 
-	return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r);
+	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky.
+	double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+	return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r);
 }
 
 TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {

+ 10 - 4
scene/3d/physics_body_3d.cpp

@@ -38,8 +38,8 @@
 #endif
 
 void PhysicsBody3D::_bind_methods() {
-	ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1));
-	ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1));
+	ClassDB::bind_method(D_METHOD("move_and_collide", "linear_velocity", "test_only", "safe_margin", "max_collisions"), &PhysicsBody3D::_move, DEFVAL(false), DEFVAL(0.001), DEFVAL(1));
+	ClassDB::bind_method(D_METHOD("test_move", "from", "linear_velocity", "collision", "safe_margin", "max_collisions"), &PhysicsBody3D::test_move, DEFVAL(Variant()), DEFVAL(0.001), DEFVAL(1));
 
 	ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock);
 	ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock);
@@ -97,7 +97,10 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
 
 Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, int p_max_collisions) {
 	PhysicsServer3D::MotionResult result;
-	if (move_and_collide(p_motion, result, p_margin, p_test_only, p_max_collisions)) {
+	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+	double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+	if (move_and_collide(p_motion * delta, result, p_margin, p_test_only, p_max_collisions)) {
 		// Create a new instance when the cached reference is invalid or still in use in script.
 		if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
 			motion_cache.instantiate();
@@ -177,7 +180,10 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion
 		r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result);
 	}
 
-	return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_margin, r, p_max_collisions);
+	// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
+	double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
+
+	return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion * delta, p_margin, r, p_max_collisions);
 }
 
 void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {