2
0
Эх сурвалжийг харах

Merge pull request #149 from blackberry-gaming/next-cculy

Next cculy
Sean Paul Taylor 14 жил өмнө
parent
commit
c50e4614e5

+ 22 - 2
gameplay/src/ParticleEmitter.cpp

@@ -235,6 +235,24 @@ bool ParticleEmitter::isStarted() const
     return _started;
 }
 
+bool ParticleEmitter::isActive() const
+{
+    if (_started)
+        return true;
+
+    bool active = false;
+    for (unsigned int i = 0; i < _particleCount; i++)
+    {
+        if (_particles[i]._energy > 0)
+        {
+            active = true;
+            break;
+        }
+    }
+
+    return active;
+}
+
 void ParticleEmitter::emit(unsigned int particleCount)
 {
     // Limit particleCount so as not to go over _particleCountMax.
@@ -867,7 +885,8 @@ void ParticleEmitter::draw()
             {
                 Particle* p = &_particles[i];
                 _spriteBatch->draw(p->_position.x, p->_position.y, p->_position.z, p->_size, p->_size,
-                                   _spriteTextureCoords[p->_frame * 4], _spriteTextureCoords[p->_frame * 4 + 1], _spriteTextureCoords[p->_frame * 4 + 2], _spriteTextureCoords[p->_frame * 4 + 3], p->_color);
+                                   _spriteTextureCoords[p->_frame * 4], _spriteTextureCoords[p->_frame * 4 + 1], _spriteTextureCoords[p->_frame * 4 + 2], _spriteTextureCoords[p->_frame * 4 + 3], p->_color,
+                                   true);
             }
         }
         else
@@ -879,7 +898,8 @@ void ParticleEmitter::draw()
             {
                 Particle* p = &_particles[i];
                 _spriteBatch->draw(p->_position, p->_size, p->_size,
-                                   _spriteTextureCoords[p->_frame * 4], _spriteTextureCoords[p->_frame * 4 + 1], _spriteTextureCoords[p->_frame * 4 + 2], _spriteTextureCoords[p->_frame * 4 + 3], p->_color, pivot, p->_angle);
+                                   _spriteTextureCoords[p->_frame * 4], _spriteTextureCoords[p->_frame * 4 + 1], _spriteTextureCoords[p->_frame * 4 + 2], _spriteTextureCoords[p->_frame * 4 + 3], p->_color, pivot, p->_angle,
+                                   true);
             }
         }
 

+ 7 - 0
gameplay/src/ParticleEmitter.h

@@ -212,6 +212,13 @@ public:
      */
     bool isStarted() const;
 
