Merge pull request #53280 from nekomatata/test-body-motion-parameters

This commit is contained in:
Rémi Verschelde 2021-10-04 21:05:38 +02:00 committed by GitHub
commit 5b270278c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 679 additions and 489 deletions

View File

@ -14,43 +14,74 @@
<return type="float" /> <return type="float" />
<argument index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" /> <argument index="0" name="up_direction" type="Vector2" default="Vector2(0, -1)" />
<description> <description>
The collision angle according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive. Returns the collision angle according to [code]up_direction[/code], which is [code]Vector2.UP[/code] by default. This value is always positive.
</description>
</method>
<method name="get_collider" qualifiers="const">
<return type="Object" />
<description>
Returns the colliding body's attached [Object].
</description>
</method>
<method name="get_collider_id" qualifiers="const">
<return type="int" />
<description>
Returns the unique instance ID of the colliding body's attached [Object]. See [method Object.get_instance_id].
</description>
</method>
<method name="get_collider_rid" qualifiers="const">
<return type="RID" />
<description>
Returns the colliding body's [RID] used by the [PhysicsServer2D].
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="Object" />
<description>
Returns the colliding body's shape.
</description>
</method>
<method name="get_collider_shape_index" qualifiers="const">
<return type="int" />
<description>
Returns the colliding body's shape index. See [CollisionObject2D].
</description>
</method>
<method name="get_collider_velocity" qualifiers="const">
<return type="Vector2" />
<description>
Returns the colliding body's velocity.
</description>
</method>
<method name="get_local_shape" qualifiers="const">
<return type="Object" />
<description>
Returns the moving object's colliding shape.
</description>
</method>
<method name="get_normal" qualifiers="const">
<return type="Vector2" />
<description>
Returns the colliding body's shape's normal at the point of collision.
</description>
</method>
<method name="get_position" qualifiers="const">
<return type="Vector2" />
<description>
Returns the point of collision in global coordinates.
</description>
</method>
<method name="get_remainder" qualifiers="const">
<return type="Vector2" />
<description>
Returns the moving object's remaining movement vector.
</description>
</method>
<method name="get_travel" qualifiers="const">
<return type="Vector2" />
<description>
Returns the moving object's travel before collision.
</description> </description>
</method> </method>
</methods> </methods>
<members>
<member name="collider" type="Object" setter="" getter="get_collider">
The colliding body.
</member>
<member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
The colliding body's unique instance ID. See [method Object.get_instance_id].
</member>
<member name="collider_rid" type="RID" setter="" getter="get_collider_rid">
The colliding body's [RID] used by the [PhysicsServer2D].
</member>
<member name="collider_shape" type="Object" setter="" getter="get_collider_shape">
The colliding body's shape.
</member>
<member name="collider_shape_index" type="int" setter="" getter="get_collider_shape_index" default="0">
The colliding shape's index. See [CollisionObject2D].
</member>
<member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2(0, 0)">
The colliding object's velocity.
</member>
<member name="local_shape" type="Object" setter="" getter="get_local_shape">
The moving object's colliding shape.
</member>
<member name="normal" type="Vector2" setter="" getter="get_normal" default="Vector2(0, 0)">
The colliding body's shape's normal at the point of collision.
</member>
<member name="position" type="Vector2" setter="" getter="get_position" default="Vector2(0, 0)">
The point of collision, in global coordinates.
</member>
<member name="remainder" type="Vector2" setter="" getter="get_remainder" default="Vector2(0, 0)">
The moving object's remaining movement vector.
</member>
<member name="travel" type="Vector2" setter="" getter="get_travel" default="Vector2(0, 0)">
The distance the moving object traveled before collision.
</member>
</members>
</class> </class>

View File

@ -15,108 +15,89 @@
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<argument index="1" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" /> <argument index="1" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
<description> <description>
The collision angle according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive. Returns the collision angle according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive.
</description> </description>
</method> </method>
<method name="get_collider" qualifiers="const"> <method name="get_collider" qualifiers="const">
<return type="Object" /> <return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider by index (the latest by default). Returns the colliding body's attached [Object] given a collision index (the deepest collision by default).
</description> </description>
</method> </method>
<method name="get_collider_id" qualifiers="const"> <method name="get_collider_id" qualifiers="const">
<return type="int" /> <return type="int" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider ID by index (the latest by default). Returns the unique instance ID of the colliding body's attached [Object] given a collision index (the deepest collision by default). See [method Object.get_instance_id].
</description> </description>
</method> </method>
<method name="get_collider_rid" qualifiers="const"> <method name="get_collider_rid" qualifiers="const">
<return type="RID" /> <return type="RID" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider RID by index (the latest by default). Returns the colliding body's [RID] used by the [PhysicsServer3D] given a collision index (the deepest collision by default).
</description> </description>
</method> </method>
<method name="get_collider_shape" qualifiers="const"> <method name="get_collider_shape" qualifiers="const">
<return type="Object" /> <return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider shape by index (the latest by default). Returns the colliding body's shape given a collision index (the deepest collision by default).
</description> </description>
</method> </method>
<method name="get_collider_shape_index" qualifiers="const"> <method name="get_collider_shape_index" qualifiers="const">
<return type="int" /> <return type="int" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider shape index by index (the latest by default). Returns the colliding body's shape index given a collision index (the deepest collision by default). See [CollisionObject3D].
</description> </description>
</method> </method>
<method name="get_collider_velocity" qualifiers="const"> <method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider velocity by index (the latest by default). Returns the colliding body's velocity given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_collision_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of detected collisions.
</description> </description>
</method> </method>
<method name="get_local_shape" qualifiers="const"> <method name="get_local_shape" qualifiers="const">
<return type="Object" /> <return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider velocity by index (the latest by default). Returns the moving object's colliding shape given a collision index (the deepest collision by default).
</description> </description>
</method> </method>
<method name="get_normal" qualifiers="const"> <method name="get_normal" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider normal by index (the latest by default). Returns the colliding body's shape's normal at the point of collision given a collision index (the deepest collision by default).
</description> </description>
</method> </method>
<method name="get_position" qualifiers="const"> <method name="get_position" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the collider collision point by index (the latest by default). Returns the point of collision in global coordinates given a collision index (the deepest collision by default).
</description>
</method>
<method name="get_remainder" qualifiers="const">
<return type="Vector3" />
<description>
Returns the moving object's remaining movement vector.
</description>
</method>
<method name="get_travel" qualifiers="const">
<return type="Vector3" />
<description>
Returns the moving object's travel before collision.
</description> </description>
</method> </method>
</methods> </methods>
<members>
<member name="collider" type="Object" setter="" getter="get_best_collider">
The colliding body.
</member>
<member name="collider_id" type="int" setter="" getter="get_best_collider_id" default="0">
The colliding body's unique instance ID. See [method Object.get_instance_id].
</member>
<member name="collider_rid" type="RID" setter="" getter="get_best_collider_rid">
The colliding body's [RID] used by the [PhysicsServer3D].
</member>
<member name="collider_shape" type="Object" setter="" getter="get_best_collider_shape">
The colliding body's shape.
</member>
<member name="collider_shape_index" type="int" setter="" getter="get_best_collider_shape_index" default="0">
The colliding shape's index. See [CollisionObject3D].
</member>
<member name="collider_velocity" type="Vector3" setter="" getter="get_best_collider_velocity" default="Vector3(0, 0, 0)">
The colliding object's velocity.
</member>
<member name="collision_count" type="int" setter="" getter="get_collision_count" default="0">
</member>
<member name="local_shape" type="Object" setter="" getter="get_best_local_shape">
The moving object's colliding shape.
</member>
<member name="normal" type="Vector3" setter="" getter="get_best_normal" default="Vector3(0, 0, 0)">
The colliding body's shape's normal at the point of collision.
</member>
<member name="position" type="Vector3" setter="" getter="get_best_position" default="Vector3(0, 0, 0)">
The point of collision, in global coordinates.
</member>
<member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3(0, 0, 0)">
The moving object's remaining movement vector.
</member>
<member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3(0, 0, 0)">
The distance the moving object traveled before collision.
</member>
</members>
</class> </class>

View File

@ -584,14 +584,10 @@
<method name="body_test_motion"> <method name="body_test_motion">
<return type="bool" /> <return type="bool" />
<argument index="0" name="body" type="RID" /> <argument index="0" name="body" type="RID" />
<argument index="1" name="from" type="Transform2D" /> <argument index="1" name="parameters" type="PhysicsTestMotionParameters2D" />
<argument index="2" name="motion" type="Vector2" /> <argument index="2" name="result" type="PhysicsTestMotionResult2D" default="null" />
<argument index="3" name="margin" type="float" default="0.08" />
<argument index="4" name="result" type="PhysicsTestMotionResult2D" default="null" />
<argument index="5" name="collide_separation_ray" type="bool" default="false" />
<argument index="6" name="exclude" type="Array" default="[]" />
<description> <description>
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult2D] can be passed to return additional information in. Returns [code]true[/code] if a collision would result from moving along a motion vector from a given point in space. [PhysicsTestMotionParameters2D] is passed to set motion parameters. [PhysicsTestMotionResult2D] can be passed to return additional information.
</description> </description>
</method> </method>
<method name="capsule_shape_create"> <method name="capsule_shape_create">

View File

