Ver código fonte

Merge pull request #235 from blackberry-gaming/next-sgrenier

Next sgrenier
Steve Grenier 13 anos atrás
pai
commit
0e81a6ac87

+ 15 - 11
gameplay/src/PhysicsCharacter.cpp

@@ -17,15 +17,17 @@ class ClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexR
 {
 public:
 
-    ClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
+    ClosestNotMeConvexResultCallback(PhysicsCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
         : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), _me(me), _up(up), _minSlopeDot(minSlopeDot)
     {
     }
 
     btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
     {
-        if (convexResult.m_hitCollisionObject == _me)
-            return btScalar(1.0);
+        PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(convexResult.m_hitCollisionObject->getUserPointer());
+
+        if (object == _me || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
+            return 1.0f;
 
         /*
         btVector3 hitNormalWorld;
@@ -50,7 +52,7 @@ public:
 
 protected:
 
-    btCollisionObject* _me;
+    PhysicsCollisionObject* _me;
     const btVector3 _up;
     btScalar _minSlopeDot;
 };
@@ -64,7 +66,7 @@ PhysicsCharacter::PhysicsCharacter(Node* node, const PhysicsCollisionShape::Defi
     setMaxSlopeAngle(45.0f);
 
     // Set the collision flags on the ghost object to indicate it's a character
-    _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT);
+    _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE);
 
     // Register ourselves as an action on the physics world so we are called back during physics ticks
     Game::getInstance()->getPhysicsController()->_world->addAction(this);
@@ -365,7 +367,6 @@ void PhysicsCharacter::updateAction(btCollisionWorld* collisionWorld, btScalar d
     // dynamic objects (i.e. objects that moved and now intersect the character).
     if (_physicsEnabled)
     {
-        //_colliding = fixCollision(collisionWorld);
         _colliding = false;
         int stepCount = 0;
         while (fixCollision(collisionWorld))
@@ -495,7 +496,7 @@ void PhysicsCharacter::stepForwardAndStrafe(btCollisionWorld* collisionWorld, fl
 
         btVector3 sweepDirNegative(_currentPosition - targetPosition);
 
-        ClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.0));
+        ClosestNotMeConvexResultCallback callback(this, sweepDirNegative, btScalar(0.0));
         callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
         callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
@@ -556,7 +557,7 @@ void PhysicsCharacter::stepDown(btCollisionWorld* collisionWorld, btScalar time)
     start.setOrigin(_currentPosition);
     end.setOrigin(targetPosition);
 
-    ClosestNotMeConvexResultCallback callback(_ghostObject, btVector3(0, 1, 0), _cosSlopeAngle);
+    ClosestNotMeConvexResultCallback callback(this, btVector3(0, 1, 0), _cosSlopeAngle);
     callback.m_collisionFilterGroup = _ghostObject->getBroadphaseHandle()->m_collisionFilterGroup;
     callback.m_collisionFilterMask = _ghostObject->getBroadphaseHandle()->m_collisionFilterMask;
 
@@ -661,6 +662,12 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
             // Get the direction of the contact points (used to scale normal vector in the correct direction).
             btScalar directionSign = manifold->getBody0() == _ghostObject ? -1.0f : 1.0f;
 
+            // Skip ghost objects
+            PhysicsCollisionObject* object = Game::getInstance()->getPhysicsController()->getCollisionObject(
+                (btCollisionObject*)(manifold->getBody0() == _ghostObject ? manifold->getBody1() : manifold->getBody0()));
+            if (!object || object->getType() == PhysicsCollisionObject::GHOST_OBJECT)
+                continue;
+
             for (int p = 0, contactCount = manifold->getNumContacts(); p < contactCount; ++p)
             {
                 const btManifoldPoint& pt = manifold->getContactPoint(p);
@@ -678,14 +685,11 @@ bool PhysicsCharacter::fixCollision(btCollisionWorld* world)
                         _collisionNormal = pt.m_normalWorldOnB * directionSign;
                     }
 
-                    //Node* node = Game::getInstance()->getPhysicsController()->getCollisionObject((btCollisionObject*)(manifold->getBody0() == _ghostObject ? manifold->getBody1() : manifold->getBody0()))->getNode();
-
                     // Calculate new position for object, which is translated back along the collision normal
                     currentPosition += pt.m_normalWorldOnB * directionSign * dist * 0.2f;
                     collision = true;
                 }
             }
-            //manifold->clearManifold();
         }
     }
 

+ 8 - 1
gameplay/src/PhysicsCollisionObject.cpp

@@ -54,7 +54,14 @@ PhysicsMotionState* PhysicsCollisionObject::getMotionState() const
 
 bool PhysicsCollisionObject::isKinematic() const
 {
-    return getCollisionObject()->isKinematicObject();
+    switch (getType())
+    {
+    case GHOST_OBJECT:
+    case CHARACTER:
+        return true;
+    default:
+        return getCollisionObject()->isKinematicObject();
+    }
 }
 
 bool PhysicsCollisionObject::isDynamic() const

+ 0 - 1
gameplay/src/PhysicsCollisionShape.h

@@ -214,7 +214,6 @@ private:
      */
     ~PhysicsCollisionShape();
 
-
     // Shape type
     Type _type;
 

+ 85 - 7
gameplay/src/PhysicsController.cpp

@@ -134,22 +134,100 @@ void PhysicsController::drawDebug(const Matrix& viewProjection)
     _debugDrawer->end();
 }
 
-PhysicsCollisionObject* PhysicsController::rayTest(const Ray& ray, float distance, Vector3* hitPoint, float* hitFraction)
+bool PhysicsController::rayTest(const Ray& ray, float distance, PhysicsController::HitResult* result)
 {
     btCollisionWorld::ClosestRayResultCallback callback(BV(ray.getOrigin()), BV(distance * ray.getDirection()));
     _world->rayTest(BV(ray.getOrigin()), BV(distance * ray.getDirection()), callback);
     if (callback.hasHit())
     {
-        if (hitPoint)
-            hitPoint->set(callback.m_hitPointWorld.x(), callback.m_hitPointWorld.y(), callback.m_hitPointWorld.z());
+        if (result)
+        {
+            result->object = getCollisionObject(callback.m_collisionObject);
+            result->point.set(callback.m_hitPointWorld.x(), callback.m_hitPointWorld.y(), callback.m_hitPointWorld.z());
+            result->fraction = callback.m_closestHitFraction;
+            result->normal.set(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+bool PhysicsController::sweepTest(PhysicsCollisionObject* object, const Vector3& endPosition, PhysicsController::HitResult* result)
+{
+    class SweepTestCallback : public btCollisionWorld::ClosestConvexResultCallback
+    {
+    public:
 
-        if (hitFraction)
-            *hitFraction = callback.m_closestHitFraction;
+	    SweepTestCallback(PhysicsCollisionObject* me)
+            : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)), me(me)
+	    {
+	    }
+
+	    btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace)
+	    {
+            PhysicsCollisionObject* object = reinterpret_cast<PhysicsCollisionObject*>(convexResult.m_hitCollisionObject->getUserPointer());
+
+		    if (object == me)
+			    return 1.0f;
+
+		    return ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace);
+	    }
+
+	    PhysicsCollisionObject* me;
+    };
+
+    PhysicsCollisionShape* shape = object->getCollisionShape();
+    PhysicsCollisionShape::Type type = shape->getType();
+    if (type != PhysicsCollisionShape::SHAPE_BOX && type != PhysicsCollisionShape::SHAPE_SPHERE && type != PhysicsCollisionShape::SHAPE_CAPSULE)
+        return false; // unsupported type
+
+    // Define the start transform
+    btTransform start;
+    if (object->getNode())
+        start.setFromOpenGLMatrix(object->getNode()->getWorldMatrix().m);
+    else
+        start.setIdentity();
+
+    // Define the end transform
+    btTransform end(start);
+    end.setOrigin(BV(endPosition));
+
+    // Perform bullet convex sweep test
+    SweepTestCallback callback(object);
+
+    // If the object is represented by a ghost object, use the ghost object's convex sweep test
+    // since it is much faster than the world's version.
+    /*switch (object->getType())
+    {
+    case PhysicsCollisionObject::GHOST_OBJECT:
+    case PhysicsCollisionObject::CHARACTER:
+        static_cast<PhysicsGhostObject*>(object)->_ghostObject->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
+        break;
+
+    default:
+        _world->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
+        break;
+    }
+    */
+    _world->convexSweepTest(static_cast<btConvexShape*>(shape->getShape()), start, end, callback, _world->getDispatchInfo().m_allowedCcdPenetration);
+
+    // Check for hits and store results
+    if (callback.hasHit())
+    {
+        if (result)
+        {
+            result->object = getCollisionObject(callback.m_hitCollisionObject);
+            result->point.set(callback.m_hitPointWorld.x(), callback.m_hitPointWorld.y(), callback.m_hitPointWorld.z());
+            result->fraction = callback.m_closestHitFraction;
+            result->normal.set(callback.m_hitNormalWorld.x(), callback.m_hitNormalWorld.y(), callback.m_hitNormalWorld.z());
+        }
 
-        return getCollisionObject(callback.m_collisionObject);
+        return true;
     }
 
-    return NULL;
+    return false;
 }
 
 btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, 

+ 43 - 7
gameplay/src/PhysicsController.h

@@ -56,6 +56,32 @@ public:
         virtual void statusEvent(EventType type) = 0;
     };
 
+    /**
+     * Stucture that stores hit test results for ray and sweep tests.
+     */
+    struct HitResult
+    {
+        /**
+         * The collision object that was hit.
+         */
+        PhysicsCollisionObject* object;
+
+        /**
+         * The point where the collision occurred, in world space.
+         */
+        Vector3 point;
+
+        /**
+         * The fraction (0-1) of the test distance to the collision point.
+         */
+        float fraction;
+
+        /**
+         * The normal vector of the collision surface, in world space.
+         */
+        Vector3 normal;
+    };
+
     /**
      * Adds a listener to the physics controller.
      * 
@@ -185,7 +211,7 @@ public:
      * @param gravity The gravity vector.
      */
     void setGravity(const Vector3& gravity);
-   
+
     /**
      * Draws debugging information (rigid body outlines, etc.) using the given view projection matrix.
      * 
@@ -194,16 +220,26 @@ public:
     void drawDebug(const Matrix& viewProjection);
 
     /**
-     * Gets the first rigid body that the given ray intersects.
+     * Performs a ray test on the physics world.
      * 
      * @param ray The ray to test intersection with.
      * @param distance How far along the given ray to test for intersections.
-     * @param hitPoint Optional Vector3 point that is populated with the world-space point of intersection.
-     * @param hitFraction Optional float pointer that is populated with the distance along the ray
-     *      (as a fraction between 0-1) where the intersection occurred.
-     * @return The first rigid body that the ray intersects, or NULL if no intersection was found.
+     * @param result Optioanl pointer to a HitTest structure to store hit test result information in.
+     * @return True if the ray test collided with a physics object, false otherwise.
+     */
+    bool rayTest(const Ray& ray, float distance, PhysicsController::HitResult* result = NULL);
+
+    /**
+     * Performs a sweep test of the given collision object on the physics world.
+     *
+     * The start position of the sweep test is defined by the current world position
+     * of the specified collision object.
+     *
+     * @param object The collision object to test.
+     * @param endPosition The end position of the sweep test, in world space.
+     * @return True if the object intersects any other physics objects, false otherwise.
      */
-    PhysicsCollisionObject* rayTest(const Ray& ray, float distance, Vector3* hitPoint = NULL, float* hitFraction = NULL);
+    bool sweepTest(PhysicsCollisionObject* object, const Vector3& endPosition, PhysicsController::HitResult* result = NULL);
 
 protected:
 

+ 1 - 0
gameplay/src/PhysicsGhostObject.cpp

@@ -18,6 +18,7 @@ PhysicsGhostObject::PhysicsGhostObject(Node* node, const PhysicsCollisionShape::
     // Create the ghost object.
     _ghostObject = bullet_new<btPairCachingGhostObject>();
     _ghostObject->setCollisionShape(_collisionShape->getShape());
+    _ghostObject->setCollisionFlags(_ghostObject->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
 
     // Initialize a physics motion state object for syncing the transform.
     _motionState = new PhysicsMotionState(_node, &centerOfMassOffset);

+ 1 - 0
gameplay/src/PhysicsGhostObject.h

@@ -16,6 +16,7 @@ class PhysicsMotionState;
 class PhysicsGhostObject : public PhysicsCollisionObject, public Transform::Listener
 {
     friend class Node;
+    friend class PhysicsController;
 
 public: