PhysicsCollisionObject.cpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. #include "Base.h"
  2. #include "PhysicsCollisionObject.h"
  3. #include "PhysicsController.h"
  4. #include "Game.h"
  5. #include "Node.h"
  6. #include "ScriptListener.h"
  7. namespace gameplay
  8. {
  9. /**
  10. * Internal class used to implement the collidesWith(PhysicsCollisionObject*) function.
  11. * @script{ignore}
  12. */
  13. struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
  14. {
  15. /**
  16. * Called with each contact. Needed to implement collidesWith(PhysicsCollisionObject*).
  17. */
  18. btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* a, int partIdA, int indexA, const btCollisionObject* b, int partIdB, int indexB)
  19. {
  20. result = true;
  21. return 0.0f;
  22. }
  23. /**
  24. * The result of the callback.
  25. */
  26. bool result;
  27. };
  28. PhysicsCollisionObject::PhysicsCollisionObject(Node* node)
  29. : _node(node), _motionState(NULL), _collisionShape(NULL), _enabled(true), _scriptListeners(NULL)
  30. {
  31. }
  32. PhysicsCollisionObject::~PhysicsCollisionObject()
  33. {
  34. SAFE_DELETE(_motionState);
  35. if (_scriptListeners)
  36. {
  37. for (unsigned int i = 0; i < _scriptListeners->size(); i++)
  38. {
  39. SAFE_DELETE((*_scriptListeners)[i]);
  40. }
  41. SAFE_DELETE(_scriptListeners);
  42. }
  43. GP_ASSERT(Game::getInstance()->getPhysicsController());
  44. Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
  45. }
  46. PhysicsCollisionShape::Type PhysicsCollisionObject::getShapeType() const
  47. {
  48. GP_ASSERT(getCollisionShape());
  49. return getCollisionShape()->getType();
  50. }
  51. Node* PhysicsCollisionObject::getNode() const
  52. {
  53. return _node;
  54. }
  55. PhysicsCollisionShape* PhysicsCollisionObject::getCollisionShape() const
  56. {
  57. return _collisionShape;
  58. }
  59. bool PhysicsCollisionObject::isKinematic() const
  60. {
  61. switch (getType())
  62. {
  63. case GHOST_OBJECT:
  64. case CHARACTER:
  65. return true;
  66. default:
  67. GP_ASSERT(getCollisionObject());
  68. return getCollisionObject()->isKinematicObject();
  69. }
  70. }
  71. bool PhysicsCollisionObject::isDynamic() const
  72. {
  73. GP_ASSERT(getCollisionObject());
  74. return !getCollisionObject()->isStaticOrKinematicObject();
  75. }
  76. bool PhysicsCollisionObject::isEnabled() const
  77. {
  78. return _enabled;
  79. }
  80. void PhysicsCollisionObject::setEnabled(bool enable)
  81. {
  82. if (enable)
  83. {
  84. if (!_enabled)
  85. {
  86. Game::getInstance()->getPhysicsController()->addCollisionObject(this);
  87. _motionState->updateTransformFromNode();
  88. _enabled = true;
  89. }
  90. }
  91. else
  92. {
  93. if (_enabled)
  94. {
  95. Game::getInstance()->getPhysicsController()->removeCollisionObject(this, false);
  96. _enabled = false;
  97. }
  98. }
  99. }
  100. void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
  101. {
  102. GP_ASSERT(Game::getInstance()->getPhysicsController());
  103. Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, object);
  104. }
  105. void PhysicsCollisionObject::removeCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
  106. {
  107. GP_ASSERT(Game::getInstance()->getPhysicsController());
  108. Game::getInstance()->getPhysicsController()->removeCollisionListener(listener, this, object);
  109. }
  110. void PhysicsCollisionObject::addCollisionListener(const char* function, PhysicsCollisionObject* object)
  111. {
  112. if (!_scriptListeners)
  113. _scriptListeners = new std::vector<ScriptListener*>();
  114. ScriptListener* listener = new ScriptListener(function);
  115. _scriptListeners->push_back(listener);
  116. addCollisionListener(listener, object);
  117. }
  118. void PhysicsCollisionObject::removeCollisionListener(const char* function, PhysicsCollisionObject* object)
  119. {
  120. if (!_scriptListeners)
  121. return;
  122. std::string functionStr = function;
  123. for (unsigned int i = 0; i < _scriptListeners->size(); i++)
  124. {
  125. if ((*_scriptListeners)[i]->_function == functionStr)
  126. {
  127. removeCollisionListener((*_scriptListeners)[i], object);
  128. SAFE_DELETE((*_scriptListeners)[i]);
  129. _scriptListeners->erase(_scriptListeners->begin() + i);
  130. return;
  131. }
  132. }
  133. }
  134. bool PhysicsCollisionObject::collidesWith(PhysicsCollisionObject* object) const
  135. {
  136. GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
  137. GP_ASSERT(object && object->getCollisionObject());
  138. GP_ASSERT(getCollisionObject());
  139. static CollidesWithCallback callback;
  140. callback.result = false;
  141. Game::getInstance()->getPhysicsController()->_world->contactPairTest(getCollisionObject(), object->getCollisionObject(), callback);
  142. return callback.result;
  143. }
  144. PhysicsCollisionObject::CollisionPair::CollisionPair(PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
  145. : objectA(objectA), objectB(objectB)
  146. {
  147. // unused
  148. }
  149. bool PhysicsCollisionObject::CollisionPair::operator < (const CollisionPair& collisionPair) const
  150. {
  151. // If the pairs are equal, then return false.
  152. if ((objectA == collisionPair.objectA && objectB == collisionPair.objectB) || (objectA == collisionPair.objectB && objectB == collisionPair.objectA))
  153. return false;
  154. // We choose to compare based on objectA arbitrarily.
  155. if (objectA < collisionPair.objectA)
  156. return true;
  157. if (objectA == collisionPair.objectA)
  158. return objectB < collisionPair.objectB;
  159. return false;
  160. }
  161. PhysicsCollisionObject::PhysicsMotionState::PhysicsMotionState(Node* node, const Vector3* centerOfMassOffset) : _node(node),
  162. _centerOfMassOffset(btTransform::getIdentity())
  163. {
  164. if (centerOfMassOffset)
  165. {
  166. // Store the center of mass offset.
  167. _centerOfMassOffset.setOrigin(BV(*centerOfMassOffset));
  168. }
  169. updateTransformFromNode();
  170. }
  171. PhysicsCollisionObject::PhysicsMotionState::~PhysicsMotionState()
  172. {
  173. }
  174. void PhysicsCollisionObject::PhysicsMotionState::getWorldTransform(btTransform &transform) const
  175. {
  176. GP_ASSERT(_node);
  177. if (_node->getCollisionObject() && _node->getCollisionObject()->isKinematic())
  178. updateTransformFromNode();
  179. transform = _centerOfMassOffset.inverse() * _worldTransform;
  180. }
  181. void PhysicsCollisionObject::PhysicsMotionState::setWorldTransform(const btTransform &transform)
  182. {
  183. GP_ASSERT(_node);
  184. _worldTransform = transform * _centerOfMassOffset;
  185. const btQuaternion& rot = _worldTransform.getRotation();
  186. const btVector3& pos = _worldTransform.getOrigin();
  187. _node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
  188. _node->setTranslation(pos.x(), pos.y(), pos.z());
  189. }
  190. void PhysicsCollisionObject::PhysicsMotionState::updateTransformFromNode() const
  191. {
  192. GP_ASSERT(_node);
  193. // Store the initial world transform (minus the scale) for use by Bullet later on.
  194. Quaternion rotation;
  195. const Matrix& m = _node->getWorldMatrix();
  196. m.getRotation(&rotation);
  197. if (!_centerOfMassOffset.getOrigin().isZero())
  198. {
  199. // When there is a center of mass offset, we modify the initial world transformation
  200. // so that when physics is initially applied, the object is in the correct location.
  201. btTransform offset = btTransform(BQ(rotation), btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
  202. btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(),
  203. m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(),
  204. m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
  205. _worldTransform = btTransform(BQ(rotation), origin);
  206. }
  207. else
  208. {
  209. _worldTransform = btTransform(BQ(rotation), btVector3(m.m[12], m.m[13], m.m[14]));
  210. }
  211. }
  212. }