@ -577,15 +577,10 @@
<method name="body_test_motion"> <method name="body_test_motion">
<return type="bool" /> <return type="bool" />
<argument index="0" name="body" type="RID" /> <argument index="0" name="body" type="RID" />
<argument index="1" name="from" type="Transform3D" /> <argument index="1" name="parameters" type="PhysicsTestMotionParameters3D" />
<argument index="2" name="motion" type="Vector3" /> <argument index="2" name="result" type="PhysicsTestMotionResult3D" default="null" />
<argument index="3" name="margin" type="float" default="0.001" />
<argument index="4" name="result" type="PhysicsTestMotionResult3D" default="null" />
<argument index="5" name="collide_separation_ray" type="bool" default="false" />
<argument index="6" name="exclude" type="Array" default="[]" />
<argument index="7" name="max_collisions" type="int" default="1" />
<description> <description>
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in. Returns [code]true[/code] if a collision would result from moving along a motion vector from a given point in space. [PhysicsTestMotionParameters3D] is passed to set motion parameters. [PhysicsTestMotionResult3D] can be passed to return additional information.
</description> </description>
</method> </method>
<method name="box_shape_create"> <method name="box_shape_create">

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsTestMotionParameters2D" inherits="RefCounted" version="4.0">
<brief_description>
Parameters to be sent to a 2D body motion test.
</brief_description>
<description>
This class contains parameters used in [method PhysicsServer2D.body_test_motion].
</description>
<tutorials>
</tutorials>
<members>
<member name="collide_separation_ray" type="bool" setter="set_collide_separation_ray_enabled" getter="is_collide_separation_ray_enabled" default="false">
If set to [code]true[/code], shapes of type [constant PhysicsServer2D.SHAPE_SEPARATION_RAY] are used to detect collisions and can stop the motion. Can be useful when snapping to the ground.
If set to [code]false[/code], shapes of type [constant PhysicsServer2D.SHAPE_SEPARATION_RAY] are only used for separation when overlapping with other bodies. That's the main use for separation ray shapes.
</member>
<member name="exclude_bodies" type="Array" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]">
Optional array of body [RID] to exclude from collision.
</member>
<member name="from" type="Transform2D" setter="set_from" getter="get_from" default="Transform2D(1, 0, 0, 1, 0, 0)">
Transform in global space where the motion should start. Usually set to [member Node2D.global_transform] for the current body's transform.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.08">
Increases the size of the shapes involved in the collision detection.
</member>
<member name="motion" type="Vector2" setter="set_motion" getter="get_motion" default="Vector2(0, 0)">
Motion vector to define the length and direction of the motion to test.
</member>
</members>
</class>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsTestMotionParameters3D" inherits="RefCounted" version="4.0">
<brief_description>
Parameters to be sent to a 3D body motion test.
</brief_description>
<description>
This class contains parameters used in [method PhysicsServer3D.body_test_motion].
</description>
<tutorials>
</tutorials>
<members>
<member name="collide_separation_ray" type="bool" setter="set_collide_separation_ray_enabled" getter="is_collide_separation_ray_enabled" default="false">
If set to [code]true[/code], shapes of type [constant PhysicsServer3D.SHAPE_SEPARATION_RAY] are used to detect collisions and can stop the motion. Can be useful when snapping to the ground.
If set to [code]false[/code], shapes of type [constant PhysicsServer3D.SHAPE_SEPARATION_RAY] are only used for separation when overlapping with other bodies. That's the main use for separation ray shapes.
</member>
<member name="exclude_bodies" type="Array" setter="set_exclude_bodies" getter="get_exclude_bodies" default="[]">
Optional array of body [RID] to exclude from collision.
</member>
<member name="from" type="Transform3D" setter="set_from" getter="get_from" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
Transform in global space where the motion should start. Usually set to [member Node3D.global_transform] for the current body's transform.
</member>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.001">
Increases the size of the shapes involved in the collision detection.
</member>
<member name="max_collisions" type="int" setter="set_max_collisions" getter="get_max_collisions" default="1">
Maximum number of returned collisions, between [code]1[/code] and [code]32[/code]. Always returns the deepest detected collisions.
</member>
<member name="motion" type="Vector3" setter="set_motion" getter="get_motion" default="Vector3(0, 0, 0)">
Motion vector to define the length and direction of the motion to test.
</member>
</members>
</class>

View File

@ -1,35 +1,91 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsTestMotionResult2D" inherits="RefCounted" version="4.0"> <class name="PhysicsTestMotionResult2D" inherits="RefCounted" version="4.0">
<brief_description> <brief_description>
Result from a 2D body motion test.
</brief_description> </brief_description>
<description> <description>
This class contains the motion and collision result from [method PhysicsServer2D.body_test_motion].
</description> </description>
<tutorials> <tutorials>
</tutorials> </tutorials>
<members> <methods>
<member name="collider" type="Object" setter="" getter="get_collider"> <method name="get_collider" qualifiers="const">
</member> <return type="Object" />
<member name="collider_id" type="int" setter="" getter="get_collider_id" default="0"> <description>
</member> Returns the colliding body's attached [Object], if a collision occured.
<member name="collider_rid" type="RID" setter="" getter="get_collider_rid"> </description>
</member> </method>
<member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0"> <method name="get_collider_id" qualifiers="const">
</member> <return type="int" />
<member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2(0, 0)"> <description>
</member> Returns the unique instance ID of the colliding body's attached [Object], if a collision occured. See [method Object.get_instance_id].
<member name="collision_depth" type="float" setter="" getter="get_collision_depth" default="0.0"> </description>
</member> </method>
<member name="collision_normal" type="Vector2" setter="" getter="get_collision_normal" default="Vector2(0, 0)"> <method name="get_collider_rid" qualifiers="const">
</member> <return type="RID" />
<member name="collision_point" type="Vector2" setter="" getter="get_collision_point" default="Vector2(0, 0)"> <description>
</member> Returns the colliding body's [RID] used by the [PhysicsServer2D], if a collision occured.
<member name="collision_safe_fraction" type="float" setter="" getter="get_collision_safe_fraction" default="0.0"> </description>
</member> </method>
<member name="collision_unsafe_fraction" type="float" setter="" getter="get_collision_unsafe_fraction" default="0.0"> <method name="get_collider_shape" qualifiers="const">
</member> <return type="int" />
<member name="remainder" type="Vector2" setter="" getter="get_remainder" default="Vector2(0, 0)"> <description>
</member> Returns the colliding body's shape index, if a collision occured. See [CollisionObject2D].
<member name="travel" type="Vector2" setter="" getter="get_travel" default="Vector2(0, 0)"> </description>
</member> </method>
</members> <method name="get_collider_velocity" qualifiers="const">
<return type="Vector2" />
<description>
Returns the colliding body's velocity, if a collision occured.
</description>
</method>
<method name="get_collision_depth" qualifiers="const">
<return type="float" />
<description>
Returns the length of overlap along the collision normal, if a collision occured.
</description>
</method>
<method name="get_collision_local_shape" qualifiers="const">
<return type="int" />
<description>
Returns the moving object's colliding shape, if a collision occured.
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
<return type="Vector2" />
<description>
Returns the colliding body's shape's normal at the point of collision, if a collision occured.
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector2" />
<description>
Returns the point of collision in global coordinates, if a collision occured.
</description>
</method>
<method name="get_collision_safe_fraction" qualifiers="const">
<return type="float" />
<description>
Returns the maximum fraction of the motion that can occur without a collision, between [code]0[/code] and [code]1[/code].
</description>
</method>
<method name="get_collision_unsafe_fraction" qualifiers="const">
<return type="float" />
<description>
Returns the minimum fraction of the motion needed to collide, if a collision occured, between [code]0[/code] and [code]1[/code].
</description>
</method>
<method name="get_remainder" qualifiers="const">
<return type="Vector2" />
<description>
Returns the moving object's remaining movement vector.
</description>
</method>
<method name="get_travel" qualifiers="const">
<return type="Vector2" />
<description>
Returns the moving object's travel before collision.
</description>
</method>
</methods>
</class> </class>

View File

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<class name="PhysicsTestMotionResult3D" inherits="RefCounted" version="4.0"> <class name="PhysicsTestMotionResult3D" inherits="RefCounted" version="4.0">
<brief_description> <brief_description>
Result from a 3D body motion test.
</brief_description> </brief_description>
<description> <description>
This class contains the motion and collision result from [method PhysicsServer3D.body_test_motion].
</description> </description>
<tutorials> <tutorials>
</tutorials> </tutorials>
@ -11,77 +13,94 @@
<return type="Object" /> <return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the colliding body's attached [Object] given a collision index (the deepest collision by default), if a collision occured.
</description> </description>
</method> </method>
<method name="get_collider_id" qualifiers="const"> <method name="get_collider_id" qualifiers="const">
<return type="int" /> <return type="int" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the unique instance ID of the colliding body's attached [Object] given a collision index (the deepest collision by default), if a collision occured. See [method Object.get_instance_id].
</description> </description>
</method> </method>
<method name="get_collider_rid" qualifiers="const"> <method name="get_collider_rid" qualifiers="const">
<return type="RID" /> <return type="RID" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the colliding body's [RID] used by the [PhysicsServer3D] given a collision index (the deepest collision by default), if a collision occured.
</description> </description>
</method> </method>
<method name="get_collider_shape" qualifiers="const"> <method name="get_collider_shape" qualifiers="const">
<return type="int" /> <return type="int" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the colliding body's shape index given a collision index (the deepest collision by default), if a collision occured. See [CollisionObject3D].
</description> </description>
</method> </method>
<method name="get_collider_velocity" qualifiers="const"> <method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the colliding body's velocity given a collision index (the deepest collision by default), if a collision occured.
</description>
</method>
<method name="get_collision_count" qualifiers="const">
<return type="int" />
<description>
Returns the number of detected collisions.
</description> </description>
</method> </method>
<method name="get_collision_depth" qualifiers="const"> <method name="get_collision_depth" qualifiers="const">
<return type="float" /> <return type="float" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the length of overlap along the collision normal given a collision index (the deepest collision by default), if a collision occured.
</description>
</method>
<method name="get_collision_local_shape" qualifiers="const">
<return type="int" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the moving object's colliding shape given a collision index (the deepest collision by default), if a collision occured.
</description> </description>
</method> </method>
<method name="get_collision_normal" qualifiers="const"> <method name="get_collision_normal" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the colliding body's shape's normal at the point of collision given a collision index (the deepest collision by default), if a collision occured.
</description> </description>
</method> </method>
<method name="get_collision_point" qualifiers="const"> <method name="get_collision_point" qualifiers="const">
<return type="Vector3" /> <return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" /> <argument index="0" name="collision_index" type="int" default="0" />
<description> <description>
Returns the point of collision in global coordinates given a collision index (the deepest collision by default), if a collision occured.
</description>
</method>
<method name="get_collision_safe_fraction" qualifiers="const">
<return type="float" />
<description>
Returns the maximum fraction of the motion that can occur without a collision, between [code]0[/code] and [code]1[/code].
</description>
</method>
<method name="get_collision_unsafe_fraction" qualifiers="const">
<return type="float" />
<description>
Returns the minimum fraction of the motion needed to collide, if a collision occured, between [code]0[/code] and [code]1[/code].
</description>
</method>
<method name="get_remainder" qualifiers="const">
<return type="Vector3" />
<description>
Returns the moving object's remaining movement vector.
</description>
</method>
<method name="get_travel" qualifiers="const">
<return type="Vector3" />
<description>
Returns the moving object's travel before collision.
</description> </description>
</method> </method>
</methods> </methods>
<members>
<member name="collider" type="Object" setter="" getter="get_best_collider">
</member>
<member name="collider_id" type="int" setter="" getter="get_best_collider_id" default="0">
</member>
<member name="collider_rid" type="RID" setter="" getter="get_best_collider_rid">
</member>
<member name="collider_shape" type="int" setter="" getter="get_best_collider_shape" default="0">
</member>
<member name="collider_velocity" type="Vector3" setter="" getter="get_best_collider_velocity" default="Vector3(0, 0, 0)">
</member>
<member name="collision_count" type="int" setter="" getter="get_collision_count" default="0">
</member>
<member name="collision_depth" type="float" setter="" getter="get_best_collision_depth" default="0.0">
</member>
<member name="collision_normal" type="Vector3" setter="" getter="get_best_collision_normal" default="Vector3(0, 0, 0)">
</member>
<member name="collision_point" type="Vector3" setter="" getter="get_best_collision_point" default="Vector3(0, 0, 0)">
</member>
<member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3(0, 0, 0)">
</member>
<member name="safe_fraction" type="float" setter="" getter="get_safe_fraction" default="0.0">
</member>
<member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3(0, 0, 0)">
</member>
<member name="unsafe_fraction" type="float" setter="" getter="get_unsafe_fraction" default="0.0">
</member>
</members>
</class> </class>