+    /**
+     * Gets whether this ParticleEmitter is currently active (i.e. if any of its particles are alive).
+     * 
+     * @return Whether this ParticleEmitter is currently active.
+     */
+    bool isActive() const;
+
     /**
      * Generates an arbitrary number of particles all at once.  Each newly emitted
      * particle has its properties assigned within the ranges defined by its ParticleEmitter.

+ 38 - 17
gameplay/src/PhysicsController.cpp

@@ -14,6 +14,7 @@ namespace gameplay
 const int PhysicsController::DIRTY         = 0x01;
 const int PhysicsController::COLLISION     = 0x02;
 const int PhysicsController::REGISTERED    = 0x04;
+const int PhysicsController::REMOVE        = 0x08;
 
 PhysicsController::PhysicsController()
   : _collisionConfiguration(NULL), _dispatcher(NULL),
@@ -158,8 +159,11 @@ btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisi
             std::vector<PhysicsRigidBody::Listener*>::const_iterator iter = collisionInfo._listeners.begin();
             for (; iter != collisionInfo._listeners.end(); iter++)
             {
-                (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
-                    Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+                if ((collisionInfo._status & REMOVE) == 0)
+                {
+                    (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                        Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+                }
             }
         }
     }
@@ -167,6 +171,9 @@ btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisi
     {
         CollisionInfo& collisionInfo = _collisionStatus[pair];
 
+        // Initialized the status for the new entry.
+        collisionInfo._status = 0;
+
         // Add the appropriate listeners.
         PhysicsRigidBody::CollisionPair p1(pair._rbA, NULL);
         if (_collisionStatus.count(p1) > 0)
@@ -192,8 +199,11 @@ btScalar PhysicsController::addSingleResult(btManifoldPoint& cp, const btCollisi
         std::vector<PhysicsRigidBody::Listener*>::iterator iter = collisionInfo._listeners.begin();
         for (; iter != collisionInfo._listeners.end(); iter++)
         {
-            (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
-                Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+            if ((collisionInfo._status & REMOVE) == 0)
+            {
+                (*iter)->collisionEvent(PhysicsRigidBody::Listener::COLLIDING, pair, Vector3(cp.getPositionWorldOnA().x(), cp.getPositionWorldOnA().y(), cp.getPositionWorldOnA().z()),
+                    Vector3(cp.getPositionWorldOnB().x(), cp.getPositionWorldOnB().y(), cp.getPositionWorldOnB().z()));
+            }
         }
     }
 
@@ -297,12 +307,24 @@ void PhysicsController::update(long elapsedTime)
     // During collision processing, if a collision occurs, the status is 
     // set to COLLISION and the DIRTY bit is cleared. Then, after collision processing 
     // is finished, if a given status is still dirty, the COLLISION bit is cleared.
+    //
+    // If an entry was marked for removal in the last frame, remove it now.
 
     // Dirty the collision status cache entries.
     std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
-    for (; iter != _collisionStatus.end(); iter++)
+    for (; iter != _collisionStatus.end();)
     {
-        iter->second._status |= DIRTY;
+        if ((iter->second._status & REMOVE) != 0)
+        {
+            std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator eraseIter = iter;
+            iter++;
+            _collisionStatus.erase(eraseIter);
+        }
+        else
+        {
+            iter->second._status |= DIRTY;
+            iter++;
+        }
     }
 
     // Go through the collision status cache and perform all registered collision tests.
@@ -312,7 +334,7 @@ void PhysicsController::update(long elapsedTime)
         // If this collision pair was one that was registered for listening, then perform the collision test.
         // (In the case where we register for all collisions with a rigid body, there will be a lot
         // of collision pairs in the status cache that we did not explicitly register for.)
-        if ((iter->second._status & REGISTERED) != 0)
+        if ((iter->second._status & REGISTERED) != 0 && (iter->second._status & REMOVE) == 0)
         {
             if (iter->first._rbB)
                 _world->contactPairTest(iter->first._rbA->_body, iter->first._rbB->_body, *this);
@@ -343,8 +365,13 @@ void PhysicsController::update(long elapsedTime)
 
 void PhysicsController::addCollisionListener(PhysicsRigidBody::Listener* listener, PhysicsRigidBody* rbA, PhysicsRigidBody* rbB)
 {
-    // Add the listener and ensure the status includes that this collision pair is registered.
     PhysicsRigidBody::CollisionPair pair(rbA, rbB);
+
+    // Make sure the status of the entry is initialized properly.
+    if (_collisionStatus.count(pair) == 0)
+        _collisionStatus[pair]._status = 0;
+
+    // Add the listener and ensure the status includes that this collision pair is registered.
     _collisionStatus[pair]._listeners.push_back(listener);
     if ((_collisionStatus[pair]._status & PhysicsController::REGISTERED) == 0)
         _collisionStatus[pair]._status |= PhysicsController::REGISTERED;
@@ -396,18 +423,12 @@ void PhysicsController::removeRigidBody(PhysicsRigidBody* rigidBody)
         }
     }
 
-    // Find all references to the rigid body in the collision status cache and remove them.
+    // Find all references to the rigid body in the collision status cache and mark them for removal.
     std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator iter = _collisionStatus.begin();
-    for (; iter != _collisionStatus.end();)
+    for (; iter != _collisionStatus.end(); iter++)
     {
         if (iter->first._rbA == rigidBody || iter->first._rbB == rigidBody)
-        {
-            std::map<PhysicsRigidBody::CollisionPair, CollisionInfo>::iterator eraseIter = iter;
-            iter++;
-            _collisionStatus.erase(eraseIter);
-        }
-        else
-            iter++;
+            iter->second._status |= REMOVE;
     }
 }
 

+ 1 - 0
gameplay/src/PhysicsController.h

@@ -210,6 +210,7 @@ private:
     static const int DIRTY;
     static const int COLLISION;
     static const int REGISTERED;
+    static const int REMOVE;
 
     // Represents the collision listeners and status for a given collision pair (used by the collision status cache).
     struct CollisionInfo

+ 1 - 1
gameplay/src/PhysicsRigidBody.h

@@ -217,7 +217,7 @@ public:
      * 
      * @return The node.
      */
