Quellcode durchsuchen

Fixes a bug in the physics character where the character was applying to much force to objects when falling and didn't handle collision with multiple objects when falling properly (causing unreasonable increases in the vertical velocity and falling through the ground).

Chris Culy vor 13 Jahren
Ursprung
Commit
e856054ff8
1 geänderte Dateien mit 50 neuen und 26 gelöschten Zeilen
  1. 50 26
      gameplay/src/PhysicsCharacter.cpp

+ 50 - 26
gameplay/src/PhysicsCharacter.cpp

@@ -440,44 +440,68 @@ void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
     btTransform end;
     btTransform end;
     start.setIdentity();
     start.setIdentity();
     end.setIdentity();
     end.setIdentity();
-    start.setOrigin(_currentPosition);
-    end.setOrigin(targetPosition);
 
 
-    ClosestNotMeConvexResultCallback callback(this, btVector3(0, 1, 0), _cosSlopeAngle);
-    callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
-    callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
+    btScalar fraction = 1.0;
+    int maxIter = 10;
+    while (fraction > btScalar(0.01) && maxIter-- > 0)
+    {
+        start.setOrigin(_currentPosition);
+        end.setOrigin(targetPosition);
 
 
-    _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
+        btVector3 sweepDirNegative(_currentPosition - targetPosition);
 
 
-    if (callback.hasHit())
-    {
-        // Collision detected, fix it.
-        Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
-        normal.normalize();
+        ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, 0.0);
+        callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
+        callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
 
-        float dot = normal.dot(Vector3::unitY());
-        if (dot > 1.0f - MATH_EPSILON)
-        {
-            targetPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
+        _ghostObject->convexSweepTest(static_cast<btConvexShape*>(_collisionShape->getShape()), start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
 
 
-            // Zero out fall velocity when we hit an object going straight down.
-            _verticalVelocity.setZero();
-        }
-        else
+        fraction -= callback.m_closestHitFraction;
+
+        if (callback.hasHit())
         {
         {
-            PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
-            if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
+            // Collision detected, fix it.
+            Vector3 normal(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+            normal.normalize();
+
+            float dot = normal.dot(Vector3::unitY());
+            if (dot > 1.0f - MATH_EPSILON)
             {
             {
-                PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
-                normal.normalize();
-                rb->applyImpulse(_mass * -normal * dot);
+                targetPosition.setInterpolate3(_currentPosition, targetPosition, callback.m_closestHitFraction);
+
+                // Zero out fall velocity when we hit an object going straight down.
+                _verticalVelocity.setZero();
+                break;
             }
             }
+            else
+            {
+                PhysicsCollisionObject* o = Game::getInstance()->getPhysicsController()->getCollisionObject(callback.m_hitCollisionObject);
+                if (o->getType() == PhysicsCollisionObject::RIGID_BODY && o->isDynamic())
+                {
+                    PhysicsRigidBody* rb = static_cast<PhysicsRigidBody*>(o);
+                    normal.normalize();
+                    rb->applyImpulse(_mass * -normal * sqrt(BV(normal).dot(_verticalVelocity)));
+                }
 
 
-            updateTargetPositionFromCollision(targetPosition, BV(normal));
-            _currentPosition = targetPosition;
+                updateTargetPositionFromCollision(targetPosition, BV(normal));
+            }
+        }
+        else
+        {
+            // Nothing is in the way.
+            break;
         }
         }
     }
     }
 
 
+    // Calculate what the vertical velocity actually is.
+    // In cases where the character might not actually be able to move down,
+    // but isn't intersecting with an object straight down either, we don't
+    // want to keep increasing the vertical velocity until the character 
+    // randomly drops through the floor when it can finally move due to its
+    // vertical velocity having such a great magnitude.
+    if (!_verticalVelocity.isZero())
+        _verticalVelocity = ((targetPosition + btVector3(0.0, _stepHeight, 0.0)) - _currentPosition) / time;
+
     _currentPosition = targetPosition;
     _currentPosition = targetPosition;
 }
 }