View File

@ -73,7 +73,7 @@
<return type="Vector2i" /> <return type="Vector2i" />
<argument index="0" name="body" type="RID" /> <argument index="0" name="body" type="RID" />
<description> <description>
Returns the coodinates of the tile for given physics body RID. Such RID can be retrieved from [member KinematicCollision2D.collider_rid], when colliding with a tile. Returns the coodinates of the tile for given physics body RID. Such RID can be retrieved from [method KinematicCollision2D.get_collider_rid], when colliding with a tile.
</description> </description>
</method> </method>
<method name="get_layer_name" qualifiers="const"> <method name="get_layer_name" qualifiers="const">

View File

@ -54,13 +54,14 @@ PhysicsBody2D::~PhysicsBody2D() {
} }
} }
Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_test_only, real_t p_margin) { Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_linear_velocity, bool p_test_only, real_t p_margin) {
PhysicsServer2D::MotionResult result;
// 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.
double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); 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)) { PhysicsServer2D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin);
PhysicsServer2D::MotionResult result;
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script. // 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) { if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
motion_cache.instantiate(); motion_cache.instantiate();
@ -74,18 +75,18 @@ Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_t
return Ref<KinematicCollision2D>(); return Ref<KinematicCollision2D>();
} }
bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool PhysicsBody2D::move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) {
if (is_only_update_transform_changes_enabled()) { if (is_only_update_transform_changes_enabled()) {
ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation."); ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation.");
} }
Transform2D gt = get_global_transform();
bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_collide_separation_ray, p_exclude); bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result);
// Restore direction of motion to be along original motion, // Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery, // in order to avoid sliding due to recovery,
// but only if collision depth is low enough to avoid tunneling. // but only if collision depth is low enough to avoid tunneling.
if (p_cancel_sliding) { if (p_cancel_sliding) {
real_t motion_length = p_motion.length(); real_t motion_length = p_parameters.motion.length();
real_t precision = 0.001; real_t precision = 0.001;
if (colliding) { if (colliding) {
@ -93,7 +94,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M
// so even in normal resting cases the depth can be a bit more than the margin. // so even in normal resting cases the depth can be a bit more than the margin.
precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction);
if (r_result.collision_depth > (real_t)p_margin + precision) { if (r_result.collision_depth > p_parameters.margin + precision) {
p_cancel_sliding = false; p_cancel_sliding = false;
} }
} }
@ -102,7 +103,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M
// When motion is null, recovery is the resulting motion. // When motion is null, recovery is the resulting motion.
Vector2 motion_normal; Vector2 motion_normal;
if (motion_length > CMP_EPSILON) { if (motion_length > CMP_EPSILON) {
motion_normal = p_motion / motion_length; motion_normal = p_parameters.motion / motion_length;
} }
// Check depth of recovery. // Check depth of recovery.
@ -111,15 +112,16 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M
real_t recovery_length = recovery.length(); real_t recovery_length = recovery.length();
// Fixes cases where canceling slide causes the motion to go too deep into the ground, // Fixes cases where canceling slide causes the motion to go too deep into the ground,
// because we're only taking rest information into account and not general recovery. // because we're only taking rest information into account and not general recovery.
if (recovery_length < (real_t)p_margin + precision) { if (recovery_length < p_parameters.margin + precision) {
// Apply adjustment to motion. // Apply adjustment to motion.
r_result.travel = motion_normal * projected_length; r_result.travel = motion_normal * projected_length;
r_result.remainder = p_motion - r_result.travel; r_result.remainder = p_parameters.motion - r_result.travel;
} }
} }
} }
if (!p_test_only) { if (!p_test_only) {
Transform2D gt = p_parameters.from;
gt.elements[2] += r_result.travel; gt.elements[2] += r_result.travel;
set_global_transform(gt); set_global_transform(gt);
} }
@ -127,7 +129,7 @@ bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, PhysicsServer2D::M
return colliding; return colliding;
} }
bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) {
ERR_FAIL_COND_V(!is_inside_tree(), false); ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer2D::MotionResult *r = nullptr; PhysicsServer2D::MotionResult *r = nullptr;
@ -139,7 +141,9 @@ bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion
// 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.
double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); 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); PhysicsServer2D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin);
return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), parameters, r);
} }
TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() {
@ -1083,10 +1087,11 @@ bool CharacterBody2D::move_and_slide() {
on_wall = false; on_wall = false;
if (!current_platform_velocity.is_equal_approx(Vector2())) { if (!current_platform_velocity.is_equal_approx(Vector2())) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
parameters.exclude_bodies.insert(platform_rid);
PhysicsServer2D::MotionResult floor_result; PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude; if (move_and_collide(parameters, floor_result, false, false)) {
exclude.insert(platform_rid);
if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, false, false, exclude)) {
motion_results.push_back(floor_result); motion_results.push_back(floor_result);
_set_collision_direction(floor_result); _set_collision_direction(floor_result);
} }
@ -1138,11 +1143,13 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
Vector2 last_travel; Vector2 last_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) { for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
Vector2 prev_position = parameters.from.elements[2];
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
Vector2 prev_position = get_global_transform().elements[2];
bool collided = move_and_collide(motion, result, margin, false, !sliding_enabled);
last_motion = result.travel; last_motion = result.travel;
if (collided) { if (collided) {
@ -1283,9 +1290,11 @@ void CharacterBody2D::_move_and_slide_free(double p_delta) {
bool first_slide = true; bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) { for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionParameters parameters(get_global_transform(), motion, margin);
PhysicsServer2D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, false);
bool collided = move_and_collide(motion, result, margin, false, false);
last_motion = result.travel; last_motion = result.travel;
if (collided) { if (collided) {
@ -1327,10 +1336,11 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
// Snap by at least collision margin to keep floor state consistent. // Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin); real_t length = MAX(floor_snap_length, margin);
Transform2D gt = get_global_transform(); PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionResult result;
if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { if (move_and_collide(parameters, result, true, false)) {
bool apply = true;
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
on_floor = true; on_floor = true;
floor_normal = result.collision_normal; floor_normal = result.collision_normal;
@ -1345,13 +1355,9 @@ void CharacterBody2D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
result.travel = Vector2(); result.travel = Vector2();
} }
} }
} else {
apply = false;
}
if (apply) { parameters.from.elements[2] += result.travel;
gt.elements[2] += result.travel; set_global_transform(parameters.from);
set_global_transform(gt);
} }
} }
} }
@ -1364,8 +1370,11 @@ bool CharacterBody2D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
// Snap by at least collision margin to keep floor state consistent. // Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin); real_t length = MAX(floor_snap_length, margin);
PhysicsServer2D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.collide_separation_ray = true;
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionResult result;
if (move_and_collide(-up_direction * length, result, margin, true, false, true)) { if (move_and_collide(parameters, result, true, false)) {
if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { if (result.get_angle(up_direction) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) {
return true; return true;
} }
@ -1806,16 +1815,4 @@ void KinematicCollision2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index); ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index);
ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "normal"), "", "get_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id");
ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
} }

View File

@ -47,11 +47,11 @@ protected:
Ref<KinematicCollision2D> motion_cache; Ref<KinematicCollision2D> motion_cache;
Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_test_only = false, real_t p_margin = 0.08); Ref<KinematicCollision2D> _move(const Vector2 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.08);
public: public:
bool move_and_collide(const Vector2 &p_motion, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); bool move_and_collide(const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
bool test_move(const Transform2D &p_from, const Vector2 &p_motion, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); bool test_move(const Transform2D &p_from, const Vector2 &p_linear_velocity, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08);
TypedArray<PhysicsBody2D> get_collision_exceptions(); TypedArray<PhysicsBody2D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node); //must be physicsbody void add_collision_exception_with(Node *p_node); //must be physicsbody

View File

