Merge pull request #51458 from nekomatata/moving-platforms-3d-3.x

[3.x] Fix 3D moving platform logic
This commit is contained in:
Rémi Verschelde 2021-08-10 14:12:47 +02:00 committed by GitHub
commit 03c41fa34c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 111 additions and 56 deletions

View file

@ -95,6 +95,7 @@
[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees.
If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody] nodes like with [StaticBody].
Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
</description>
</method>
<method name="move_and_slide_with_snap">

View file

@ -93,6 +93,7 @@
[code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees.
If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody2D] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody2D] nodes like with [StaticBody2D].
Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision].
When the body touches a moving platform, the platform's velocity is automatically added to the body motion. If a collision occurs due to the platform's motion, it will always be first in the slide collisions.
</description>
</method>
<method name="move_and_slide_with_snap">

View file

@ -602,6 +602,8 @@
<argument index="2" name="motion" type="Vector3" />
<argument index="3" name="infinite_inertia" type="bool" />
<argument index="4" name="result" type="PhysicsTestMotionResult" default="null" />
<argument index="5" name="exclude_raycast_shapes" type="bool" default="true" />
<argument index="6" name="exclude" type="Array" default="[ ]" />
<description>
Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. [PhysicsTestMotionResult] can be passed to return additional information in.
</description>

View file

@ -856,12 +856,12 @@ PhysicsDirectBodyState *BulletPhysicsServer::body_get_direct_state(RID p_body) {
return BulletPhysicsDirectBodyState::get_singleton(body);
}
bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
bool BulletPhysicsServer::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
RigidBodyBullet *body = rigid_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes);
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes, p_exclude);
}
int BulletPhysicsServer::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) {

View file

@ -254,7 +254,7 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body);
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true);
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>());
virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001);
/* SOFT BODY API */

View file

@ -142,6 +142,10 @@ bool GodotKinClosestConvexResultCallback::needsCollision(btBroadphaseProxy *prox
if (m_self_object->has_collision_exception(gObj) || gObj->has_collision_exception(m_self_object)) {
return false;
}
if (m_exclude->has(gObj->get_self())) {
return false;
}
}
return true;
} else {

View file

@ -105,11 +105,13 @@ public:
struct GodotKinClosestConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
public:
const RigidBodyBullet *m_self_object;
const Set<RID> *m_exclude;
const bool m_infinite_inertia;
GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia) :
GodotKinClosestConvexResultCallback(const btVector3 &convexFromWorld, const btVector3 &convexToWorld, const RigidBodyBullet *p_self_object, bool p_infinite_inertia, const Set<RID> *p_exclude) :
btCollisionWorld::ClosestConvexResultCallback(convexFromWorld, convexToWorld),
m_self_object(p_self_object),
m_exclude(p_exclude),
m_infinite_inertia(p_infinite_inertia) {}
virtual bool needsCollision(btBroadphaseProxy *proxy0) const;

View file

@ -928,7 +928,7 @@ static Ref<SpatialMaterial> red_mat;
static Ref<SpatialMaterial> blue_mat;
#endif
bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
#if debug_test_motion
/// Yes I know this is not good, but I've used it as fast debugging hack.
/// I'm leaving it here just for speedup the other eventual debugs
@ -968,7 +968,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
btVector3 initial_recover_motion(0, 0, 0);
{ /// Phase one - multi shapes depenetration using margin
for (int t(RECOVERING_MOVEMENT_CYCLES); 0 < t; --t) {
if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion)) {
if (!recover_from_penetration(p_body, body_transform, RECOVERING_MOVEMENT_SCALE, p_infinite_inertia, initial_recover_motion, nullptr, p_exclude)) {
break;
}
}
@ -1020,7 +1020,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
break;
}
GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia);
GodotKinClosestConvexResultCallback btResult(shape_world_from.getOrigin(), shape_world_to.getOrigin(), p_body, p_infinite_inertia, &p_exclude);
btResult.m_collisionFilterGroup = p_body->get_collision_layer();
btResult.m_collisionFilterMask = p_body->get_collision_mask();
@ -1043,7 +1043,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f
btVector3 __rec(0, 0, 0);
RecoverResult r_recover_result;
has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result);
has_penetration = recover_from_penetration(p_body, body_transform, 1, p_infinite_inertia, __rec, &r_recover_result, p_exclude);
// Parse results
if (r_result) {
@ -1195,7 +1195,7 @@ public:
}
};
bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result) {
bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result, const Set<RID> &p_exclude) {
// Calculate the cumulative AABB of all shapes of the kinematic body
btVector3 aabb_min, aabb_max;
bool shapes_found = false;
@ -1264,6 +1264,12 @@ bool SpaceBullet::recover_from_penetration(RigidBodyBullet *p_body, const btTran
for (int i = recover_broad_result.results.size() - 1; 0 <= i; --i) {
btCollisionObject *otherObject = recover_broad_result.results[i].collision_object;
CollisionObjectBullet *gObj = static_cast<CollisionObjectBullet *>(otherObject->getUserPointer());
if (p_exclude.has(gObj->get_self())) {
continue;
}
if (p_infinite_inertia && !otherObject->isStaticOrKinematicObject()) {
otherObject->activate(); // Force activation of hitten rigid, soft body
continue;

View file

@ -185,7 +185,7 @@ public:
real_t get_linear_damp() const { return linear_damp; }
real_t get_angular_damp() const { return angular_damp; }
bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes);
bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, float p_margin);
private:
@ -213,7 +213,7 @@ private:
local_shape_most_recovered(0) {}
};
bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);
bool recover_from_penetration(RigidBodyBullet *p_body, const btTransform &p_body_position, btScalar p_recover_movement_scale, bool p_infinite_inertia, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr, const Set<RID> &p_exclude = Set<RID>());
/// This is an API that recover a kinematic object from penetration
/// This allow only Convex Convex test and it always use GJK algorithm, With this API we don't benefit of Bullet special accelerated functions
bool RFP_convex_convex_test(const btConvexShape *p_shapeA, const btConvexShape *p_shapeB, btCollisionObject *p_objectB, int p_shapeId_A, int p_shapeId_B, const btTransform &p_transformA, const btTransform &p_transformB, btScalar p_recover_movement_scale, btVector3 &r_delta_recover_movement, RecoverResult *r_recover_result = nullptr);

