Merge pull request #52889 from fabriceci/multiple_collision-support-fab

Port 2D improvements to move and slide 3D (with extras)
This commit is contained in:
Camille Mohr-Daurat 2021-09-21 17:41:33 -07:00 committed by GitHub
commit c1e6c2c49a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1305 additions and 386 deletions

View File

@ -170,7 +170,7 @@
Apply when notions of walls, ceiling and floor are relevant. In this mode the body motion will react to slopes (acceleration/slowdown). This mode is suitable for sided games like platformers.
</constant>
<constant name="MOTION_MODE_FREE" value="1" enum="MotionMode">
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will be always constant. This mode is suitable for top-down games.
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for top-down games.
</constant>
</constants>
</class>

View File

@ -29,6 +29,12 @@
Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
</description>
</method>
<method name="get_last_motion" qualifiers="const">
<return type="Vector3" />
<description>
Returns the last motion applied to the [CharacterBody3D] during the last call to [method move_and_slide]. The movement can be split if needed into multiple motion, this method return the last one, it's useful to retrieve the current direction of the movement.
</description>
</method>
<method name="get_last_slide_collision">
<return type="KinematicCollision3D" />
<description>
@ -41,6 +47,18 @@
Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
</description>
</method>
<method name="get_position_delta" qualifiers="const">
<return type="Vector3" />
<description>
Returns the travel (position delta) that occurred during the last call to [method move_and_slide].
</description>
</method>
<method name="get_real_velocity" qualifiers="const">
<return type="Vector3" />
<description>
Returns the current real velocity since the last call to [method move_and_slide]. For example, when you climb a slope, you will move diagonally even though the velocity is horizontal. This method returns the diagonal movement, as opposed to [member linear_velocity] which returns the requested velocity.
</description>
</method>
<method name="get_slide_collision">
<return type="KinematicCollision3D" />
<argument index="0" name="slide_idx" type="int" />
@ -54,6 +72,12 @@
Returns the number of times the body collided and changed direction during the last call to [method move_and_slide].
</description>
</method>
<method name="get_wall_normal" qualifiers="const">
<return type="Vector3" />
<description>
Returns the surface normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
</description>
</method>
<method name="is_on_ceiling" qualifiers="const">
<return type="bool" />
<description>
@ -108,24 +132,66 @@
A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors.
A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies.
</member>
<member name="floor_block_on_wall" type="bool" setter="set_floor_block_on_wall_enabled" getter="is_floor_block_on_wall_enabled" default="true">
If [code]true[/code], the body will be able to move on the floor only. This option avoids to be able to walk on walls, it will however allow to slide down along them.
</member>
<member name="floor_constant_speed" type="bool" setter="set_floor_constant_speed_enabled" getter="is_floor_constant_speed_enabled" default="false">
If [code]false[/code] (by default), the body will move faster on downward slopes and slower on upward slopes.
If [code]true[/code], the body will always move at the same speed on the ground no matter the slope. Note that you need to use [member floor_snap_length] to stick along a downward slope at constant speed.
</member>
<member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398">
Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees.
</member>
<member name="floor_snap_length" type="float" setter="set_floor_snap_length" getter="get_floor_snap_length" default="0.1">
Sets a snapping distance. When set to a value different from [code]0.0[/code], the body is kept attached to slopes when calling [method move_and_slide]. The snapping vector is determined by the given distance along the opposite direction of the [member up_direction].
As long as the snapping vector is in contact with the ground and the body moves against `up_direction`, the body will remain attached to the surface. Snapping is not applied if the body moves along `up_direction`, so it will be able to detach from the ground when jumping.
</member>
<member name="floor_stop_on_slope" type="bool" setter="set_floor_stop_on_slope_enabled" getter="is_floor_stop_on_slope_enabled" default="false">
If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still.
</member>
<member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)">
Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide].
</member>
<member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4">
<member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="6">
Maximum number of times the body can change direction before it stops when calling [method move_and_slide].
</member>
<member name="snap" type="Vector3" setter="set_snap" getter="get_snap" default="Vector3(0, 0, 0)">
When set to a value different from [code]Vector3(0, 0, 0)[/code], the body is kept attached to slopes when calling [method move_and_slide].
As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code]Vector3(0, 0, 0)[/code].
<member name="motion_mode" type="int" setter="set_motion_mode" getter="get_motion_mode" enum="CharacterBody3D.MotionMode" default="0">
Sets the motion mode which defines the behaviour of [method move_and_slide]. See [enum MotionMode] constants for available modes.
</member>
<member name="moving_platform_apply_velocity_on_leave" type="int" setter="set_moving_platform_apply_velocity_on_leave" getter="get_moving_platform_apply_velocity_on_leave" enum="CharacterBody3D.MovingPlatformApplyVelocityOnLeave" default="0">
Sets the behaviour to apply when you leave a moving platform. By default, to be physically accurate, when you leave the last platform velocity is applied. See [enum MovingPlatformApplyVelocityOnLeave] constants for available behaviour.
</member>
<member name="moving_platform_floor_layers" type="int" setter="set_moving_platform_floor_layers" getter="get_moving_platform_floor_layers" default="4294967295">
Collision layers that will be included for detecting floor bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all floor bodies are detected and propagate their velocity.
</member>
<member name="moving_platform_wall_layers" type="int" setter="set_moving_platform_wall_layers" getter="get_moving_platform_wall_layers" default="0">
Collision layers that will be included for detecting wall bodies that will act as moving platforms to be followed by the [CharacterBody2D]. By default, all wall bodies are ignored.
</member>
<member name="slide_on_ceiling" type="bool" setter="set_slide_on_ceiling_enabled" getter="is_slide_on_ceiling_enabled" default="true">
If [code]true[/code], during a jump against the ceiling, the body will slide, if [code]false[/code] it will be stopped and will fall vertically.
</member>
<member name="up_direction" type="Vector3" setter="set_up_direction" getter="get_up_direction" default="Vector3(0, 1, 0)">
Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. If set to [code]Vector3(0, 0, 0)[/code], everything is considered a wall. This is useful for topdown games.
</member>
<member name="wall_min_slide_angle" type="float" setter="set_wall_min_slide_angle" getter="get_wall_min_slide_angle" default="0.261799">
Minimum angle (in radians) where the body is allowed to slide when it encounters a slope. The default value equals 15 degrees. In [code]MOTION_MODE_GROUNDED[/code], it works only when [member floor_block_on_wall] is [code]true[/code].
</member>
</members>
<constants>
<constant name="MOTION_MODE_GROUNDED" value="0" enum="MotionMode">
Apply when notions of walls, ceiling and floor are relevant. In this mode the body motion will react to slopes (acceleration/slowdown). This mode is suitable for grounded games like platformers.
</constant>
<constant name="MOTION_MODE_FREE" value="1" enum="MotionMode">
Apply when there is no notion of floor or ceiling. All collisions will be reported as [code]on_wall[/code]. In this mode, when you slide, the speed will always be constant. This mode is suitable for games without ground like space games.
</constant>
<constant name="PLATFORM_VEL_ON_LEAVE_ALWAYS" value="0" enum="MovingPlatformApplyVelocityOnLeave">
Add the last platform velocity to the [member linear_velocity] when you leave a moving platform.
</constant>
<constant name="PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY" value="1" enum="MovingPlatformApplyVelocityOnLeave">
Add the last platform velocity to the [member linear_velocity] when you leave a moving platform, but any downward motion is ignored. It's useful to keep full jump height even when the platform is moving down.
</constant>
<constant name="PLATFORM_VEL_ON_LEAVE_NEVER" value="2" enum="MovingPlatformApplyVelocityOnLeave">
Do nothing when leaving a platform.
</constant>
</constants>
</class>