@ -91,12 +91,15 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid());
} }
Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_test_only, real_t p_margin, int p_max_collisions) { Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_linear_velocity, bool p_test_only, real_t p_margin, int p_max_collisions) {
PhysicsServer3D::MotionResult result;
// 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
double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); 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)) { PhysicsServer3D::MotionParameters parameters(get_global_transform(), p_linear_velocity * delta, p_margin);
parameters.max_collisions = p_max_collisions;
PhysicsServer3D::MotionResult result;
if (move_and_collide(parameters, result, p_test_only)) {
// Create a new instance when the cached reference is invalid or still in use in script. // 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) { if (motion_cache.is_null() || motion_cache->reference_get_count() > 1) {
motion_cache.instantiate(); motion_cache.instantiate();
@ -111,23 +114,22 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_t
return Ref<KinematicCollision3D>(); return Ref<KinematicCollision3D>();
} }
bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only, int p_max_collisions, bool p_cancel_sliding, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool PhysicsBody3D::move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only, bool p_cancel_sliding) {
Transform3D gt = get_global_transform(); bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_parameters, &r_result);
bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_margin, &r_result, p_max_collisions, p_collide_separation_ray, p_exclude);
// Restore direction of motion to be along original motion, // Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery, // in order to avoid sliding due to recovery,
// but only if collision depth is low enough to avoid tunneling. // but only if collision depth is low enough to avoid tunneling.
if (p_cancel_sliding) { if (p_cancel_sliding) {
real_t motion_length = p_motion.length(); real_t motion_length = p_parameters.motion.length();
real_t precision = 0.001; real_t precision = 0.001;
if (colliding) { if (colliding) {
// Can't just use margin as a threshold because collision depth is calculated on unsafe motion, // Can't just use margin as a threshold because collision depth is calculated on unsafe motion,
// so even in normal resting cases the depth can be a bit more than the margin. // so even in normal resting cases the depth can be a bit more than the margin.
precision += motion_length * (r_result.unsafe_fraction - r_result.safe_fraction); precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction);
if (r_result.collisions[0].depth > (real_t)p_margin + precision) { if (r_result.collisions[0].depth > p_parameters.margin + precision) {
p_cancel_sliding = false; p_cancel_sliding = false;
} }
} }
@ -136,7 +138,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
// When motion is null, recovery is the resulting motion. // When motion is null, recovery is the resulting motion.
Vector3 motion_normal; Vector3 motion_normal;
if (motion_length > CMP_EPSILON) { if (motion_length > CMP_EPSILON) {
motion_normal = p_motion / motion_length; motion_normal = p_parameters.motion / motion_length;
} }
// Check depth of recovery. // Check depth of recovery.
@ -145,10 +147,10 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
real_t recovery_length = recovery.length(); real_t recovery_length = recovery.length();
// Fixes cases where canceling slide causes the motion to go too deep into the ground, // Fixes cases where canceling slide causes the motion to go too deep into the ground,
// because we're only taking rest information into account and not general recovery. // because we're only taking rest information into account and not general recovery.
if (recovery_length < (real_t)p_margin + precision) { if (recovery_length < p_parameters.margin + precision) {
// Apply adjustment to motion. // Apply adjustment to motion.
r_result.travel = motion_normal * projected_length; r_result.travel = motion_normal * projected_length;
r_result.remainder = p_motion - r_result.travel; r_result.remainder = p_parameters.motion - r_result.travel;
} }
} }
} }
@ -160,6 +162,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
} }
if (!p_test_only) { if (!p_test_only) {
Transform3D gt = p_parameters.from;
gt.origin += r_result.travel; gt.origin += r_result.travel;
set_global_transform(gt); set_global_transform(gt);
} }
@ -167,7 +170,7 @@ bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, PhysicsServer3D::M
return colliding; return colliding;
} }
bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) { bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision, real_t p_margin, int p_max_collisions) {
ERR_FAIL_COND_V(!is_inside_tree(), false); ERR_FAIL_COND_V(!is_inside_tree(), false);
PhysicsServer3D::MotionResult *r = nullptr; PhysicsServer3D::MotionResult *r = nullptr;
@ -179,7 +182,9 @@ bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion
// 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
double delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time(); 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); PhysicsServer3D::MotionParameters parameters(p_from, p_linear_velocity * delta, p_margin);
return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), parameters, r);
} }
void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) {
@ -1124,10 +1129,11 @@ bool CharacterBody3D::move_and_slide() {
last_motion = Vector3(); last_motion = Vector3();
if (!current_platform_velocity.is_equal_approx(Vector3())) { if (!current_platform_velocity.is_equal_approx(Vector3())) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
parameters.exclude_bodies.insert(platform_rid);
PhysicsServer3D::MotionResult floor_result; PhysicsServer3D::MotionResult floor_result;
Set<RID> exclude; if (move_and_collide(parameters, floor_result, false, false)) {
exclude.insert(platform_rid);
if (move_and_collide(current_platform_velocity * delta, floor_result, margin, false, 1, false, false, exclude)) {
motion_results.push_back(floor_result); motion_results.push_back(floor_result);
CollisionState result_state; CollisionState result_state;
@ -1181,8 +1187,12 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
Vector3 total_travel; Vector3 total_travel;
for (int iteration = 0; iteration < max_slides; ++iteration) { for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
parameters.max_collisions = 4;
PhysicsServer3D::MotionResult result; PhysicsServer3D::MotionResult result;
bool collided = move_and_collide(motion, result, margin, false, 4, !sliding_enabled); bool collided = move_and_collide(parameters, result, false, !sliding_enabled);
last_motion = result.travel; last_motion = result.travel;
if (collided) { if (collided) {
@ -1411,9 +1421,11 @@ void CharacterBody3D::_move_and_slide_free(double p_delta) {
bool first_slide = true; bool first_slide = true;
for (int iteration = 0; iteration < max_slides; ++iteration) { for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result; PhysicsServer3D::MotionParameters parameters(get_global_transform(), motion, margin);
PhysicsServer3D::MotionResult result;
bool collided = move_and_collide(parameters, result, false, false);
bool collided = move_and_collide(motion, result, margin, false, 1, false);
last_motion = result.travel; last_motion = result.travel;
if (collided) { if (collided) {
@ -1462,9 +1474,12 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
// Snap by at least collision margin to keep floor state consistent. // Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin); real_t length = MAX(floor_snap_length, margin);
Transform3D gt = get_global_transform(); PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.max_collisions = 4;
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result; PhysicsServer3D::MotionResult result;
if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) { if (move_and_collide(parameters, result, true, false)) {
CollisionState result_state; CollisionState result_state;
// Apply direction for floor only. // Apply direction for floor only.
_set_collision_direction(result, result_state, CollisionState(true, false, false)); _set_collision_direction(result, result_state, CollisionState(true, false, false));
@ -1480,8 +1495,8 @@ void CharacterBody3D::_snap_on_floor(bool was_on_floor, bool vel_dir_facing_up)
} }
} }
gt.origin += result.travel; parameters.from.origin += result.travel;
set_global_transform(gt); set_global_transform(parameters.from);
} }
} }
} }
@ -1494,8 +1509,12 @@ bool CharacterBody3D::_on_floor_if_snapped(bool was_on_floor, bool vel_dir_facin
// Snap by at least collision margin to keep floor state consistent. // Snap by at least collision margin to keep floor state consistent.
real_t length = MAX(floor_snap_length, margin); real_t length = MAX(floor_snap_length, margin);
PhysicsServer3D::MotionParameters parameters(get_global_transform(), -up_direction * length, margin);
parameters.max_collisions = 4;
parameters.collide_separation_ray = true;
PhysicsServer3D::MotionResult result; PhysicsServer3D::MotionResult result;
if (move_and_collide(-up_direction * length, result, margin, true, 4, false, true)) { if (move_and_collide(parameters, result, true, false)) {
CollisionState result_state; CollisionState result_state;
// Don't apply direction for any type. // Don't apply direction for any type.
_set_collision_direction(result, result_state, CollisionState()); _set_collision_direction(result, result_state, CollisionState());
@ -2002,42 +2021,6 @@ Vector3 KinematicCollision3D::get_collider_velocity(int p_collision_index) const
return result.collisions[p_collision_index].collider_velocity; return result.collisions[p_collision_index].collider_velocity;
} }
Vector3 KinematicCollision3D::get_best_position() const {
return result.collision_count ? get_position() : Vector3();
}
Vector3 KinematicCollision3D::get_best_normal() const {
return result.collision_count ? get_normal() : Vector3();
}
Object *KinematicCollision3D::get_best_local_shape() const {
return result.collision_count ? get_local_shape() : nullptr;
}
Object *KinematicCollision3D::get_best_collider() const {
return result.collision_count ? get_collider() : nullptr;
}
ObjectID KinematicCollision3D::get_best_collider_id() const {
return result.collision_count ? get_collider_id() : ObjectID();
}
RID KinematicCollision3D::get_best_collider_rid() const {
return result.collision_count ? get_collider_rid() : RID();
}
Object *KinematicCollision3D::get_best_collider_shape() const {
return result.collision_count ? get_collider_shape() : nullptr;
}
int KinematicCollision3D::get_best_collider_shape_index() const {
return result.collision_count ? get_collider_shape_index() : 0;
}
Vector3 KinematicCollision3D::get_best_collider_velocity() const {
return result.collision_count ? get_collider_velocity() : Vector3();
}
void KinematicCollision3D::_bind_methods() { void KinematicCollision3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel); ClassDB::bind_method(D_METHOD("get_travel"), &KinematicCollision3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder); ClassDB::bind_method(D_METHOD("get_remainder"), &KinematicCollision3D::get_remainder);
@ -2052,29 +2035,6 @@ void KinematicCollision3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &KinematicCollision3D::get_collider_shape, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider_shape_index", "collision_index"), &KinematicCollision3D::get_collider_shape_index, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &KinematicCollision3D::get_collider_velocity, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_best_position"), &KinematicCollision3D::get_best_position);
ClassDB::bind_method(D_METHOD("get_best_normal"), &KinematicCollision3D::get_best_normal);
ClassDB::bind_method(D_METHOD("get_best_local_shape"), &KinematicCollision3D::get_best_local_shape);
ClassDB::bind_method(D_METHOD("get_best_collider"), &KinematicCollision3D::get_best_collider);
ClassDB::bind_method(D_METHOD("get_best_collider_id"), &KinematicCollision3D::get_best_collider_id);
ClassDB::bind_method(D_METHOD("get_best_collider_rid"), &KinematicCollision3D::get_best_collider_rid);
ClassDB::bind_method(D_METHOD("get_best_collider_shape"), &KinematicCollision3D::get_best_collider_shape);
ClassDB::bind_method(D_METHOD("get_best_collider_shape_index"), &KinematicCollision3D::get_best_collider_shape_index);
ClassDB::bind_method(D_METHOD("get_best_collider_velocity"), &KinematicCollision3D::get_best_collider_velocity);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_count"), "", "get_collision_count");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "", "get_best_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "normal"), "", "get_best_normal");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_best_local_shape");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_best_collider");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_best_collider_id");
ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_best_collider_rid");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_best_collider_shape");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_best_collider_shape_index");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_best_collider_velocity");
} }
/////////////////////////////////////// ///////////////////////////////////////

