PhysicsCollisionObject.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #include "Base.h"
  2. #include "PhysicsCollisionObject.h"
  3. #include "PhysicsController.h"
  4. #include "Game.h"
  5. #include "Node.h"
  6. #include "ScriptController.h"
  7. #include "PhysicsRigidBody.h"
  8. #include "PhysicsCharacter.h"
  9. #include "PhysicsGhostObject.h"
  10. #include "PhysicsVehicle.h"
  11. #include "PhysicsVehicleWheel.h"
  12. namespace gameplay
  13. {
  14. extern void splitURL(const std::string& url, std::string* file, std::string* id);
  15. /**
  16. * Internal class used to implement the collidesWith(PhysicsCollisionObject*) function.
  17. * @script{ignore}
  18. */
  19. struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
  20. {
  21. /**
  22. * Called with each contact. Needed to implement collidesWith(PhysicsCollisionObject*).
  23. */
  24. btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* a, int partIdA, int indexA, const btCollisionObjectWrapper* b, int partIdB, int indexB)
  25. {
  26. result = true;
  27. return 0.0f;
  28. }
  29. /**
  30. * The result of the callback.
  31. */
  32. bool result;
  33. };
  34. PhysicsCollisionObject::PhysicsCollisionObject(Node* node, int group, int mask)
  35. : _node(node), _collisionShape(NULL), _enabled(true), _scriptListeners(NULL), _motionState(NULL), _group(group), _mask(mask)
  36. {
  37. }
  38. PhysicsCollisionObject::~PhysicsCollisionObject()
  39. {
  40. SAFE_DELETE(_motionState);
  41. if (_scriptListeners)
  42. {
  43. for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
  44. {
  45. SAFE_DELETE((*_scriptListeners)[i]);
  46. }
  47. SAFE_DELETE(_scriptListeners);
  48. }
  49. GP_ASSERT(Game::getInstance()->getPhysicsController());
  50. Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
  51. }
  52. PhysicsCollisionShape::Type PhysicsCollisionObject::getShapeType() const
  53. {
  54. GP_ASSERT(getCollisionShape());
  55. return getCollisionShape()->getType();
  56. }
  57. Node* PhysicsCollisionObject::getNode() const
  58. {
  59. return _node;
  60. }
  61. PhysicsCollisionShape* PhysicsCollisionObject::getCollisionShape() const
  62. {
  63. return _collisionShape;
  64. }
  65. bool PhysicsCollisionObject::isKinematic() const
  66. {
  67. switch (getType())
  68. {
  69. case GHOST_OBJECT:
  70. case CHARACTER:
  71. return true;
  72. default:
  73. GP_ASSERT(getCollisionObject());
  74. return getCollisionObject()->isKinematicObject();
  75. }
  76. }
  77. bool PhysicsCollisionObject::isStatic() const
  78. {
  79. switch (getType())
  80. {
  81. case GHOST_OBJECT:
  82. case CHARACTER:
  83. return false;
  84. default:
  85. GP_ASSERT(getCollisionObject());
  86. return getCollisionObject()->isStaticObject();
  87. }
  88. }
  89. bool PhysicsCollisionObject::isDynamic() const
  90. {
  91. GP_ASSERT(getCollisionObject());
  92. return !getCollisionObject()->isStaticOrKinematicObject();
  93. }
  94. bool PhysicsCollisionObject::isEnabled() const
  95. {
  96. return _enabled;
  97. }
  98. void PhysicsCollisionObject::setEnabled(bool enable)
  99. {
  100. if (enable)
  101. {
  102. if (!_enabled)
  103. {
  104. Game::getInstance()->getPhysicsController()->addCollisionObject(this);
  105. _motionState->updateTransformFromNode();
  106. _enabled = true;
  107. }
  108. }
  109. else
  110. {
  111. if (_enabled)
  112. {
  113. Game::getInstance()->getPhysicsController()->removeCollisionObject(this, false);
  114. _enabled = false;
  115. }
  116. }
  117. }
  118. void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
  119. {
  120. GP_ASSERT(Game::getInstance()->getPhysicsController());
  121. Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, object);
  122. }
  123. void PhysicsCollisionObject::removeCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
  124. {
  125. GP_ASSERT(Game::getInstance()->getPhysicsController());
  126. Game::getInstance()->getPhysicsController()->removeCollisionListener(listener, this, object);
  127. }
  128. void PhysicsCollisionObject::addCollisionListener(const char* function, PhysicsCollisionObject* object)
  129. {
  130. ScriptListener* listener = ScriptListener::create(function);
  131. if (!listener)
  132. return; // falied to load
  133. if (!_scriptListeners)
  134. _scriptListeners = new std::vector<ScriptListener*>();
  135. _scriptListeners->push_back(listener);
  136. addCollisionListener(listener, object);
  137. }
  138. void PhysicsCollisionObject::removeCollisionListener(const char* function, PhysicsCollisionObject* object)
  139. {
  140. if (!_scriptListeners)
  141. return;
  142. std::string url = function;
  143. for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
  144. {
  145. if ((*_scriptListeners)[i]->url == url)
  146. {
  147. removeCollisionListener((*_scriptListeners)[i], object);
  148. SAFE_DELETE((*_scriptListeners)[i]);
  149. _scriptListeners->erase(_scriptListeners->begin() + i);
  150. return;
  151. }
  152. }
  153. }
  154. bool PhysicsCollisionObject::collidesWith(PhysicsCollisionObject* object) const
  155. {
  156. GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
  157. GP_ASSERT(object && object->getCollisionObject());
  158. GP_ASSERT(getCollisionObject());
  159. static CollidesWithCallback callback;
  160. callback.result = false;
  161. Game::getInstance()->getPhysicsController()->_world->contactPairTest(getCollisionObject(), object->getCollisionObject(), callback);
  162. return callback.result;
  163. }
  164. PhysicsRigidBody* PhysicsCollisionObject::asRigidBody()
  165. {
  166. return getType() == RIGID_BODY ? static_cast<PhysicsRigidBody*>(this) : NULL;
  167. }
  168. PhysicsCharacter* PhysicsCollisionObject::asCharacter()
  169. {
  170. return getType() == CHARACTER ? static_cast<PhysicsCharacter*>(this) : NULL;
  171. }
  172. PhysicsGhostObject* PhysicsCollisionObject::asGhostObject()
  173. {
  174. return getType() == GHOST_OBJECT ? static_cast<PhysicsGhostObject*>(this) : NULL;
  175. }
  176. PhysicsVehicle* PhysicsCollisionObject::asVehicle()
  177. {
  178. return getType() == VEHICLE ? static_cast<PhysicsVehicle*>(this) : NULL;
  179. }
  180. PhysicsVehicleWheel* PhysicsCollisionObject::asVehicleWheel()
  181. {
  182. return getType() == VEHICLE_WHEEL ? static_cast<PhysicsVehicleWheel*>(this) : NULL;
  183. }
  184. PhysicsCollisionObject::CollisionPair::CollisionPair(PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
  185. : objectA(objectA), objectB(objectB)
  186. {
  187. // unused
  188. }
  189. bool PhysicsCollisionObject::CollisionPair::operator < (const CollisionPair& collisionPair) const
  190. {
  191. // If the pairs are equal, then return false.
  192. if ((objectA == collisionPair.objectA && objectB == collisionPair.objectB) || (objectA == collisionPair.objectB && objectB == collisionPair.objectA))
  193. return false;
  194. // We choose to compare based on objectA arbitrarily.
  195. if (objectA < collisionPair.objectA)
  196. return true;
  197. if (objectA == collisionPair.objectA)
  198. return objectB < collisionPair.objectB;
  199. return false;
  200. }
  201. PhysicsCollisionObject::PhysicsMotionState::PhysicsMotionState(Node* node, PhysicsCollisionObject* collisionObject, const Vector3* centerOfMassOffset) :
  202. _node(node), _collisionObject(collisionObject), _centerOfMassOffset(btTransform::getIdentity())
  203. {
  204. if (centerOfMassOffset)
  205. {
  206. // Store the center of mass offset.
  207. _centerOfMassOffset.setOrigin(BV(*centerOfMassOffset));
  208. }
  209. updateTransformFromNode();
  210. }
  211. PhysicsCollisionObject::PhysicsMotionState::~PhysicsMotionState()
  212. {
  213. }
  214. void PhysicsCollisionObject::PhysicsMotionState::getWorldTransform(btTransform &transform) const
  215. {
  216. GP_ASSERT(_node);
  217. GP_ASSERT(_collisionObject);
  218. if (_collisionObject->isKinematic())
  219. updateTransformFromNode();
  220. transform = _centerOfMassOffset.inverse() * _worldTransform;
  221. }
  222. void PhysicsCollisionObject::PhysicsMotionState::setWorldTransform(const btTransform &transform)
  223. {
  224. GP_ASSERT(_node);
  225. _worldTransform = transform * _centerOfMassOffset;
  226. const btQuaternion& rot = _worldTransform.getRotation();
  227. const btVector3& pos = _worldTransform.getOrigin();
  228. _node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
  229. _node->setTranslation(pos.x(), pos.y(), pos.z());
  230. }
  231. void PhysicsCollisionObject::PhysicsMotionState::updateTransformFromNode() const
  232. {
  233. GP_ASSERT(_node);
  234. // Store the initial world transform (minus the scale) for use by Bullet later on.
  235. Quaternion rotation;
  236. const Matrix& m = _node->getWorldMatrix();
  237. m.getRotation(&rotation);
  238. if (!_centerOfMassOffset.getOrigin().isZero())
  239. {
  240. // When there is a center of mass offset, we modify the initial world transformation
  241. // so that when physics is initially applied, the object is in the correct location.
  242. btTransform offset = btTransform(BQ(rotation), btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
  243. btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(),
  244. m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(),
  245. m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
  246. _worldTransform = btTransform(BQ(rotation), origin);
  247. }
  248. else
  249. {
  250. _worldTransform = btTransform(BQ(rotation), btVector3(m.m[12], m.m[13], m.m[14]));
  251. }
  252. }
  253. void PhysicsCollisionObject::PhysicsMotionState::setCenterOfMassOffset(const Vector3& centerOfMassOffset)
  254. {
  255. _centerOfMassOffset.setOrigin(BV(centerOfMassOffset));
  256. }
  257. PhysicsCollisionObject::ScriptListener::ScriptListener()
  258. : script(NULL)
  259. {
  260. }
  261. PhysicsCollisionObject::ScriptListener::~ScriptListener()
  262. {
  263. SAFE_RELEASE(script);
  264. }
  265. PhysicsCollisionObject::ScriptListener* PhysicsCollisionObject::ScriptListener::create(const char* url)
  266. {
  267. std::string scriptPath, func;
  268. splitURL(url, &scriptPath, &func);
  269. if (func.empty())
  270. {
  271. // Only a function was specified
  272. func = scriptPath;
  273. scriptPath = "";
  274. }
  275. Script* script = NULL;
  276. if (!scriptPath.empty())
  277. {
  278. script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
  279. if (!script)
  280. {
  281. // Failed to load script
  282. return NULL;
  283. }
  284. }
  285. ScriptListener* listener = new ScriptListener();
  286. listener->url = url;
  287. listener->script = script;
  288. listener->function = func;
  289. return listener;
  290. }
  291. void PhysicsCollisionObject::ScriptListener::collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,
  292. const PhysicsCollisionObject::CollisionPair& collisionPair, const Vector3& contactPointA, const Vector3& contactPointB)
  293. {
  294. Game::getInstance()->getScriptController()->executeFunction<void>(function.c_str(),
  295. "[PhysicsCollisionObject::CollisionListener::EventType]<PhysicsCollisionObject::CollisionPair><Vector3><Vector3>",
  296. type, &collisionPair, &contactPointA, &contactPointB);
  297. }
  298. }