View File

@ -12,41 +12,114 @@
<methods>
<method name="get_angle" qualifiers="const">
<return type="float" />
<argument index="0" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
<argument index="0" name="collision_index" type="int" default="0" />
<argument index="1" name="up_direction" type="Vector3" default="Vector3(0, 1, 0)" />
<description>
The collision angle according to [code]up_direction[/code], which is [code]Vector3.UP[/code] by default. This value is always positive.
</description>
</method>
<method name="get_collider" qualifiers="const">
<return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider by index (the latest by default).
</description>
</method>
<method name="get_collider_id" qualifiers="const">
<return type="int" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider ID by index (the latest by default).
</description>
</method>
<method name="get_collider_metadata" qualifiers="const">
<return type="Variant" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider metadata by index (the latest by default).
</description>
</method>
<method name="get_collider_rid" qualifiers="const">
<return type="RID" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider RID by index (the latest by default).
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider shape by index (the latest by default).
</description>
</method>
<method name="get_collider_shape_index" qualifiers="const">
<return type="int" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider shape index by index (the latest by default).
</description>
</method>
<method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider velocity by index (the latest by default).
</description>
</method>
<method name="get_local_shape" qualifiers="const">
<return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider velocity by index (the latest by default).
</description>
</method>
<method name="get_normal" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider normal by index (the latest by default).
</description>
</method>
<method name="get_position" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
Returns the collider collision point by index (the latest by default).
</description>
</method>
</methods>
<members>
<member name="collider" type="Object" setter="" getter="get_collider">
<member name="collider" type="Object" setter="" getter="get_best_collider">
The colliding body.
</member>
<member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
<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_metadata" type="Variant" setter="" getter="get_collider_metadata">
<member name="collider_metadata" type="Variant" setter="" getter="get_best_collider_metadata">
The colliding body's metadata. See [Object].
</member>
<member name="collider_rid" type="RID" setter="" getter="get_collider_rid">
<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_collider_shape">
<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_collider_shape_index" default="0">
<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_collider_velocity" default="Vector3(0, 0, 0)">
<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="local_shape" type="Object" setter="" getter="get_local_shape">
<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_normal" default="Vector3(0, 0, 0)">
<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_position" default="Vector3(0, 0, 0)">
<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)">

View File

@ -35,10 +35,12 @@
<argument index="0" name="rel_vec" type="Vector3" />
<argument index="1" name="test_only" type="bool" default="false" />
<argument index="2" name="safe_margin" type="float" default="0.001" />
<argument index="3" name="max_collisions" type="int" default="1" />
<description>
Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision.
If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given.
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
[code]max_collisions[/code] allows to retrieve more than one collision result.
</description>
</method>
<method name="remove_collision_exception_with">
@ -62,10 +64,12 @@
<argument index="1" name="rel_vec" type="Vector3" />
<argument index="2" name="collision" type="KinematicCollision3D" default="null" />
<argument index="3" name="safe_margin" type="float" default="0.001" />
<argument index="4" name="max_collisions" type="int" default="1" />
<description>
Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur.
[code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one).
[code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details).
[code]max_collisions[/code] allows to retrieve more than one collision result.
</description>
</method>
</methods>

View File

@ -583,6 +583,7 @@
<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>
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.
</description>

View File

@ -6,30 +6,82 @@
</description>
<tutorials>
</tutorials>
<methods>
<method name="get_collider" qualifiers="const">
<return type="Object" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collider_id" qualifiers="const">
<return type="int" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collider_rid" qualifiers="const">
<return type="RID" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collider_shape" qualifiers="const">
<return type="int" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collider_velocity" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collision_depth" qualifiers="const">
<return type="float" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collision_normal" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
<method name="get_collision_point" qualifiers="const">
<return type="Vector3" />
<argument index="0" name="collision_index" type="int" default="0" />
<description>
</description>
</method>
</methods>
<members>
<member name="collider" type="Object" setter="" getter="get_collider">
<member name="collider" type="Object" setter="" getter="get_best_collider">
</member>
<member name="collider_id" type="int" setter="" getter="get_collider_id" default="0">
<member name="collider_id" type="int" setter="" getter="get_best_collider_id" default="0">
</member>
<member name="collider_rid" type="RID" setter="" getter="get_collider_rid">
<member name="collider_rid" type="RID" setter="" getter="get_best_collider_rid">
</member>
<member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0">
<member name="collider_shape" type="int" setter="" getter="get_best_collider_shape" default="0">
</member>
<member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3(0, 0, 0)">
<member name="collider_velocity" type="Vector3" setter="" getter="get_best_collider_velocity" default="Vector3(0, 0, 0)">
</member>
<member name="collision_depth" type="float" setter="" getter="get_collision_depth" default="0.0">
<member name="collision_count" type="int" setter="" getter="get_collision_count" default="0">
</member>
<member name="collision_normal" type="Vector3" setter="" getter="get_collision_normal" default="Vector3(0, 0, 0)">
<member name="collision_depth" type="float" setter="" getter="get_best_collision_depth" default="0.0">
</member>
<member name="collision_point" type="Vector3" setter="" getter="get_collision_point" default="Vector3(0, 0, 0)">
<member name="collision_normal" type="Vector3" setter="" getter="get_best_collision_normal" default="Vector3(0, 0, 0)">
</member>
<member name="collision_safe_fraction" type="float" setter="" getter="get_collision_safe_fraction" default="0.0">
</member>
<member name="collision_unsafe_fraction" type="float" setter="" getter="get_collision_unsafe_fraction" default="0.0">
<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>