View File

@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0; uint16_t locked_axis = 0;
Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1); Ref<KinematicCollision3D> _move(const Vector3 &p_linear_velocity, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1);
public: public:
bool move_and_collide(const Vector3 &p_motion, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_test_only = false, int p_max_collisions = 1, bool p_cancel_sliding = true, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true);
bool test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1); bool test_move(const Transform3D &p_from, const Vector3 &p_linear_velocity, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001, int p_max_collisions = 1);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@ -487,16 +487,6 @@ public:
Object *get_collider_shape(int p_collision_index = 0) const; Object *get_collider_shape(int p_collision_index = 0) const;
int get_collider_shape_index(int p_collision_index = 0) const; int get_collider_shape_index(int p_collision_index = 0) const;
Vector3 get_collider_velocity(int p_collision_index = 0) const; Vector3 get_collider_velocity(int p_collision_index = 0) const;
Vector3 get_best_position() const;
Vector3 get_best_normal() const;
Object *get_best_local_shape() const;
Object *get_best_collider() const;
ObjectID get_best_collider_id() const;
RID get_best_collider_rid() const;
Object *get_best_collider_shape() const;
int get_best_collider_shape_index() const;
Vector3 get_best_collider_velocity() const;
}; };
class PhysicalBone3D : public PhysicsBody3D { class PhysicalBone3D : public PhysicsBody3D {

View File

@ -948,7 +948,7 @@ void PhysicsServer2DSW::body_set_pickable(RID p_body, bool p_pickable) {
body->set_pickable(p_pickable); body->set_pickable(p_pickable);
} }
bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool PhysicsServer2DSW::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) {
Body2DSW *body = body_owner.get_or_null(p_body); Body2DSW *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false); ERR_FAIL_COND_V(!body->get_space(), false);
@ -956,7 +956,7 @@ bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from,
_update_shapes(); _update_shapes();
return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); return body->get_space()->test_body_motion(body, p_parameters, r_result);
} }
PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) { PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) {

View File

@ -246,7 +246,7 @@ public:
virtual void body_set_pickable(RID p_body, bool p_pickable) override; virtual void body_set_pickable(RID p_body, bool p_pickable) override;
virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override; virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override;
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override; virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override;

View File

@ -254,9 +254,9 @@ public:
FUNC2(body_set_pickable, RID, bool); FUNC2(body_set_pickable, RID, bool);
bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override { bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); return physics_2d_server->body_test_motion(p_body, p_parameters, r_result);
} }
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise

View File

@ -525,7 +525,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) {
return amount; return amount;
} }
bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool Space2DSW::test_body_motion(Body2DSW *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result) {
//give me back regular physics engine logic //give me back regular physics engine logic
//this is madness //this is madness
//and most people using this function will think //and most people using this function will think
@ -557,25 +557,25 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
if (!shapes_found) { if (!shapes_found) {
if (r_result) { if (r_result) {
*r_result = PhysicsServer2D::MotionResult(); *r_result = PhysicsServer2D::MotionResult();
r_result->travel = p_motion; r_result->travel = p_parameters.motion;
} }
return false; return false;
} }
// Undo the currently transform the physics server is aware of and apply the provided one // Undo the currently transform the physics server is aware of and apply the provided one
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin); body_aabb = body_aabb.grow(p_parameters.margin);
static const int max_excluded_shape_pairs = 32; static const int max_excluded_shape_pairs = 32;
ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs]; ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs];
int excluded_shape_pair_count = 0; int excluded_shape_pair_count = 0;
real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
real_t motion_length = p_motion.length(); real_t motion_length = p_parameters.motion.length();
Vector2 motion_normal = p_motion / motion_length; Vector2 motion_normal = p_parameters.motion / motion_length;
Transform2D body_transform = p_from; Transform2D body_transform = p_parameters.from;
bool recovered = false; bool recovered = false;
@ -612,7 +612,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject2DSW *col_obj = intersection_query_results[i]; const CollisionObject2DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
@ -624,7 +624,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work cbk.valid_depth = MAX(owc_margin, p_parameters.margin); //user specified, but never less than actual margin or it won't work
cbk.invalid_by_dir = 0; cbk.invalid_by_dir = 0;
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
@ -649,7 +649,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
bool did_collide = false; bool did_collide = false;
Shape2DSW *against_shape = col_obj->get_shape(shape_idx); Shape2DSW *against_shape = col_obj->get_shape(shape_idx);
if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) { if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_parameters.margin)) {
did_collide = cbk.passed > current_passed; //more passed, so collision actually existed did_collide = cbk.passed > current_passed; //more passed, so collision actually existed
} }
@ -714,7 +714,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
// STEP 2 ATTEMPT MOTION // STEP 2 ATTEMPT MOTION
Rect2 motion_aabb = body_aabb; Rect2 motion_aabb = body_aabb;
motion_aabb.position += p_motion; motion_aabb.position += p_parameters.motion;
motion_aabb = motion_aabb.merge(body_aabb); motion_aabb = motion_aabb.merge(body_aabb);
int amount = _cull_aabb_for_body(p_body, motion_aabb); int amount = _cull_aabb_for_body(p_body, motion_aabb);
@ -728,7 +728,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
// Colliding separation rays allows to properly snap to the ground, // Colliding separation rays allows to properly snap to the ground,
// otherwise it's not needed in regular motion. // otherwise it's not needed in regular motion.
if (!p_collide_separation_ray && (body_shape->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY)) { if (!p_parameters.collide_separation_ray && (body_shape->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY)) {
// When slide on slope is on, separation ray shape acts like a regular shape. // When slide on slope is on, separation ray shape acts like a regular shape.
if (!static_cast<SeparationRayShape2DSW *>(body_shape)->get_slide_on_slope()) { if (!static_cast<SeparationRayShape2DSW *>(body_shape)->get_slide_on_slope()) {
continue; continue;
@ -744,9 +744,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject2DSW *col_obj = intersection_query_results[i]; const CollisionObject2DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
int col_shape_idx = intersection_query_subindex_results[i]; int col_shape_idx = intersection_query_subindex_results[i];
Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx); Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx);
@ -765,7 +766,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx); Transform2D col_obj_shape_xform = col_obj->get_transform() * col_obj->get_shape_transform(col_shape_idx);
//test initial overlap, does it collide if going all the way? //test initial overlap, does it collide if going all the way?
if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { if (!CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_parameters.motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) {
continue; continue;
} }
@ -790,7 +791,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
real_t fraction = low + (hi - low) * fraction_coeff; real_t fraction = low + (hi - low) * fraction_coeff;
Vector2 sep = motion_normal; //important optimization for this to work fast enough Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * fraction, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0); bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_parameters.motion * fraction, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0);
if (collided) { if (collided) {
hi = fraction; hi = fraction;
@ -827,7 +828,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
cbk.valid_depth = 10e20; cbk.valid_depth = 10e20;
Vector2 sep = motion_normal; //important optimization for this to work fast enough Vector2 sep = motion_normal; //important optimization for this to work fast enough
bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0); bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_parameters.motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0);
if (!collided || cbk.amount == 0) { if (!collided || cbk.amount == 0) {
continue; continue;
} }
@ -865,7 +866,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
//it collided, let's get the rest info in unsafe advance //it collided, let's get the rest info in unsafe advance
Transform2D ugt = body_transform; Transform2D ugt = body_transform;
ugt.elements[2] += p_motion * unsafe; ugt.elements[2] += p_parameters.motion * unsafe;
_RestCallbackData2D rcd; _RestCallbackData2D rcd;
rcd.best_len = 0; rcd.best_len = 0;
@ -886,13 +887,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j);
Shape2DSW *body_shape = p_body->get_shape(j); Shape2DSW *body_shape = p_body->get_shape(j);
body_aabb.position += p_motion * unsafe; body_aabb.position += p_parameters.motion * unsafe;
int amount = _cull_aabb_for_body(p_body, body_aabb); int amount = _cull_aabb_for_body(p_body, body_aabb);
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject2DSW *col_obj = intersection_query_results[i]; const CollisionObject2DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
@ -917,7 +918,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized();
real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx);
rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work rcd.valid_depth = MAX(owc_margin, p_parameters.margin); //user specified, but never less than actual margin or it won't work
if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) {
const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); const Body2DSW *b = static_cast<const Body2DSW *>(col_obj);
@ -939,7 +940,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
rcd.object = col_obj; rcd.object = col_obj;
rcd.shape = shape_idx; rcd.shape = shape_idx;
rcd.local_shape = j; rcd.local_shape = j;
bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, p_margin); bool sc = CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, p_parameters.margin);
if (!sc) { if (!sc) {
continue; continue;
} }
@ -962,9 +963,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass()); Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass());
r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();
r_result->travel = safe * p_motion; r_result->travel = safe * p_parameters.motion;
r_result->remainder = p_motion - safe * p_motion; r_result->remainder = p_parameters.motion - safe * p_parameters.motion;
r_result->travel += (body_transform.get_origin() - p_from.get_origin()); r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
} }
collided = true; collided = true;
@ -972,9 +973,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co
} }
if (!collided && r_result) { if (!collided && r_result) {
r_result->travel = p_motion; r_result->travel = p_parameters.motion;
r_result->remainder = Vector2(); r_result->remainder = Vector2();
r_result->travel += (body_transform.get_origin() - p_from.get_origin()); r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
} }
return collided; return collided;

View File

@ -187,7 +187,7 @@ public:
int get_collision_pairs() const { return collision_pairs; } int get_collision_pairs() const { return collision_pairs; }
bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); bool test_body_motion(Body2DSW *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result);
void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
_FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); }

View File

@ -868,7 +868,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) {
body->set_ray_pickable(p_enable); body->set_ray_pickable(p_enable);
} }
bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, MotionResult *r_result, int p_max_collisions, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool PhysicsServer3DSW::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) {
Body3DSW *body = body_owner.get_or_null(p_body); Body3DSW *body = body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false); ERR_FAIL_COND_V(!body->get_space(), false);
@ -876,7 +876,7 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from,
_update_shapes(); _update_shapes();
return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_max_collisions, p_collide_separation_ray, p_exclude); return body->get_space()->test_body_motion(body, p_parameters, r_result);
} }
PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) { PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) {

View File

@ -242,7 +242,7 @@ public:
virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; virtual void body_set_ray_pickable(RID p_body, bool p_enable) override;
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, int p_max_collisions = 1, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override; virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override;
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;

View File

@ -253,9 +253,9 @@ public:
FUNC2(body_set_ray_pickable, RID, bool); FUNC2(body_set_ray_pickable, RID, bool);
bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, int p_max_collisions = 1, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override { bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override {
ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false);
return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_max_collisions, p_collide_separation_ray, p_exclude); return physics_3d_server->body_test_motion(p_body, p_parameters, r_result);
} }
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise

View File

@ -620,7 +620,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
return amount; return amount;
} }
bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, int p_max_collisions, bool p_collide_separation_ray, const Set<RID> &p_exclude) { bool Space3DSW::test_body_motion(Body3DSW *p_body, const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult *r_result) {
//give me back regular physics engine logic //give me back regular physics engine logic
//this is madness //this is madness
//and most people using this function will think //and most people using this function will think
@ -628,7 +628,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
//this took about a week to get right.. //this took about a week to get right..
//but is it right? who knows at this point.. //but is it right? who knows at this point..
ERR_FAIL_INDEX_V(p_max_collisions, PhysicsServer3D::MotionResult::MAX_COLLISIONS, false); ERR_FAIL_INDEX_V(p_parameters.max_collisions, PhysicsServer3D::MotionResult::MAX_COLLISIONS, false);
if (r_result) { if (r_result) {
*r_result = PhysicsServer3D::MotionResult(); *r_result = PhysicsServer3D::MotionResult();
@ -652,22 +652,22 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
if (!shapes_found) { if (!shapes_found) {
if (r_result) { if (r_result) {
r_result->travel = p_motion; r_result->travel = p_parameters.motion;
} }
return false; return false;
} }
// Undo the currently transform the physics server is aware of and apply the provided one // Undo the currently transform the physics server is aware of and apply the provided one
body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb));
body_aabb = body_aabb.grow(p_margin); body_aabb = body_aabb.grow(p_parameters.margin);
real_t min_contact_depth = p_margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR;
real_t motion_length = p_motion.length(); real_t motion_length = p_parameters.motion.length();
Vector3 motion_normal = p_motion / motion_length; Vector3 motion_normal = p_parameters.motion / motion_length;
Transform3D body_transform = p_from; Transform3D body_transform = p_parameters.from;
bool recovered = false; bool recovered = false;
@ -701,13 +701,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i]; const CollisionObject3DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
int shape_idx = intersection_query_subindex_results[i]; int shape_idx = intersection_query_subindex_results[i];
if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) { if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_parameters.margin)) {
collided = cbk.amount > 0; collided = cbk.amount > 0;
} }
} }
@ -757,7 +757,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
// STEP 2 ATTEMPT MOTION // STEP 2 ATTEMPT MOTION
AABB motion_aabb = body_aabb; AABB motion_aabb = body_aabb;
motion_aabb.position += p_motion; motion_aabb.position += p_parameters.motion;
motion_aabb = motion_aabb.merge(body_aabb); motion_aabb = motion_aabb.merge(body_aabb);
int amount = _cull_aabb_for_body(p_body, motion_aabb); int amount = _cull_aabb_for_body(p_body, motion_aabb);
@ -771,7 +771,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
// Colliding separation rays allows to properly snap to the ground, // Colliding separation rays allows to properly snap to the ground,
// otherwise it's not needed in regular motion. // otherwise it's not needed in regular motion.
if (!p_collide_separation_ray && (body_shape->get_type() == PhysicsServer3D::SHAPE_SEPARATION_RAY)) { if (!p_parameters.collide_separation_ray && (body_shape->get_type() == PhysicsServer3D::SHAPE_SEPARATION_RAY)) {
// When slide on slope is on, separation ray shape acts like a regular shape. // When slide on slope is on, separation ray shape acts like a regular shape.
if (!static_cast<SeparationRayShape3DSW *>(body_shape)->get_slide_on_slope()) { if (!static_cast<SeparationRayShape3DSW *>(body_shape)->get_slide_on_slope()) {
continue; continue;
@ -783,7 +783,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse(); Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse();
MotionShape3DSW mshape; MotionShape3DSW mshape;
mshape.shape = body_shape; mshape.shape = body_shape;
mshape.motion = body_shape_xform_inv.basis.xform(p_motion); mshape.motion = body_shape_xform_inv.basis.xform(p_parameters.motion);
bool stuck = false; bool stuck = false;
@ -792,7 +792,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i]; const CollisionObject3DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
@ -821,7 +821,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int k = 0; k < 8; k++) { //steps should be customizable.. for (int k = 0; k < 8; k++) { //steps should be customizable..
real_t fraction = low + (hi - low) * fraction_coeff; real_t fraction = low + (hi - low) * fraction_coeff;
mshape.motion = body_shape_xform_inv.basis.xform(p_motion * fraction); mshape.motion = body_shape_xform_inv.basis.xform(p_parameters.motion * fraction);
Vector3 lA, lB; Vector3 lA, lB;
Vector3 sep = motion_normal; //important optimization for this to work fast enough Vector3 sep = motion_normal; //important optimization for this to work fast enough
@ -883,13 +883,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
//it collided, let's get the rest info in unsafe advance //it collided, let's get the rest info in unsafe advance
Transform3D ugt = body_transform; Transform3D ugt = body_transform;
ugt.origin += p_motion * unsafe; ugt.origin += p_parameters.motion * unsafe;
_RestResultData results[PhysicsServer3D::MotionResult::MAX_COLLISIONS]; _RestResultData results[PhysicsServer3D::MotionResult::MAX_COLLISIONS];
_RestCallbackData rcd; _RestCallbackData rcd;
if (p_max_collisions > 1) { if (p_parameters.max_collisions > 1) {
rcd.max_results = p_max_collisions; rcd.max_results = p_parameters.max_collisions;
rcd.other_results = results; rcd.other_results = results;
} }
@ -907,20 +907,20 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j); Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j);
Shape3DSW *body_shape = p_body->get_shape(j); Shape3DSW *body_shape = p_body->get_shape(j);
body_aabb.position += p_motion * unsafe; body_aabb.position += p_parameters.motion * unsafe;
int amount = _cull_aabb_for_body(p_body, body_aabb); int amount = _cull_aabb_for_body(p_body, body_aabb);
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i]; const CollisionObject3DSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) { if (p_parameters.exclude_bodies.has(col_obj->get_self())) {
continue; continue;
} }
int shape_idx = intersection_query_subindex_results[i]; int shape_idx = intersection_query_subindex_results[i];
rcd.object = col_obj; rcd.object = col_obj;
rcd.shape = shape_idx; rcd.shape = shape_idx;
bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_parameters.margin);
if (!sc) { if (!sc) {
continue; continue;
} }
@ -948,12 +948,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
} }
r_result->travel = safe * p_motion; r_result->travel = safe * p_parameters.motion;
r_result->remainder = p_motion - safe * p_motion; r_result->remainder = p_parameters.motion - safe * p_parameters.motion;
r_result->travel += (body_transform.get_origin() - p_from.get_origin()); r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
r_result->safe_fraction = safe; r_result->collision_safe_fraction = safe;
r_result->unsafe_fraction = unsafe; r_result->collision_unsafe_fraction = unsafe;
r_result->collision_count = rcd.result_count; r_result->collision_count = rcd.result_count;
} }
@ -963,12 +963,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
} }
if (!collided && r_result) { if (!collided && r_result) {
r_result->travel = p_motion; r_result->travel = p_parameters.motion;
r_result->remainder = Vector3(); r_result->remainder = Vector3();
r_result->travel += (body_transform.get_origin() - p_from.get_origin()); r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin());
r_result->safe_fraction = 1.0; r_result->collision_safe_fraction = 1.0;
r_result->unsafe_fraction = 1.0; r_result->collision_unsafe_fraction = 1.0;
} }
return collided; return collided;

View File

@ -207,7 +207,7 @@ public:
void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; }
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, int p_max_collisions = 1, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); bool test_body_motion(Body3DSW *p_body, const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult *r_result);
Space3DSW(); Space3DSW();
~Space3DSW(); ~Space3DSW();

View File

