summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/classes/CharacterBody2D.xml1
-rw-r--r--doc/classes/CharacterBody3D.xml1
-rw-r--r--doc/classes/PhysicsServer3D.xml2
-rw-r--r--modules/bullet/bullet_physics_server.cpp4
-rw-r--r--modules/bullet/bullet_physics_server.h2
-rw-r--r--modules/bullet/godot_result_callbacks.cpp4
-rw-r--r--modules/bullet/godot_result_callbacks.h4
-rw-r--r--modules/bullet/space_bullet.cpp16
-rw-r--r--modules/bullet/space_bullet.h4
-rw-r--r--scene/2d/physics_body_2d.cpp2
-rw-r--r--scene/2d/physics_body_2d.h3
-rw-r--r--scene/3d/physics_body_3d.cpp97
-rw-r--r--scene/3d/physics_body_3d.h4
-rw-r--r--servers/physics_3d/physics_server_3d_sw.cpp4
-rw-r--r--servers/physics_3d/physics_server_3d_sw.h2
-rw-r--r--servers/physics_3d/physics_server_3d_wrap_mt.h4
-rw-r--r--servers/physics_3d/space_3d_sw.cpp11
-rw-r--r--servers/physics_3d/space_3d_sw.h2
-rw-r--r--servers/physics_server_3d.cpp10
-rw-r--r--servers/physics_server_3d.h4
20 files changed, 119 insertions, 62 deletions
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index 1ace7ee6bf..b73aba50fd 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -79,6 +79,7 @@
Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
Modifies [member linear_velocity] 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>
</methods>
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 577ab5e84c..4cb4f9a850 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -65,6 +65,7 @@
Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes.
This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed.
Modifies [member linear_velocity] 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>
</methods>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 7bca8afdda..d6b7318a06 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -572,6 +572,8 @@
<argument index="3" name="infinite_inertia" type="bool" />
<argument index="4" name="margin" type="float" default="0.001" />
<argument index="5" name="result" type="PhysicsTestMotionResult3D" default="null" />
+ <argument index="6" name="exclude_raycast_shapes" type="bool" default="true" />
+ <argument index="7" 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. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in.
</description>
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index e07be14c5b..fc876a81cf 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -842,12 +842,12 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod
return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
-bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &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.getornull(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 BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index d34d619ba2..7f0934e679 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -253,7 +253,7 @@ public:
// this function only works on physics process, errors and returns null otherwise
virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override;
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &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>()) override;
virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
/* SOFT BODY API */
diff --git a/modules/bullet/godot_result_callbacks.cpp b/modules/bullet/godot_result_callbacks.cpp
index 399b102284..1f962772e7 100644
--- a/modules/bullet/godot_result_callbacks.cpp
+++ b/modules/bullet/godot_result_callbacks.cpp
@@ -135,6 +135,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 {
diff --git a/modules/bullet/godot_result_callbacks.h b/modules/bullet/godot_result_callbacks.h
index 9216322108..96a649d77a 100644
--- a/modules/bullet/godot_result_callbacks.h
+++ b/modules/bullet/godot_result_callbacks.h
@@ -100,11 +100,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;
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index 583900e6bc..c6d835742d 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat;
static Ref<StandardMaterial3D> blue_mat;
#endif
-bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::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
@@ -948,7 +948,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
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;
}
}
@@ -1000,7 +1000,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
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();
@@ -1023,7 +1023,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
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) {
@@ -1173,7 +1173,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;
@@ -1242,6 +1242,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;
diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h
index 36d0538e6b..2070e0e633 100644
--- a/modules/bullet/space_bullet.h
+++ b/modules/bullet/space_bullet.h
@@ -188,7 +188,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 Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
private:
@@ -209,7 +209,7 @@ private:
RecoverResult() {}
};
- 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);
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 00eeb60192..9235a2290e 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -1075,7 +1075,7 @@ void CharacterBody2D::move_and_slide() {
floor_normal = Vector2();
floor_velocity = Vector2();
- if (current_floor_velocity != Vector2()) {
+ if (current_floor_velocity != Vector2() && on_floor_body.is_valid()) {
PhysicsServer2D::MotionResult floor_result;
Set<RID> exclude;
exclude.insert(on_floor_body);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index 7a319aabc9..c20372fe75 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -292,6 +292,8 @@ private:
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
+ void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
+
bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result);
void set_safe_margin(real_t p_margin);
@@ -314,7 +316,6 @@ private:
const Vector2 &get_up_direction() const;
void set_up_direction(const Vector2 &p_up_direction);
- void _set_collision_direction(const PhysicsServer2D::MotionResult &p_result);
protected:
void _notification(int p_what);
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 38104a8365..53ec07f1ce 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -117,9 +117,9 @@ Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_i
return Ref<KinematicCollision3D>();
}
-bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) {
+bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding, const Set<RID> &p_exclude) {
Transform3D gt = get_global_transform();
- bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes);
+ bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes, p_exclude);
// Restore direction of motion to be along original motion,
// in order to avoid sliding due to recovery,
@@ -1090,6 +1090,9 @@ void CharacterBody3D::move_and_slide() {
bool was_on_floor = on_floor;
+ // 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();
+
for (int i = 0; i < 3; i++) {
if (locked_axis & (1 << i)) {
linear_velocity[i] = 0.0;
@@ -1097,7 +1100,7 @@ void CharacterBody3D::move_and_slide() {
}
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
PhysicsDirectBodyState3D *bs = PhysicsServer3D::get_singleton()->body_get_direct_state(on_floor_body);
if (bs) {
@@ -1107,20 +1110,30 @@ void CharacterBody3D::move_and_slide() {
}
}
- // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky
- Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time());
-
+ motion_results.clear();
on_floor = false;
- on_floor_body = RID();
on_ceiling = false;
on_wall = false;
- motion_results.clear();
floor_normal = Vector3();
floor_velocity = Vector3();
+ if (current_floor_velocity != Vector3() && on_floor_body.is_valid()) {
+ PhysicsServer3D::MotionResult floor_result;
+ Set<RID> exclude;
+ exclude.insert(on_floor_body);
+ if (move_and_collide(current_floor_velocity * delta, infinite_inertia, floor_result, true, false, false, false, exclude)) {
+ motion_results.push_back(floor_result);
+ _set_collision_direction(floor_result);
+ }
+ }
+
+ on_floor_body = RID();
+ Vector3 motion = linear_velocity * delta;
+
// No sliding on first attempt to keep floor motion stable when possible,
// when stop on slope is enabled.
bool sliding_enabled = !stop_on_slope;
+
for (int iteration = 0; iteration < max_slides; ++iteration) {
PhysicsServer3D::MotionResult result;
bool found_collision = false;
@@ -1144,35 +1157,19 @@ void CharacterBody3D::move_and_slide() {
found_collision = true;
motion_results.push_back(result);
-
- if (up_direction == Vector3()) {
- //all is a wall
- on_wall = true;
- } else {
- if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
-
- on_floor = true;
- floor_normal = result.collision_normal;
- on_floor_body = result.collider;
- floor_velocity = result.collider_velocity;
-
- if (stop_on_slope) {
- if ((body_velocity_normal + up_direction).length() < 0.01) {
- Transform3D gt = get_global_transform();
- if (result.motion.length() > margin) {
- gt.origin -= result.motion.slide(up_direction);
- } else {
- gt.origin -= result.motion;
- }
- set_global_transform(gt);
- linear_velocity = Vector3();
- return;
- }
+ _set_collision_direction(result);
+
+ if (on_floor && stop_on_slope) {
+ if ((body_velocity_normal + up_direction).length() < 0.01) {
+ Transform3D gt = get_global_transform();
+ if (result.motion.length() > margin) {
+ gt.origin -= result.motion.slide(up_direction);
+ } else {
+ gt.origin -= result.motion;
}
- } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
- on_ceiling = true;
- } else {
- on_wall = true;
+ set_global_transform(gt);
+ linear_velocity = Vector3();
+ return;
}
}
@@ -1198,6 +1195,11 @@ void CharacterBody3D::move_and_slide() {
}
}
+ if (!on_floor && !on_wall) {
+ // Add last platform velocity when just left a moving platform.
+ linear_velocity += current_floor_velocity;
+ }
+
if (!was_on_floor || snap == Vector3()) {
return;
}
@@ -1233,6 +1235,29 @@ void CharacterBody3D::move_and_slide() {
}
}
+void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResult &p_result) {
+ on_floor = false;
+ on_ceiling = false;
+ on_wall = false;
+ if (up_direction == Vector3()) {
+ //all is a wall
+ on_wall = true;
+ } else {
+ if (Math::acos(p_result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor
+ on_floor = true;
+ floor_normal = p_result.collision_normal;
+ on_floor_body = p_result.collider;
+ floor_velocity = p_result.collider_velocity;
+ } else if (Math::acos(p_result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling
+ on_ceiling = true;
+ } else {
+ on_wall = true;
+ on_floor_body = p_result.collider;
+ floor_velocity = p_result.collider_velocity;
+ }
+ }
+}
+
bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) {
PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays
diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h
index 0ef9c78f3b..227e6d43b6 100644
--- a/scene/3d/physics_body_3d.h
+++ b/scene/3d/physics_body_3d.h
@@ -53,7 +53,7 @@ protected:
Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001);
public:
- bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, 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, PhysicsServer3D::MotionResult &r_result, real_t p_margin, 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 Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001);
void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock);
@@ -298,6 +298,8 @@ private:
Ref<KinematicCollision3D> _get_slide_collision(int p_bounce);
+ void _set_collision_direction(const PhysicsServer3D::MotionResult &p_result);
+
bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result);
void set_safe_margin(real_t p_margin);
diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp
index c1a9d6259d..e2ab84428b 100644
--- a/servers/physics_3d/physics_server_3d_sw.cpp
+++ b/servers/physics_3d/physics_server_3d_sw.cpp
@@ -854,7 +854,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, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes, 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);
@@ -862,7 +862,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_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
+ return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
}
int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h
index 0ccd15fbb2..326b6fbe7a 100644
--- a/servers/physics_3d/physics_server_3d_sw.h
+++ b/servers/physics_3d/physics_server_3d_sw.h
@@ -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, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) override;
virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override;
// this function only works on physics process, errors and returns null otherwise
diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h
index 9beec22bcd..c3c2e50e56 100644
--- a/servers/physics_3d/physics_server_3d_wrap_mt.h
+++ b/servers/physics_3d/physics_server_3d_wrap_mt.h
@@ -250,9 +250,9 @@ public:
FUNC2(body_set_ray_pickable, RID, bool);
- bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override {
+ bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, 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_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes);
+ return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes, p_exclude);
}
int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override {
diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp
index 1037243d3b..2a39a9d363 100644
--- a/servers/physics_3d/space_3d_sw.cpp
+++ b/servers/physics_3d/space_3d_sw.cpp
@@ -720,7 +720,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_t
return rays_found;
}
-bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) {
+bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::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
@@ -801,6 +801,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ if (p_exclude.has(col_obj->get_self())) {
+ continue;
+ }
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
@@ -890,6 +893,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ if (p_exclude.has(col_obj->get_self())) {
+ continue;
+ }
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
@@ -1015,6 +1021,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co
for (int i = 0; i < amount; i++) {
const CollisionObject3DSW *col_obj = intersection_query_results[i];
+ if (p_exclude.has(col_obj->get_self())) {
+ continue;
+ }
int shape_idx = intersection_query_subindex_results[i];
if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) {
diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h
index 18e93c90cc..580693deba 100644
--- a/servers/physics_3d/space_3d_sw.h
+++ b/servers/physics_3d/space_3d_sw.h
@@ -204,7 +204,7 @@ public:
uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; }
int test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin);
- bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes);
+ bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude = Set<RID>());
Space3DSW();
~Space3DSW();
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 63a51dd9d6..b4ee5fbaf0 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -447,12 +447,16 @@ void PhysicsTestMotionResult3D::_bind_methods() {
///////////////////////////////////////
-bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result) {
+bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &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, p_margin, 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, p_margin, r, p_exclude_raycast_shapes, exclude);
}
RID PhysicsServer3D::shape_create(ShapeType p_shape) {
@@ -608,7 +612,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", "infinite_inertia", "margin", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result", "exclude_raycast_shapes", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(true), DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 3fb01b301b..0d3d5bd4a1 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -212,7 +212,7 @@ class PhysicsServer3D : public Object {
static PhysicsServer3D *singleton;
- virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>());
+ virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_exclude_raycast_shapes = true, const Vector<RID> &p_exclude = Vector<RID>());
protected:
static void _bind_methods();
@@ -491,7 +491,7 @@ public:
Variant collider_metadata;
};
- virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0;
+ virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true, const Set<RID> &p_exclude = Set<RID>()) = 0;
struct SeparationResult {
real_t collision_depth;