View File

@ -334,7 +334,7 @@ private:
int max_slides = 4;
int platform_layer;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
float floor_snap_length = 0;
real_t floor_snap_length = 0;
real_t free_mode_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector2 up_direction = Vector2(0.0, -1.0);
uint32_t moving_platform_floor_layers = UINT32_MAX;

File diff suppressed because it is too large Load Diff

View File

@ -50,11 +50,11 @@ protected:
uint16_t locked_axis = 0;
Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001);
Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, int p_max_collisions = 1);
public:
bool move_and_collide(const Vector3 &p_motion, PhysicsServer3D::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 test_move(const Transform3D &p_from, const Vector3 &p_motion, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
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 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);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const;
@ -306,54 +306,16 @@ class KinematicCollision3D;
class CharacterBody3D : public PhysicsBody3D {
GDCLASS(CharacterBody3D, PhysicsBody3D);
private:
real_t margin = 0.001;
bool floor_stop_on_slope = false;
int max_slides = 4;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
Vector3 snap;
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
Vector3 linear_velocity;
Vector3 floor_normal;
Vector3 floor_velocity;
RID on_floor_body;
bool on_floor = false;
bool on_ceiling = false;
bool on_wall = false;
Vector<PhysicsServer3D::MotionResult> motion_results;
Vector<Ref<KinematicCollision3D>> slide_colliders;
Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
Ref<KinematicCollision3D> _get_last_slide_collision();
void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result);
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool is_floor_stop_on_slope_enabled() const;
void set_floor_stop_on_slope_enabled(bool p_enabled);
int get_max_slides() const;
void set_max_slides(int p_max_slides);
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
const Vector3 &get_snap() const;
void set_snap(const Vector3 &p_snap);
const Vector3 &get_up_direction() const;
void set_up_direction(const Vector3 &p_up_direction);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
enum MotionMode {
MOTION_MODE_GROUNDED,
MOTION_MODE_FREE,
};
enum MovingPlatformApplyVelocityOnLeave {
PLATFORM_VEL_ON_LEAVE_ALWAYS,
PLATFORM_VEL_ON_LEAVE_UPWARD_ONLY,
PLATFORM_VEL_ON_LEAVE_NEVER,
};
bool move_and_slide();
virtual Vector3 get_linear_velocity() const override;
@ -365,7 +327,11 @@ public:
bool is_on_wall_only() const;
bool is_on_ceiling() const;
bool is_on_ceiling_only() const;
Vector3 get_last_motion() const;
Vector3 get_position_delta() const;
Vector3 get_floor_normal() const;
Vector3 get_wall_normal() const;
Vector3 get_real_velocity() const;
real_t get_floor_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Vector3 get_platform_velocity() const;
@ -374,8 +340,114 @@ public:
CharacterBody3D();
~CharacterBody3D();
private:
real_t margin = 0.001;
MotionMode motion_mode = MOTION_MODE_GROUNDED;
MovingPlatformApplyVelocityOnLeave moving_platform_apply_velocity_on_leave = PLATFORM_VEL_ON_LEAVE_ALWAYS;
union CollisionState {
uint32_t state = 0;
struct {
bool floor;
bool wall;
bool ceiling;
};
CollisionState() {
}
CollisionState(bool p_floor, bool p_wall, bool p_ceiling) {
floor = p_floor;
wall = p_wall;
ceiling = p_ceiling;
}
};
CollisionState collision_state;
bool floor_stop_on_slope = false;
bool floor_constant_speed = false;
bool floor_block_on_wall = true;
bool slide_on_ceiling = true;
int max_slides = 6;
int platform_layer;
RID platform_rid;
uint32_t moving_platform_floor_layers = UINT32_MAX;
uint32_t moving_platform_wall_layers = 0;
real_t floor_snap_length = 0.1;
real_t floor_max_angle = Math::deg2rad((real_t)45.0);
real_t wall_min_slide_angle = Math::deg2rad((real_t)15.0);
Vector3 up_direction = Vector3(0.0, 1.0, 0.0);
Vector3 linear_velocity;
Vector3 floor_normal;
Vector3 wall_normal;
Vector3 last_motion;
Vector3 platform_velocity;
Vector3 previous_position;
Vector3 real_velocity;
Vector<PhysicsServer3D::MotionResult> motion_results;
Vector<Ref<KinematicCollision3D>> slide_colliders;
void set_safe_margin(real_t p_margin);
real_t get_safe_margin() const;
bool is_floor_stop_on_slope_enabled() const;
void set_floor_stop_on_slope_enabled(bool p_enabled);
bool is_floor_constant_speed_enabled() const;
void set_floor_constant_speed_enabled(bool p_enabled);
bool is_floor_block_on_wall_enabled() const;
void set_floor_block_on_wall_enabled(bool p_enabled);
bool is_slide_on_ceiling_enabled() const;
void set_slide_on_ceiling_enabled(bool p_enabled);
int get_max_slides() const;
void set_max_slides(int p_max_slides);
real_t get_floor_max_angle() const;
void set_floor_max_angle(real_t p_radians);
real_t get_floor_snap_length();
void set_floor_snap_length(real_t p_floor_snap_length);
real_t get_wall_min_slide_angle() const;
void set_wall_min_slide_angle(real_t p_radians);
uint32_t get_moving_platform_floor_layers() const;
void set_moving_platform_floor_layers(const uint32_t p_exclude_layer);
uint32_t get_moving_platform_wall_layers() const;
void set_moving_platform_wall_layers(const uint32_t p_exclude_layer);
void set_motion_mode(MotionMode p_mode);
MotionMode get_motion_mode() const;
void set_moving_platform_apply_velocity_on_leave(MovingPlatformApplyVelocityOnLeave p_on_leave_velocity);
MovingPlatformApplyVelocityOnLeave get_moving_platform_apply_velocity_on_leave() const;
void _move_and_slide_free(double p_delta);
void _move_and_slide_grounded(double p_delta, bool p_was_on_floor);
Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
Ref<KinematicCollision3D> _get_last_slide_collision();
const Vector3 &get_up_direction() const;
bool _on_floor_if_snapped(bool was_on_floor, bool vel_dir_facing_up);
void set_up_direction(const Vector3 &p_up_direction);
void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result, CollisionState &r_state, CollisionState p_apply_state = CollisionState(true, true, true));
void _set_platform_data(const PhysicsServer3D::MotionCollision &p_collision);
void _snap_on_floor(bool was_on_floor, bool vel_dir_facing_up);
protected:
void _notification(int p_what);
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
};
VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
VARIANT_ENUM_CAST(CharacterBody3D::MovingPlatformApplyVelocityOnLeave);
class KinematicCollision3D : public RefCounted {
GDCLASS(KinematicCollision3D, RefCounted);
@ -388,19 +460,31 @@ protected:
static void _bind_methods();
public:
Vector3 get_position() const;
Vector3 get_normal() const;
Vector3 get_travel() const;
Vector3 get_remainder() const;
real_t get_angle(const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Object *get_local_shape() const;
Object *get_collider() const;
ObjectID get_collider_id() const;
RID get_collider_rid() const;
Object *get_collider_shape() const;
int get_collider_shape_index() const;
Vector3 get_collider_velocity() const;
Variant get_collider_metadata() const;
int get_collision_count() const;
Vector3 get_position(int p_collision_index = 0) const;
Vector3 get_normal(int p_collision_index = 0) const;
real_t get_angle(int p_collision_index = 0, const Vector3 &p_up_direction = Vector3(0.0, 1.0, 0.0)) const;
Object *get_local_shape(int p_collision_index = 0) const;
Object *get_collider(int p_collision_index = 0) const;
ObjectID get_collider_id(int p_collision_index = 0) const;
RID get_collider_rid(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;
Vector3 get_collider_velocity(int p_collision_index = 0) const;
Variant get_collider_metadata(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;
Variant get_best_collider_metadata() const;
};
class PhysicalBone3D : public PhysicsBody3D {

View File

@ -868,7 +868,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool 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, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
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) {
Body3DSW *body = body_owner.getornull(p_body);
ERR_FAIL_COND_V(!body, 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();
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_from, p_motion, p_margin, r_result, p_max_collisions, p_collide_separation_ray, p_exclude);
}
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 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, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) 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;
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;

View File

@ -253,9 +253,9 @@ public:
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, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override {
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 {
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_collide_separation_ray, p_exclude);
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);
}
// this function only works on physics process, errors and returns null otherwise

View File

@ -401,17 +401,27 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform3D &
return collided;
}
struct _RestResultData {
const CollisionObject3DSW *object = nullptr;
int local_shape = 0;
int shape = 0;
Vector3 contact;
Vector3 normal;
real_t len = 0.0;
};
struct _RestCallbackData {
const CollisionObject3DSW *object;
const CollisionObject3DSW *best_object;
int local_shape;
int best_local_shape;
int shape;
int best_shape;
Vector3 best_contact;
Vector3 best_normal;
real_t best_len;
real_t min_allowed_depth;
const CollisionObject3DSW *object = nullptr;
int local_shape = 0;
int shape = 0;
real_t min_allowed_depth = 0.0;
_RestResultData best_result;
int max_results = 0;
int result_count = 0;
_RestResultData *other_results = nullptr;
};
static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
@ -422,16 +432,56 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
if (len < rd->min_allowed_depth) {
return;
}
if (len <= rd->best_len) {
bool is_best_result = (len > rd->best_result.len);
if (rd->other_results && rd->result_count > 0) {
// Consider as new result by default.
int prev_result_count = rd->result_count++;
int result_index = 0;
real_t tested_len = is_best_result ? rd->best_result.len : len;
for (; result_index < prev_result_count - 1; ++result_index) {
if (tested_len > rd->other_results[result_index].len) {
// Re-using a previous result.
rd->result_count--;
break;
}
}
if (result_index < rd->max_results - 1) {
_RestResultData &result = rd->other_results[result_index];
if (is_best_result) {
// Keep the previous best result as separate result.
result = rd->best_result;
} else {
// Keep this result as separate result.
result.len = len;
result.contact = p_point_B;
result.normal = contact_rel / len;
result.object = rd->object;
result.shape = rd->shape;
result.local_shape = rd->local_shape;
}
} else {
// Discarding this result.
rd->result_count--;
}
} else if (is_best_result) {
rd->result_count = 1;
}
if (!is_best_result) {
return;
}
rd->best_len = len;
rd->best_contact = p_point_B;
rd->best_normal = contact_rel / len;
rd->best_object = rd->object;
rd->best_shape = rd->shape;
rd->best_local_shape = rd->local_shape;
rd->best_result.len = len;
rd->best_result.contact = p_point_B;
rd->best_result.normal = contact_rel / len;
rd->best_result.object = rd->object;
rd->best_result.shape = rd->shape;
rd->best_result.local_shape = rd->local_shape;
}
bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
@ -444,9 +494,6 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh
int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results);
_RestCallbackData rcd;
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
rcd.min_allowed_depth = space->test_motion_min_contact_depth;
for (int i = 0; i < amount; i++) {
@ -470,18 +517,18 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh
}
}
if (rcd.best_len == 0 || !rcd.best_object) {
if (rcd.best_result.len == 0 || !rcd.best_result.object) {
return false;
}
r_info->collider_id = rcd.best_object->get_instance_id();
r_info->shape = rcd.best_shape;
r_info->normal = rcd.best_normal;
r_info->point = rcd.best_contact;
r_info->rid = rcd.best_object->get_self();
if (rcd.best_object->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
r_info->collider_id = rcd.best_result.object->get_instance_id();
r_info->shape = rcd.best_result.shape;
r_info->normal = rcd.best_result.normal;
r_info->point = rcd.best_result.contact;
r_info->rid = rcd.best_result.object->get_self();
if (rcd.best_result.object->get_type() == CollisionObject3DSW::TYPE_BODY) {
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_result.object);
Vector3 rel_vec = rcd.best_result.contact - (body->get_transform().origin + body->get_center_of_mass());
r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
} else {
@ -569,7 +616,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) {
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, bool p_collide_separation_ray, const Set<RID> &p_exclude) {
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) {
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@ -577,10 +624,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
//this took about a week to get right..
//but is it right? who knows at this point..
ERR_FAIL_INDEX_V(p_max_collisions, PhysicsServer3D::MotionResult::MAX_COLLISIONS, false);
if (r_result) {
r_result->collider_id = ObjectID();
r_result->collider_shape = 0;
*r_result = PhysicsServer3D::MotionResult();
}
AABB body_aabb;
bool shapes_found = false;
@ -599,7 +648,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
if (!shapes_found) {
if (r_result) {
*r_result = PhysicsServer3D::MotionResult();
r_result->travel = p_motion;
}
@ -832,10 +880,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
Transform3D ugt = body_transform;
ugt.origin += p_motion * unsafe;
_RestResultData results[PhysicsServer3D::MotionResult::MAX_COLLISIONS];
_RestCallbackData rcd;
rcd.best_len = 0;
rcd.best_object = nullptr;
rcd.best_shape = 0;
if (p_max_collisions > 1) {
rcd.max_results = p_max_collisions;
rcd.other_results = results;
}
// Allowed depth can't be lower than motion length, in order to handle contacts at low speed.
rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth);
@ -871,27 +922,36 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
}
}
if (rcd.best_len != 0) {
if (rcd.result_count > 0) {
if (r_result) {
r_result->collider = rcd.best_object->get_self();
r_result->collider_id = rcd.best_object->get_instance_id();
r_result->collider_shape = rcd.best_shape;
r_result->collision_local_shape = rcd.best_local_shape;
r_result->collision_normal = rcd.best_normal;
r_result->collision_point = rcd.best_contact;
r_result->collision_depth = rcd.best_len;
r_result->collision_safe_fraction = safe;
r_result->collision_unsafe_fraction = unsafe;
//r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape);
for (int collision_index = 0; collision_index < rcd.result_count; ++collision_index) {
const _RestResultData &result = (collision_index > 0) ? rcd.other_results[collision_index - 1] : rcd.best_result;
const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object);
PhysicsServer3D::MotionCollision &collision = r_result->collisions[collision_index];
Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass());
r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
collision.collider = result.object->get_self();
collision.collider_id = result.object->get_instance_id();
collision.collider_shape = result.shape;
collision.local_shape = result.local_shape;
collision.normal = result.normal;
collision.position = result.contact;
collision.depth = result.len;
//r_result->collider_metadata = result.object->get_shape_metadata(result.shape);
const Body3DSW *body = static_cast<const Body3DSW *>(result.object);
Vector3 rel_vec = result.contact - (body->get_transform().origin + body->get_center_of_mass());
collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec);
}
r_result->travel = safe * p_motion;
r_result->remainder = p_motion - safe * p_motion;
r_result->travel += (body_transform.get_origin() - p_from.get_origin());
r_result->safe_fraction = safe;
r_result->unsafe_fraction = unsafe;
r_result->collision_count = rcd.result_count;
}
collided = true;
@ -902,6 +962,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
r_result->travel = p_motion;
r_result->remainder = Vector3();
r_result->travel += (body_transform.get_origin() - p_from.get_origin());
r_result->safe_fraction = 1.0;
r_result->unsafe_fraction = 1.0;
}
return collided;

View File

@ -208,7 +208,7 @@ public:
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]; }
bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>());
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>());
Space3DSW();
~Space3DSW();

View File

@ -370,77 +370,132 @@ Vector3 PhysicsTestMotionResult3D::get_remainder() const {
return result.remainder;
}
Vector3 PhysicsTestMotionResult3D::get_collision_point() const {
return result.collision_point;
real_t PhysicsTestMotionResult3D::get_safe_fraction() const {
return result.safe_fraction;
}
Vector3 PhysicsTestMotionResult3D::get_collision_normal() const {
return result.collision_normal;
real_t PhysicsTestMotionResult3D::get_unsafe_fraction() const {
return result.unsafe_fraction;
}
Vector3 PhysicsTestMotionResult3D::get_collider_velocity() const {
return result.collider_velocity;
int PhysicsTestMotionResult3D::get_collision_count() const {
return result.collision_count;
}
ObjectID PhysicsTestMotionResult3D::get_collider_id() const {
return result.collider_id;
Vector3 PhysicsTestMotionResult3D::get_collision_point(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
return result.collisions[p_collision_index].position;
}
RID PhysicsTestMotionResult3D::get_collider_rid() const {
return result.collider;
Vector3 PhysicsTestMotionResult3D::get_collision_normal(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
return result.collisions[p_collision_index].normal;
}
Object *PhysicsTestMotionResult3D::get_collider() const {
return ObjectDB::get_instance(result.collider_id);
Vector3 PhysicsTestMotionResult3D::get_collider_velocity(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3());
return result.collisions[p_collision_index].collider_velocity;
}
int PhysicsTestMotionResult3D::get_collider_shape() const {
return result.collider_shape;
ObjectID PhysicsTestMotionResult3D::get_collider_id(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID());
return result.collisions[p_collision_index].collider_id;
}
real_t PhysicsTestMotionResult3D::get_collision_depth() const {
return result.collision_depth;
RID PhysicsTestMotionResult3D::get_collider_rid(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID());
return result.collisions[p_collision_index].collider;
}
real_t PhysicsTestMotionResult3D::get_collision_safe_fraction() const {
return result.collision_safe_fraction;
Object *PhysicsTestMotionResult3D::get_collider(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id);
}
real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const {
return result.collision_unsafe_fraction;
int PhysicsTestMotionResult3D::get_collider_shape(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0);
return result.collisions[p_collision_index].collider_shape;
}
real_t PhysicsTestMotionResult3D::get_collision_depth(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0);
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() {
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_collision_point"), &PhysicsTestMotionResult3D::get_collision_point);
ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult3D::get_collision_normal);
ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult3D::get_collider_velocity);
ClassDB::bind_method(D_METHOD("get_collider_id"), &PhysicsTestMotionResult3D::get_collider_id);
ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult3D::get_collider_rid);
ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult3D::get_collider);
ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult3D::get_collider_shape);
ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult3D::get_collision_depth);
ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction);
ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction);
ClassDB::bind_method(D_METHOD("get_safe_fraction"), &PhysicsTestMotionResult3D::get_safe_fraction);
ClassDB::bind_method(D_METHOD("get_unsafe_fraction"), &PhysicsTestMotionResult3D::get_unsafe_fraction);
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_normal", "collision_index"), &PhysicsTestMotionResult3D::get_collision_normal, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &PhysicsTestMotionResult3D::get_collider_velocity, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &PhysicsTestMotionResult3D::get_collider_id, 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_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collider_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_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::VECTOR3, "collision_point"), "", "get_collision_point");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_collision_normal");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "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");
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) {
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) {
MotionResult *r = nullptr;
if (p_result.is_valid()) {
r = p_result->get_result_ptr();
@ -449,7 +504,7 @@ bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, c
for (int i = 0; i < p_exclude.size(); i++) {
exclude.insert(p_exclude[i]);
}
return body_test_motion(p_body, p_from, p_motion, p_margin, r, p_collide_separation_ray, exclude);
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) {
@ -607,7 +662,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_test_motion", "body", "from", "motion", "margin", "result", "collide_separation_ray", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(false), DEFVAL(Array()));
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_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);

View File

@ -210,7 +210,7 @@ class PhysicsServer3D : public Object {
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>());
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);
protected:
static void _bind_methods();
@ -484,28 +484,34 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0;
struct MotionResult {
Vector3 travel;
Vector3 remainder;
Vector3 collision_point;
Vector3 collision_normal;
struct MotionCollision {
Vector3 position;
Vector3 normal;
Vector3 collider_velocity;
real_t collision_depth = 0.0;
real_t collision_safe_fraction = 0.0;
real_t collision_unsafe_fraction = 0.0;
int collision_local_shape = 0;
real_t depth = 0.0;
int local_shape = 0;
ObjectID collider_id;
RID collider;
int collider_shape = 0;
Variant collider_metadata;
real_t get_angle(Vector3 p_up_direction) const {
return Math::acos(collision_normal.dot(p_up_direction));
return Math::acos(normal.dot(p_up_direction));
}
};
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, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) = 0;
struct MotionResult {
Vector3 travel;
Vector3 remainder;
real_t safe_fraction = 0.0;
real_t unsafe_fraction = 0.0;
static const int MAX_COLLISIONS = 32;
MotionCollision collisions[MAX_COLLISIONS];
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;
/* SOFT BODY */
@ -770,17 +776,28 @@ public:
Vector3 get_travel() const;
Vector3 get_remainder() const;
real_t get_safe_fraction() const;
real_t get_unsafe_fraction() const;
Vector3 get_collision_point() const;
Vector3 get_collision_normal() const;
Vector3 get_collider_velocity() const;
ObjectID get_collider_id() const;
RID get_collider_rid() const;
Object *get_collider() const;
int get_collider_shape() const;
real_t get_collision_depth() const;
real_t get_collision_safe_fraction() const;
real_t get_collision_unsafe_fraction() const;
int get_collision_count() const;
Vector3 get_collision_point(int p_collision_index = 0) const;
Vector3 get_collision_normal(int p_collision_index = 0) const;
Vector3 get_collider_velocity(int p_collision_index = 0) const;
ObjectID get_collider_id(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;
int get_collider_shape(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)();