-    inline const Node* getNode() const;
+    inline Node* getNode();
 
     /**
      * Gets the rigid body's restitution.

+ 1 - 1
gameplay/src/PhysicsRigidBody.inl

@@ -59,7 +59,7 @@ inline const Vector3& PhysicsRigidBody::getLinearVelocity() const
     return *_linearVelocity;
 }
 
-inline const Node* PhysicsRigidBody::getNode() const
+inline Node* PhysicsRigidBody::getNode()
 {
     return _node;
 }

+ 62 - 10
gameplay/src/SpriteBatch.cpp

@@ -69,6 +69,7 @@ SpriteBatch::SpriteBatch(const SpriteBatch& copy)
 SpriteBatch::~SpriteBatch()
 {
     SAFE_DELETE(_batch);
+    SAFE_RELEASE(__spriteEffect);
 }
 
 SpriteBatch* SpriteBatch::create(const char* texturePath, Effect* effect, unsigned int initialCapacity)
@@ -200,23 +201,33 @@ void SpriteBatch::draw(const Vector3& dst, const Rectangle& src, const Vector2&
 }
 
 void SpriteBatch::draw(const Vector3& dst, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color,
-                       const Vector2& rotationPoint, float rotationAngle)
+                       const Vector2& rotationPoint, float rotationAngle, bool positionIsCenter)
 {
-    // Expand dst by scale into 4 points.
-    float x2 = dst.x + width;
-    float y2 = dst.y + height;
+    float x = dst.x;
+    float y = dst.y;
+
+    // Treat the given position as the center if the user specified it as such.
+    if (positionIsCenter)
+    {
+        x -= 0.5f * width;
+        y -= 0.5f * height;
+    }
+
+    // Expand the destination position by scale into 4 points.
+    float x2 = x + width;
+    float y2 = y + height;
     
-    Vector2 upLeft(dst.x, dst.y);
-    Vector2 upRight(x2, dst.y);
-    Vector2 downLeft(dst.x, y2);
+    Vector2 upLeft(x, y);
+    Vector2 upRight(x2, y);
+    Vector2 downLeft(x, y2);
     Vector2 downRight(x2, y2);
 
     // Rotate points around rotationAxis by rotationAngle.
     Vector2 pivotPoint(rotationPoint);
     pivotPoint.x *= width;
     pivotPoint.y *= height;
-    pivotPoint.x += dst.x;
-    pivotPoint.y += dst.y;
+    pivotPoint.x += x;
+    pivotPoint.y += y;
     upLeft.rotate(pivotPoint, rotationAngle);
     upRight.rotate(pivotPoint, rotationAngle);
     downLeft.rotate(pivotPoint, rotationAngle);
@@ -234,13 +245,54 @@ void SpriteBatch::draw(const Vector3& dst, float width, float height, float u1,
     _batch->add(v, 4, indices, 4);
 }
 
+void SpriteBatch::draw(const Vector3& position, const Vector3& right, const Vector3& forward, float width, float height,
+    float u1, float v1, float u2, float v2, const Vector4& color, const Vector2& rotationPoint, float rotationAngle)
+{
+    // Calculate the vertex positions.
+    Vector3 p[4];
+    p[0] = position - 0.5f * width * right;
+    p[1] = position + 0.5f * width * right;
+    p[2] = p[0] + height * forward;
+    p[3] = p[1] + height * forward;
+
+    // Calculate the rotation point.
+    Vector3 rp = p[0] + (rotationPoint.x * width * right) + (rotationPoint.y * height * forward);
+
+    // Rotate all points the specified amount about the given point (about the up vector).
+    Vector3 u;
+    Vector3::cross(right, forward, &u);
+    Matrix rotation;
+    Matrix::createRotation(u, rotationAngle, &rotation);
+    p[0] = (rotation * (p[0] - rp)) + rp;
+    p[1] = (rotation * (p[1] - rp)) + rp;
+    p[2] = (rotation * (p[2] - rp)) + rp;
+    p[3] = (rotation * (p[3] - rp)) + rp;
+
+    // Add the sprite vertex data to the batch.
+    static SpriteVertex v[4];
+    ADD_SPRITE_VERTEX(v[0], p[0].x, p[0].y, p[0].z, u1, v1, color.x, color.y, color.z, color.w);
+    ADD_SPRITE_VERTEX(v[1], p[1].x, p[1].y, p[1].z, u2, v1, color.x, color.y, color.z, color.w);
+    ADD_SPRITE_VERTEX(v[2], p[2].x, p[2].y, p[2].z, u1, v2, color.x, color.y, color.z, color.w);
+    ADD_SPRITE_VERTEX(v[3], p[3].x, p[3].y, p[3].z, u2, v2, color.x, color.y, color.z, color.w);
+    
+    static const unsigned short indices[4] = { 0, 1, 2, 3 };
+    _batch->add(v, 4, const_cast<unsigned short*>(indices), 4);
+}
+
 void SpriteBatch::draw(float x, float y, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
 {
     draw(x, y, 0, width, height, u1, v1, u2, v2, color);
 }
 
-void SpriteBatch::draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color)
+void SpriteBatch::draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color, bool positionIsCenter)
 {
+    // Treat the given position as the center if the user specified it as such.
+    if (positionIsCenter)
+    {
+        x -= 0.5f * width;
+        y -= 0.5f * height;
+    }
+
     // Write sprite vertex data.
     float x2 = x + width;
     float y2 = y + height;

+ 24 - 2
gameplay/src/SpriteBatch.h

@@ -140,9 +140,30 @@ public:
      * @param rotationPoint The point to rotate around, relative to dst's x and y values.
      *                      (e.g. Use Vector2(0.5f, 0.5f) to rotate around the quad's center.)
      * @param rotationAngle The rotation angle.
+     * @param positionIsCenter Specified whether the given destination is to be the center of the sprite or not (if not, it is treated as the bottom-left).
      */
     void draw(const Vector3& dst, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color,
-              const Vector2& rotationPoint, float rotationAngle);
+              const Vector2& rotationPoint, float rotationAngle, bool positionIsCenter = false);
+    
+    /**
+     * Draws a single sprite, rotated about the implied up vector.
+     * 
+     * @param position The destination position.
+     * @param right The right vector of the sprite quad (should be normalized).
+     * @param forward The forward vector of the sprite quad (should be normalized).
+     * @param width The width of the sprite.
+     * @param height The height of the sprite.
+     * @param u1 Texture coordinate.
+     * @param v1 Texture coordinate.
+     * @param u2 Texture coordinate.
+     * @param v2 Texture coordinate.
+     * @param color The color to tint the sprite. Use white for no tint.
+     * @param rotationPoint The point to rotate around, relative to dst's x and y values.
+     *                      (e.g. Use Vector2(0.5f, 0.5f) to rotate around the quad's center.)
+     * @param rotationAngle The rotation angle.
+     */
+    void draw(const Vector3& position, const Vector3& right, const Vector3& forward, float width, float height, 
+        float u1, float v1, float u2, float v2, const Vector4& color, const Vector2& rotationPoint, float rotationAngle);
 
     /**
      * Draws a single sprite.
@@ -172,8 +193,9 @@ public:
      * @param u2 Texture coordinate.
      * @param v2 Texture coordinate.
      * @param color The color to tint the sprite. Use white for no tint.
+     * @param positionIsCenter Specified whether the given destination is to be the center of the sprite or not (if not, it is treated as the bottom-left).
      */
-    void draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color);
+    void draw(float x, float y, float z, float width, float height, float u1, float v1, float u2, float v2, const Vector4& color, bool positionIsCenter = false);
 
     /**
      * Ends sprite drawing.