Fix 3D moving platform logic
Same thing that was already done in 2D, applies moving platform motion by using a call to move_and_collide that excludes the platform itself, instead of making it part of the body motion. Helps with handling walls and slopes correctly when the character walks on the moving platform. Also made some minor adjustments to the 2D version and documentation. Co-authored-by: fabriceci <fabricecipolla@gmail.com>
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user