View file

@ -1128,7 +1128,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
floor_normal = Vector2();
floor_velocity = Vector2();
if (current_floor_velocity != Vector2()) {
if (current_floor_velocity != Vector2() && on_floor_body.is_valid()) {
Collision floor_collision;
Set<RID> exclude;
exclude.insert(on_floor_body);

View file

@ -973,14 +973,14 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_inf
return Ref<KinematicCollision>();
}
bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) {
bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
if (sync_to_physics) {
ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation.");
}
Transform gt = get_global_transform();
PhysicsServer::MotionResult result;
bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes);
bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@ -1061,8 +1061,11 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
}
}
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
float delta = Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time();
Vector3 current_floor_velocity = floor_velocity;
if (on_floor && on_floor_body.is_valid()) {
if ((on_floor || on_wall) && on_floor_body.is_valid()) {
// This approach makes sure there is less delay between the actual body velocity and the one we saved.
PhysicsDirectBodyState *bs = PhysicsServer::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
@ -1072,17 +1075,26 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
}
}
// Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
Vector3 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
colliders.clear();
on_floor = false;
on_floor_body = RID();
on_ceiling = false;
on_wall = false;
colliders.clear();
floor_normal = Vector3();
floor_velocity = Vector3();
if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) {
Collision floor_collision;
Set<RID> exclude;
exclude.insert(on_floor_body);
if (move_and_collide(current_floor_velocity * delta, p_infinite_inertia, floor_collision, true, false, false, exclude)) {
colliders.push_back(floor_collision);
_set_collision_direction(floor_collision, up_direction, p_floor_max_angle);
}
}
on_floor_body = RID();
Vector3 motion = body_velocity * delta;
// No sliding on first attempt to keep floor motion stable when possible,
// when stop on slope is enabled.
bool sliding_enabled = !p_stop_on_slope;
@ -1110,33 +1122,18 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
colliders.push_back(collision);
if (up_direction == Vector3()) {
//all is a wall
on_wall = true;
} else {
if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
_set_collision_direction(collision, up_direction, p_floor_max_angle);
on_floor = true;
floor_normal = collision.normal;
on_floor_body = collision.collider_rid;
floor_velocity = collision.collider_vel;
if (p_stop_on_slope) {
if ((body_velocity_normal + up_direction).length() < 0.01) {
Transform gt = get_global_transform();
if (collision.travel.length() > margin) {
gt.origin -= collision.travel.slide(up_direction);
} else {
gt.origin -= collision.travel;
}
set_global_transform(gt);
return Vector3();
}
if (on_floor && p_stop_on_slope) {
if ((body_velocity_normal + up_direction).length() < 0.01) {
Transform gt = get_global_transform();
if (collision.travel.length() > margin) {
gt.origin -= collision.travel.slide(up_direction);
} else {
gt.origin -= collision.travel;
}
} else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
set_global_transform(gt);
return Vector3();
}
}
@ -1162,6 +1159,11 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
}
}
if (!on_floor && !on_wall) {
// Add last platform velocity when just left a moving platform.
return body_velocity + current_floor_velocity;
}
return body_velocity;
}
@ -1207,6 +1209,29 @@ Vector3 KinematicBody::move_and_slide_with_snap(const Vector3 &p_linear_velocity
return ret;
}
void KinematicBody::_set_collision_direction(const Collision &p_collision, const Vector3 &p_up_direction, float p_floor_max_angle) {
on_floor = false;
on_ceiling = false;
on_wall = false;
if (p_up_direction == Vector3()) {
//all is a wall
on_wall = true;
} else {
if (Math::acos(p_collision.normal.dot(p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
on_floor = true;
floor_normal = p_collision.normal;
on_floor_body = p_collision.collider_rid;
floor_velocity = p_collision.collider_vel;
} else if (Math::acos(p_collision.normal.dot(-p_up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
on_ceiling = true;
} else {
on_wall = true;
on_floor_body = p_collision.collider_rid;
floor_velocity = p_collision.collider_vel;
}
}
}
bool KinematicBody::is_on_floor() const {
return on_floor;
}

View file

@ -300,13 +300,14 @@ private:
Transform last_valid_transform;
void _direct_state_changed(Object *p_state);
void _set_collision_direction(const Collision &p_collision, const Vector3 &p_up_direction, float p_floor_max_angle);
protected:
void _notification(int p_what);
static void _bind_methods();
public:
bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true);
bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true, const Set<RID> &p_exclude = Set<RID>());
bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision);

View file

@ -860,7 +860,7 @@ bool PhysicsServerSW::body_is_ray_pickable(RID p_body) const {
return body->is_ray_pickable();
}
bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@ -868,7 +868,7 @@ bool PhysicsServerSW::body_test_motion(RID p_body, const Transform &p_from, cons
_update_shapes();
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes);
return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes, p_exclude);
}
int PhysicsServerSW::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin) {

View file

@ -233,7 +233,7 @@ public:
virtual void body_set_ray_pickable(RID p_body, bool p_enable);
virtual bool body_is_ray_pickable(RID p_body) const;
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true);
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>());
virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, float p_margin = 0.001);
// this function only works on physics process, errors and returns null otherwise

View file

@ -712,7 +712,7 @@ int SpaceSW::test_body_ray_separation(BodySW *p_body, const Transform &p_transfo
return rays_found;
}
bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes) {
bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
//give me back regular physics engine logic
//this is madness
//and most people using this function will think
@ -793,6 +793,9 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
for (int i = 0; i < amount; i++) {
const CollisionObjectSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObjectSW::TYPE_BODY == col_obj->get_type()) {
@ -882,6 +885,9 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
for (int i = 0; i < amount; i++) {
const CollisionObjectSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObjectSW::TYPE_BODY == col_obj->get_type()) {
@ -1008,6 +1014,9 @@ bool SpaceSW::test_body_motion(BodySW *p_body, const Transform &p_from, const Ve
for (int i = 0; i < amount; i++) {
const CollisionObjectSW *col_obj = intersection_query_results[i];
if (p_exclude.has(col_obj->get_self())) {
continue;
}
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObjectSW::TYPE_BODY == col_obj->get_type()) {

View file

@ -199,7 +199,7 @@ public:
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
int test_body_ray_separation(BodySW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer::SeparationResult *r_results, int p_result_max, real_t p_margin);
bool test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes);
bool test_body_motion(BodySW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
SpaceSW();
~SpaceSW();

View file

@ -436,12 +436,16 @@ void PhysicsTestMotionResult::_bind_methods() {
///////////////////////////////////////
bool PhysicsServer::_body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, const Ref<PhysicsTestMotionResult> &p_result) {
bool PhysicsServer::_body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, const Ref<PhysicsTestMotionResult> &p_result, bool p_exclude_raycast_shapes, const Vector<RID> &p_exclude) {
MotionResult *r = nullptr;
if (p_result.is_valid()) {
r = p_result->get_result_ptr();
}
return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, r);
Set<RID> exclude;
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_infinite_inertia, r, p_exclude_raycast_shapes, exclude);
}
void PhysicsServer::_bind_methods() {
@ -565,7 +569,7 @@ void PhysicsServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer::body_set_ray_pickable);
ClassDB::bind_method(D_METHOD("body_is_ray_pickable", "body"), &PhysicsServer::body_is_ray_pickable);
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "result"), &PhysicsServer::_body_test_motion, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer::_body_test_motion, DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer::body_get_direct_state);

View file

@ -201,7 +201,7 @@ class PhysicsServer : public Object {
static PhysicsServer *singleton;
virtual bool _body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, const Ref<PhysicsTestMotionResult> &p_result = Ref<PhysicsTestMotionResult>());
virtual bool _body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, const Ref<PhysicsTestMotionResult> &p_result = Ref<PhysicsTestMotionResult>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>());
protected:
static void _bind_methods();
@ -473,7 +473,7 @@ public:
Variant collider_metadata;
};
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0;
struct SeparationResult {
float collision_depth;