@ -412,6 +412,49 @@ void PhysicsDirectSpaceState2D::_bind_methods() {
/////////////////////////////// ///////////////////////////////
Vector<RID> PhysicsTestMotionParameters2D::get_exclude_bodies() const {
Vector<RID> exclude;
exclude.resize(parameters.exclude_bodies.size());
int body_index = 0;
for (RID body : parameters.exclude_bodies) {
exclude.write[body_index++] = body;
}
return exclude;
}
void PhysicsTestMotionParameters2D::set_exclude_bodies(const Vector<RID> &p_exclude) {
for (RID body : p_exclude) {
parameters.exclude_bodies.insert(body);
}
}
void PhysicsTestMotionParameters2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters2D::get_from);
ClassDB::bind_method(D_METHOD("set_from"), &PhysicsTestMotionParameters2D::set_from);
ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionParameters2D::get_motion);
ClassDB::bind_method(D_METHOD("set_motion"), &PhysicsTestMotionParameters2D::set_motion);
ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsTestMotionParameters2D::get_margin);
ClassDB::bind_method(D_METHOD("set_margin"), &PhysicsTestMotionParameters2D::set_margin);
ClassDB::bind_method(D_METHOD("is_collide_separation_ray_enabled"), &PhysicsTestMotionParameters2D::is_collide_separation_ray_enabled);
ClassDB::bind_method(D_METHOD("set_collide_separation_ray_enabled"), &PhysicsTestMotionParameters2D::set_collide_separation_ray_enabled);
ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters2D::get_exclude_bodies);
ClassDB::bind_method(D_METHOD("set_exclude_bodies"), &PhysicsTestMotionParameters2D::set_exclude_bodies);
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "from"), "set_from", "get_from");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies"), "set_exclude_bodies", "get_exclude_bodies");
}
///////////////////////////////
Vector2 PhysicsTestMotionResult2D::get_travel() const { Vector2 PhysicsTestMotionResult2D::get_travel() const {
return result.travel; return result.travel;
} }
@ -448,6 +491,10 @@ int PhysicsTestMotionResult2D::get_collider_shape() const {
return result.collider_shape; return result.collider_shape;
} }
int PhysicsTestMotionResult2D::get_collision_local_shape() const {
return result.collision_local_shape;
}
real_t PhysicsTestMotionResult2D::get_collision_depth() const { real_t PhysicsTestMotionResult2D::get_collision_depth() const {
return result.collision_depth; return result.collision_depth;
} }
@ -470,36 +517,23 @@ void PhysicsTestMotionResult2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult2D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult2D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult2D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_local_shape"), &PhysicsTestMotionResult2D::get_collision_local_shape);
ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult2D::get_collision_depth); ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult2D::get_collision_depth);
ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id");
ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_collision_depth");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_safe_fraction"), "", "get_collision_safe_fraction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_unsafe_fraction"), "", "get_collision_unsafe_fraction");
} }
/////////////////////////////////////// ///////////////////////////////////////
bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result, bool p_collide_separation_ray, const Vector<RID> &p_exclude) { bool PhysicsServer2D::_body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters2D> &p_parameters, const Ref<PhysicsTestMotionResult2D> &p_result) {
MotionResult *r = nullptr; ERR_FAIL_COND_V(!p_parameters.is_valid(), false);
MotionResult *result_ptr = nullptr;
if (p_result.is_valid()) { if (p_result.is_valid()) {
r = p_result->get_result_ptr(); result_ptr = p_result->get_result_ptr();
} }
Set<RID> exclude;
for (int i = 0; i < p_exclude.size(); i++) { return body_test_motion(p_body, p_parameters->get_parameters(), result_ptr);
exclude.insert(p_exclude[i]);
}
return body_test_motion(p_body, p_from, p_motion, p_margin, r, p_collide_separation_ray, exclude);
} }
void PhysicsServer2D::_bind_methods() { void PhysicsServer2D::_bind_methods() {
@ -626,7 +660,7 @@ void PhysicsServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "collide_separation_ray", "exclude"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()), DEFVAL(false), DEFVAL(Array())); ClassDB::bind_method(D_METHOD("body_test_motion", "body", "parameters", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer2D::body_get_direct_state); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer2D::body_get_direct_state);

View File

