| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- #include "Base.h"
- #include "PhysicsCollisionObject.h"
- #include "PhysicsController.h"
- #include "Game.h"
- #include "Node.h"
- #include "ScriptController.h"
- #include "PhysicsRigidBody.h"
- #include "PhysicsCharacter.h"
- #include "PhysicsGhostObject.h"
- #include "PhysicsVehicle.h"
- #include "PhysicsVehicleWheel.h"
- namespace gameplay
- {
- extern void splitURL(const std::string& url, std::string* file, std::string* id);
- /**
- * Internal class used to implement the collidesWith(PhysicsCollisionObject*) function.
- * @script{ignore}
- */
- struct CollidesWithCallback : public btCollisionWorld::ContactResultCallback
- {
- /**
- * Called with each contact. Needed to implement collidesWith(PhysicsCollisionObject*).
- */
- btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* a, int partIdA, int indexA, const btCollisionObjectWrapper* b, int partIdB, int indexB)
- {
- result = true;
- return 0.0f;
- }
- /**
- * The result of the callback.
- */
- bool result;
- };
- PhysicsCollisionObject::PhysicsCollisionObject(Node* node, int group, int mask)
- : _node(node), _collisionShape(NULL), _enabled(true), _scriptListeners(NULL), _motionState(NULL), _group(group), _mask(mask)
- {
- }
- PhysicsCollisionObject::~PhysicsCollisionObject()
- {
- SAFE_DELETE(_motionState);
- if (_scriptListeners)
- {
- for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
- {
- SAFE_DELETE((*_scriptListeners)[i]);
- }
- SAFE_DELETE(_scriptListeners);
- }
- GP_ASSERT(Game::getInstance()->getPhysicsController());
- Game::getInstance()->getPhysicsController()->destroyShape(_collisionShape);
- }
- PhysicsCollisionShape::Type PhysicsCollisionObject::getShapeType() const
- {
- GP_ASSERT(getCollisionShape());
- return getCollisionShape()->getType();
- }
- Node* PhysicsCollisionObject::getNode() const
- {
- return _node;
- }
- PhysicsCollisionShape* PhysicsCollisionObject::getCollisionShape() const
- {
- return _collisionShape;
- }
- bool PhysicsCollisionObject::isKinematic() const
- {
- switch (getType())
- {
- case GHOST_OBJECT:
- case CHARACTER:
- return true;
- default:
- GP_ASSERT(getCollisionObject());
- return getCollisionObject()->isKinematicObject();
- }
- }
- bool PhysicsCollisionObject::isStatic() const
- {
- switch (getType())
- {
- case GHOST_OBJECT:
- case CHARACTER:
- return false;
- default:
- GP_ASSERT(getCollisionObject());
- return getCollisionObject()->isStaticObject();
- }
- }
- bool PhysicsCollisionObject::isDynamic() const
- {
- GP_ASSERT(getCollisionObject());
- return !getCollisionObject()->isStaticOrKinematicObject();
- }
- bool PhysicsCollisionObject::isEnabled() const
- {
- return _enabled;
- }
- void PhysicsCollisionObject::setEnabled(bool enable)
- {
- if (enable)
- {
- if (!_enabled)
- {
- Game::getInstance()->getPhysicsController()->addCollisionObject(this);
- _motionState->updateTransformFromNode();
- _enabled = true;
- }
- }
- else
- {
- if (_enabled)
- {
- Game::getInstance()->getPhysicsController()->removeCollisionObject(this, false);
- _enabled = false;
- }
- }
- }
- void PhysicsCollisionObject::addCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
- {
- GP_ASSERT(Game::getInstance()->getPhysicsController());
- Game::getInstance()->getPhysicsController()->addCollisionListener(listener, this, object);
- }
- void PhysicsCollisionObject::removeCollisionListener(CollisionListener* listener, PhysicsCollisionObject* object)
- {
- GP_ASSERT(Game::getInstance()->getPhysicsController());
- Game::getInstance()->getPhysicsController()->removeCollisionListener(listener, this, object);
- }
- void PhysicsCollisionObject::addCollisionListener(const char* function, PhysicsCollisionObject* object)
- {
- ScriptListener* listener = ScriptListener::create(function);
- if (!listener)
- return; // falied to load
- if (!_scriptListeners)
- _scriptListeners = new std::vector<ScriptListener*>();
- _scriptListeners->push_back(listener);
- addCollisionListener(listener, object);
- }
- void PhysicsCollisionObject::removeCollisionListener(const char* function, PhysicsCollisionObject* object)
- {
- if (!_scriptListeners)
- return;
- std::string url = function;
- for (size_t i = 0, count = _scriptListeners->size(); i < count; ++i)
- {
- if ((*_scriptListeners)[i]->url == url)
- {
- removeCollisionListener((*_scriptListeners)[i], object);
- SAFE_DELETE((*_scriptListeners)[i]);
- _scriptListeners->erase(_scriptListeners->begin() + i);
- return;
- }
- }
- }
- bool PhysicsCollisionObject::collidesWith(PhysicsCollisionObject* object) const
- {
- GP_ASSERT(Game::getInstance()->getPhysicsController() && Game::getInstance()->getPhysicsController()->_world);
- GP_ASSERT(object && object->getCollisionObject());
- GP_ASSERT(getCollisionObject());
- static CollidesWithCallback callback;
- callback.result = false;
- Game::getInstance()->getPhysicsController()->_world->contactPairTest(getCollisionObject(), object->getCollisionObject(), callback);
- return callback.result;
- }
- PhysicsRigidBody* PhysicsCollisionObject::asRigidBody()
- {
- return getType() == RIGID_BODY ? static_cast<PhysicsRigidBody*>(this) : NULL;
- }
- PhysicsCharacter* PhysicsCollisionObject::asCharacter()
- {
- return getType() == CHARACTER ? static_cast<PhysicsCharacter*>(this) : NULL;
- }
- PhysicsGhostObject* PhysicsCollisionObject::asGhostObject()
- {
- return getType() == GHOST_OBJECT ? static_cast<PhysicsGhostObject*>(this) : NULL;
- }
- PhysicsVehicle* PhysicsCollisionObject::asVehicle()
- {
- return getType() == VEHICLE ? static_cast<PhysicsVehicle*>(this) : NULL;
- }
- PhysicsVehicleWheel* PhysicsCollisionObject::asVehicleWheel()
- {
- return getType() == VEHICLE_WHEEL ? static_cast<PhysicsVehicleWheel*>(this) : NULL;
- }
- PhysicsCollisionObject::CollisionPair::CollisionPair(PhysicsCollisionObject* objectA, PhysicsCollisionObject* objectB)
- : objectA(objectA), objectB(objectB)
- {
- // unused
- }
- bool PhysicsCollisionObject::CollisionPair::operator < (const CollisionPair& collisionPair) const
- {
- // If the pairs are equal, then return false.
- if ((objectA == collisionPair.objectA && objectB == collisionPair.objectB) || (objectA == collisionPair.objectB && objectB == collisionPair.objectA))
- return false;
- // We choose to compare based on objectA arbitrarily.
- if (objectA < collisionPair.objectA)
- return true;
- if (objectA == collisionPair.objectA)
- return objectB < collisionPair.objectB;
- return false;
- }
- PhysicsCollisionObject::PhysicsMotionState::PhysicsMotionState(Node* node, PhysicsCollisionObject* collisionObject, const Vector3* centerOfMassOffset) :
- _node(node), _collisionObject(collisionObject), _centerOfMassOffset(btTransform::getIdentity())
- {
- if (centerOfMassOffset)
- {
- // Store the center of mass offset.
- _centerOfMassOffset.setOrigin(BV(*centerOfMassOffset));
- }
- updateTransformFromNode();
- }
- PhysicsCollisionObject::PhysicsMotionState::~PhysicsMotionState()
- {
- }
- void PhysicsCollisionObject::PhysicsMotionState::getWorldTransform(btTransform &transform) const
- {
- GP_ASSERT(_node);
- GP_ASSERT(_collisionObject);
- if (_collisionObject->isKinematic())
- updateTransformFromNode();
- transform = _centerOfMassOffset.inverse() * _worldTransform;
- }
- void PhysicsCollisionObject::PhysicsMotionState::setWorldTransform(const btTransform &transform)
- {
- GP_ASSERT(_node);
- _worldTransform = transform * _centerOfMassOffset;
-
- const btQuaternion& rot = _worldTransform.getRotation();
- const btVector3& pos = _worldTransform.getOrigin();
- _node->setRotation(rot.x(), rot.y(), rot.z(), rot.w());
- _node->setTranslation(pos.x(), pos.y(), pos.z());
- }
- void PhysicsCollisionObject::PhysicsMotionState::updateTransformFromNode() const
- {
- GP_ASSERT(_node);
- // Store the initial world transform (minus the scale) for use by Bullet later on.
- Quaternion rotation;
- const Matrix& m = _node->getWorldMatrix();
- m.getRotation(&rotation);
- if (!_centerOfMassOffset.getOrigin().isZero())
- {
- // When there is a center of mass offset, we modify the initial world transformation
- // so that when physics is initially applied, the object is in the correct location.
- btTransform offset = btTransform(BQ(rotation), btVector3(0.0f, 0.0f, 0.0f)) * _centerOfMassOffset.inverse();
- btVector3 origin(m.m[12] + _centerOfMassOffset.getOrigin().getX() + offset.getOrigin().getX(),
- m.m[13] + _centerOfMassOffset.getOrigin().getY() + offset.getOrigin().getY(),
- m.m[14] + _centerOfMassOffset.getOrigin().getZ() + offset.getOrigin().getZ());
- _worldTransform = btTransform(BQ(rotation), origin);
- }
- else
- {
- _worldTransform = btTransform(BQ(rotation), btVector3(m.m[12], m.m[13], m.m[14]));
- }
- }
- void PhysicsCollisionObject::PhysicsMotionState::setCenterOfMassOffset(const Vector3& centerOfMassOffset)
- {
- _centerOfMassOffset.setOrigin(BV(centerOfMassOffset));
- }
- PhysicsCollisionObject::ScriptListener::ScriptListener()
- : script(NULL)
- {
- }
- PhysicsCollisionObject::ScriptListener::~ScriptListener()
- {
- SAFE_RELEASE(script);
- }
- PhysicsCollisionObject::ScriptListener* PhysicsCollisionObject::ScriptListener::create(const char* url)
- {
- std::string scriptPath, func;
- splitURL(url, &scriptPath, &func);
- if (func.empty())
- {
- // Only a function was specified
- func = scriptPath;
- scriptPath = "";
- }
- Script* script = NULL;
- if (!scriptPath.empty())
- {
- script = Game::getInstance()->getScriptController()->loadScript(scriptPath.c_str(), Script::GLOBAL);
- if (!script)
- {
- // Failed to load script
- return NULL;
- }
- }
- ScriptListener* listener = new ScriptListener();
- listener->url = url;
- listener->script = script;
- listener->function = func;
- return listener;
- }
- void PhysicsCollisionObject::ScriptListener::collisionEvent(PhysicsCollisionObject::CollisionListener::EventType type,
- const PhysicsCollisionObject::CollisionPair& collisionPair, const Vector3& contactPointA, const Vector3& contactPointB)
- {
- Game::getInstance()->getScriptController()->executeFunction<void>(function.c_str(),
- "[PhysicsCollisionObject::CollisionListener::EventType]<PhysicsCollisionObject::CollisionPair><Vector3><Vector3>",
- type, &collisionPair, &contactPointA, &contactPointB);
- }
- }
|