@ -198,6 +198,7 @@ public:
PhysicsDirectSpaceState2D(); PhysicsDirectSpaceState2D();
}; };
class PhysicsTestMotionParameters2D;
class PhysicsTestMotionResult2D; class PhysicsTestMotionResult2D;
class PhysicsServer2D : public Object { class PhysicsServer2D : public Object {
@ -205,7 +206,7 @@ class PhysicsServer2D : public Object {
static PhysicsServer2D *singleton; static PhysicsServer2D *singleton;
virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>(), bool p_collide_separation_ray = false, const Vector<RID> &p_exclude = Vector<RID>()); virtual bool _body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters2D> &p_parameters, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>());
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -465,6 +466,21 @@ public:
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0; virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0;
struct MotionParameters {
Transform2D from;
Vector2 motion;
real_t margin = 0.08;
bool collide_separation_ray = false;
Set<RID> exclude_bodies;
MotionParameters() {}
MotionParameters(const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08) :
from(p_from),
motion(p_motion),
margin(p_margin) {}
};
struct MotionResult { struct MotionResult {
Vector2 travel; Vector2 travel;
Vector2 remainder; Vector2 remainder;
@ -485,18 +501,7 @@ public:
} }
}; };
virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) = 0; virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) = 0;
struct SeparationResult {
real_t collision_depth;
Vector2 collision_point;
Vector2 collision_normal;
Vector2 collider_velocity;
int collision_local_shape;
ObjectID collider_id;
RID collider;
int collider_shape;
};
/* JOINT API */ /* JOINT API */
@ -579,11 +584,37 @@ public:
~PhysicsServer2D(); ~PhysicsServer2D();
}; };
class PhysicsTestMotionParameters2D : public RefCounted {
GDCLASS(PhysicsTestMotionParameters2D, RefCounted);
PhysicsServer2D::MotionParameters parameters;
protected:
static void _bind_methods();
public:
const PhysicsServer2D::MotionParameters &get_parameters() const { return parameters; }
const Transform2D &get_from() const { return parameters.from; }
void set_from(const Transform2D &p_from) { parameters.from = p_from; }
const Vector2 &get_motion() const { return parameters.motion; }
void set_motion(const Vector2 &p_motion) { parameters.motion = p_motion; }
real_t get_margin() const { return parameters.margin; }
void set_margin(real_t p_margin) { parameters.margin = p_margin; }
bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; }
void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; }
Vector<RID> get_exclude_bodies() const;
void set_exclude_bodies(const Vector<RID> &p_exclude);
};
class PhysicsTestMotionResult2D : public RefCounted { class PhysicsTestMotionResult2D : public RefCounted {
GDCLASS(PhysicsTestMotionResult2D, RefCounted); GDCLASS(PhysicsTestMotionResult2D, RefCounted);
PhysicsServer2D::MotionResult result; PhysicsServer2D::MotionResult result;
friend class PhysicsServer2D;
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -601,6 +632,7 @@ public:
RID get_collider_rid() const; RID get_collider_rid() const;
Object *get_collider() const; Object *get_collider() const;
int get_collider_shape() const; int get_collider_shape() const;
int get_collision_local_shape() const;
real_t get_collision_depth() const; real_t get_collision_depth() const;
real_t get_collision_safe_fraction() const; real_t get_collision_safe_fraction() const;
real_t get_collision_unsafe_fraction() const; real_t get_collision_unsafe_fraction() const;

View File

@ -362,6 +362,53 @@ void PhysicsDirectSpaceState3D::_bind_methods() {
/////////////////////////////// ///////////////////////////////
Vector<RID> PhysicsTestMotionParameters3D::get_exclude_bodies() const {
Vector<RID> exclude;
exclude.resize(parameters.exclude_bodies.size());
int body_index = 0;
for (RID body : parameters.exclude_bodies) {
exclude.write[body_index++] = body;
}
return exclude;
}
void PhysicsTestMotionParameters3D::set_exclude_bodies(const Vector<RID> &p_exclude) {
for (RID body : p_exclude) {
parameters.exclude_bodies.insert(body);
}
}
void PhysicsTestMotionParameters3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters3D::get_from);
ClassDB::bind_method(D_METHOD("set_from"), &PhysicsTestMotionParameters3D::set_from);
ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionParameters3D::get_motion);
ClassDB::bind_method(D_METHOD("set_motion"), &PhysicsTestMotionParameters3D::set_motion);
ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsTestMotionParameters3D::get_margin);
ClassDB::bind_method(D_METHOD("set_margin"), &PhysicsTestMotionParameters3D::set_margin);
ClassDB::bind_method(D_METHOD("get_max_collisions"), &PhysicsTestMotionParameters3D::get_max_collisions);
ClassDB::bind_method(D_METHOD("set_max_collisions"), &PhysicsTestMotionParameters3D::set_max_collisions);
ClassDB::bind_method(D_METHOD("is_collide_separation_ray_enabled"), &PhysicsTestMotionParameters3D::is_collide_separation_ray_enabled);
ClassDB::bind_method(D_METHOD("set_collide_separation_ray_enabled"), &PhysicsTestMotionParameters3D::set_collide_separation_ray_enabled);
ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters3D::get_exclude_bodies);
ClassDB::bind_method(D_METHOD("set_exclude_bodies"), &PhysicsTestMotionParameters3D::set_exclude_bodies);
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "from"), "set_from", "get_from");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "set_motion", "get_motion");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_collisions"), "set_max_collisions", "get_max_collisions");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies"), "set_exclude_bodies", "get_exclude_bodies");
}
///////////////////////////////
Vector3 PhysicsTestMotionResult3D::get_travel() const { Vector3 PhysicsTestMotionResult3D::get_travel() const {
return result.travel; return result.travel;
} }
@ -370,12 +417,12 @@ Vector3 PhysicsTestMotionResult3D::get_remainder() const {
return result.remainder; return result.remainder;
} }
real_t PhysicsTestMotionResult3D::get_safe_fraction() const { real_t PhysicsTestMotionResult3D::get_collision_safe_fraction() const {
return result.safe_fraction; return result.collision_safe_fraction;
} }
real_t PhysicsTestMotionResult3D::get_unsafe_fraction() const { real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const {
return result.unsafe_fraction; return result.collision_unsafe_fraction;
} }
int PhysicsTestMotionResult3D::get_collision_count() const { int PhysicsTestMotionResult3D::get_collision_count() const {
@ -417,48 +464,21 @@ int PhysicsTestMotionResult3D::get_collider_shape(int p_collision_index) const {
return result.collisions[p_collision_index].collider_shape; return result.collisions[p_collision_index].collider_shape;
} }
int PhysicsTestMotionResult3D::get_collision_local_shape(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0);
return result.collisions[p_collision_index].local_shape;
}
real_t PhysicsTestMotionResult3D::get_collision_depth(int p_collision_index) const { real_t PhysicsTestMotionResult3D::get_collision_depth(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0); ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0);
return result.collisions[p_collision_index].depth; return result.collisions[p_collision_index].depth;
} }
Vector3 PhysicsTestMotionResult3D::get_best_collision_point() const {
return result.collision_count ? get_collision_point() : Vector3();
}
Vector3 PhysicsTestMotionResult3D::get_best_collision_normal() const {
return result.collision_count ? get_collision_normal() : Vector3();
}
Vector3 PhysicsTestMotionResult3D::get_best_collider_velocity() const {
return result.collision_count ? get_collider_velocity() : Vector3();
}
ObjectID PhysicsTestMotionResult3D::get_best_collider_id() const {
return result.collision_count ? get_collider_id() : ObjectID();
}
RID PhysicsTestMotionResult3D::get_best_collider_rid() const {
return result.collision_count ? get_collider_rid() : RID();
}
Object *PhysicsTestMotionResult3D::get_best_collider() const {
return result.collision_count ? get_collider() : nullptr;
}
int PhysicsTestMotionResult3D::get_best_collider_shape() const {
return result.collision_count ? get_collider_shape() : 0;
}
real_t PhysicsTestMotionResult3D::get_best_collision_depth() const {
return result.collision_count ? get_collision_depth() : 0.0;
}
void PhysicsTestMotionResult3D::_bind_methods() { void PhysicsTestMotionResult3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult3D::get_travel); ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult3D::get_travel);
ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult3D::get_remainder); ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult3D::get_remainder);
ClassDB::bind_method(D_METHOD("get_safe_fraction"), &PhysicsTestMotionResult3D::get_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_unsafe_fraction"), &PhysicsTestMotionResult3D::get_unsafe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction);
ClassDB::bind_method(D_METHOD("get_collision_count"), &PhysicsTestMotionResult3D::get_collision_count); ClassDB::bind_method(D_METHOD("get_collision_count"), &PhysicsTestMotionResult3D::get_collision_count);
ClassDB::bind_method(D_METHOD("get_collision_point", "collision_index"), &PhysicsTestMotionResult3D::get_collision_point, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collision_point", "collision_index"), &PhysicsTestMotionResult3D::get_collision_point, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collision_normal", "collision_index"), &PhysicsTestMotionResult3D::get_collision_normal, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collision_normal", "collision_index"), &PhysicsTestMotionResult3D::get_collision_normal, DEFVAL(0));
@ -467,44 +487,21 @@ void PhysicsTestMotionResult3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &PhysicsTestMotionResult3D::get_collider_rid, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &PhysicsTestMotionResult3D::get_collider_rid, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &PhysicsTestMotionResult3D::get_collider, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &PhysicsTestMotionResult3D::get_collider, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collider_shape, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collider_shape, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collision_local_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collision_local_shape, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collision_depth", "collision_index"), &PhysicsTestMotionResult3D::get_collision_depth, DEFVAL(0)); ClassDB::bind_method(D_METHOD("get_collision_depth", "collision_index"), &PhysicsTestMotionResult3D::get_collision_depth, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_best_collision_point"), &PhysicsTestMotionResult3D::get_best_collision_point);
ClassDB::bind_method(D_METHOD("get_best_collision_normal"), &PhysicsTestMotionResult3D::get_best_collision_normal);
ClassDB::bind_method(D_METHOD("get_best_collider_velocity"), &PhysicsTestMotionResult3D::get_best_collider_velocity);
ClassDB::bind_method(D_METHOD("get_best_collider_id"), &PhysicsTestMotionResult3D::get_best_collider_id);
ClassDB::bind_method(D_METHOD("get_best_collider_rid"), &PhysicsTestMotionResult3D::get_best_collider_rid);
ClassDB::bind_method(D_METHOD("get_best_collider"), &PhysicsTestMotionResult3D::get_best_collider);
ClassDB::bind_method(D_METHOD("get_best_collider_shape"), &PhysicsTestMotionResult3D::get_best_collider_shape);
ClassDB::bind_method(D_METHOD("get_best_collision_depth"), &PhysicsTestMotionResult3D::get_best_collision_depth);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "safe_fraction"), "", "get_safe_fraction");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unsafe_fraction"), "", "get_unsafe_fraction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_count"), "", "get_collision_count");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_point"), "", "get_best_collision_point");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_best_collision_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_best_collider_velocity");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_best_collider_id");
ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_best_collider_rid");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_best_collider");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_best_collider_shape");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_best_collision_depth");
} }
/////////////////////////////////////// ///////////////////////////////////////
bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, bool p_collide_separation_ray, const Vector<RID> &p_exclude, int p_max_collisions) { bool PhysicsServer3D::_body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters3D> &p_parameters, const Ref<PhysicsTestMotionResult3D> &p_result) {
MotionResult *r = nullptr; ERR_FAIL_COND_V(!p_parameters.is_valid(), false);
MotionResult *result_ptr = nullptr;
if (p_result.is_valid()) { if (p_result.is_valid()) {
r = p_result->get_result_ptr(); result_ptr = p_result->get_result_ptr();
} }
Set<RID> exclude;
for (int i = 0; i < p_exclude.size(); i++) { return body_test_motion(p_body, p_parameters->get_parameters(), result_ptr);
exclude.insert(p_exclude[i]);
}
return body_test_motion(p_body, p_from, p_motion, p_margin, r, p_max_collisions, p_collide_separation_ray, exclude);
} }
RID PhysicsServer3D::shape_create(ShapeType p_shape) { RID PhysicsServer3D::shape_create(ShapeType p_shape) {
@ -662,7 +659,7 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable);
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "collide_separation_ray", "exclude", "max_collisions"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(false), DEFVAL(Array()), DEFVAL(1)); ClassDB::bind_method(D_METHOD("body_test_motion", "body", "parameters", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);

View File

@ -203,6 +203,7 @@ public:
virtual ~RenderingServerHandler() {} virtual ~RenderingServerHandler() {}
}; };
class PhysicsTestMotionParameters3D;
class PhysicsTestMotionResult3D; class PhysicsTestMotionResult3D;
class PhysicsServer3D : public Object { class PhysicsServer3D : public Object {
@ -210,7 +211,7 @@ class PhysicsServer3D : public Object {
static PhysicsServer3D *singleton; static PhysicsServer3D *singleton;
virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_collide_separation_ray = false, const Vector<RID> &p_exclude = Vector<RID>(), int p_max_collisions = 1); virtual bool _body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters3D> &p_parameters, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>());
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -483,6 +484,22 @@ public:
// this function only works on physics process, errors and returns null otherwise // this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0; virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0;
struct MotionParameters {
Transform3D from;
Vector3 motion;
real_t margin = 0.001;
int max_collisions = 1;
bool collide_separation_ray = false;
Set<RID> exclude_bodies;
MotionParameters() {}
MotionParameters(const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001) :
from(p_from),
motion(p_motion),
margin(p_margin) {}
};
struct MotionCollision { struct MotionCollision {
Vector3 position; Vector3 position;
Vector3 normal; Vector3 normal;
@ -501,15 +518,15 @@ public:
struct MotionResult { struct MotionResult {
Vector3 travel; Vector3 travel;
Vector3 remainder; Vector3 remainder;
real_t safe_fraction = 0.0; real_t collision_safe_fraction = 0.0;
real_t unsafe_fraction = 0.0; real_t collision_unsafe_fraction = 0.0;
static const int MAX_COLLISIONS = 32; static const int MAX_COLLISIONS = 32;
MotionCollision collisions[MAX_COLLISIONS]; MotionCollision collisions[MAX_COLLISIONS];
int collision_count = 0; int collision_count = 0;
}; };
virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, int p_max_collisions = 1, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) = 0; virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) = 0;
/* SOFT BODY */ /* SOFT BODY */
@ -760,11 +777,40 @@ public:
~PhysicsServer3D(); ~PhysicsServer3D();
}; };
class PhysicsTestMotionParameters3D : public RefCounted {
GDCLASS(PhysicsTestMotionParameters3D, RefCounted);
PhysicsServer3D::MotionParameters parameters;
protected:
static void _bind_methods();
public:
const PhysicsServer3D::MotionParameters &get_parameters() const { return parameters; }
const Transform3D &get_from() const { return parameters.from; }
void set_from(const Transform3D &p_from) { parameters.from = p_from; }
const Vector3 &get_motion() const { return parameters.motion; }
void set_motion(const Vector3 &p_motion) { parameters.motion = p_motion; }
real_t get_margin() const { return parameters.margin; }
void set_margin(real_t p_margin) { parameters.margin = p_margin; }
int get_max_collisions() const { return parameters.max_collisions; }
void set_max_collisions(int p_max_collisions) { parameters.max_collisions = p_max_collisions; }
bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; }
void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; }
Vector<RID> get_exclude_bodies() const;
void set_exclude_bodies(const Vector<RID> &p_exclude);
};
class PhysicsTestMotionResult3D : public RefCounted { class PhysicsTestMotionResult3D : public RefCounted {
GDCLASS(PhysicsTestMotionResult3D, RefCounted); GDCLASS(PhysicsTestMotionResult3D, RefCounted);
PhysicsServer3D::MotionResult result; PhysicsServer3D::MotionResult result;
friend class PhysicsServer3D;
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -774,8 +820,8 @@ public:
Vector3 get_travel() const; Vector3 get_travel() const;
Vector3 get_remainder() const; Vector3 get_remainder() const;
real_t get_safe_fraction() const; real_t get_collision_safe_fraction() const;
real_t get_unsafe_fraction() const; real_t get_collision_unsafe_fraction() const;
int get_collision_count() const; int get_collision_count() const;
@ -786,16 +832,8 @@ public:
RID get_collider_rid(int p_collision_index = 0) const; RID get_collider_rid(int p_collision_index = 0) const;
Object *get_collider(int p_collision_index = 0) const; Object *get_collider(int p_collision_index = 0) const;
int get_collider_shape(int p_collision_index = 0) const; int get_collider_shape(int p_collision_index = 0) const;
int get_collision_local_shape(int p_collision_index = 0) const;
real_t get_collision_depth(int p_collision_index = 0) const; real_t get_collision_depth(int p_collision_index = 0) const;
Vector3 get_best_collision_point() const;
Vector3 get_best_collision_normal() const;
Vector3 get_best_collider_velocity() const;
ObjectID get_best_collider_id() const;
RID get_best_collider_rid() const;
Object *get_best_collider() const;
int get_best_collider_shape() const;
real_t get_best_collision_depth() const;
}; };
typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)(); typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)();

View File

@ -208,12 +208,14 @@ void register_server_types() {
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2D);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2D);
GDREGISTER_CLASS(PhysicsTestMotionParameters2D);
GDREGISTER_CLASS(PhysicsTestMotionResult2D); GDREGISTER_CLASS(PhysicsTestMotionResult2D);
GDREGISTER_CLASS(PhysicsShapeQueryParameters2D); GDREGISTER_CLASS(PhysicsShapeQueryParameters2D);
GDREGISTER_CLASS(PhysicsShapeQueryParameters3D); GDREGISTER_CLASS(PhysicsShapeQueryParameters3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3D);
GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState3D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState3D);
GDREGISTER_CLASS(PhysicsTestMotionParameters3D);
GDREGISTER_CLASS(PhysicsTestMotionResult3D); GDREGISTER_CLASS(PhysicsTestMotionResult3D);
// Physics 2D // Physics 2D