| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- #include "Base.h"
- #include "Game.h"
- #include "MathUtil.h"
- #include "Node.h"
- #include "PhysicsVehicle.h"
- #include "PhysicsVehicleWheel.h"
- #define AIR_DENSITY (1.2f)
- #define KPH_TO_MPS (1.0f / 3.6f)
- namespace gameplay
- {
- /**
- * The default vehicle raycaster in Bullet currently does not filter out the vehicle's own
- * rigid body from the ray test which can result in unexpected behavior. These implementations
- * are intended to fix that.
- *
- * @script{ignore}
- */
- class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
- {
- public:
- ClosestNotMeRayResultCallback(const btVector3& from, const btVector3& to, btCollisionObject* me)
- : btCollisionWorld::ClosestRayResultCallback(from, to), _me(me)
- {
- }
- btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
- {
- if (rayResult.m_collisionObject == _me)
- return 1.0f;
- return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
- }
- private:
- btCollisionObject* _me;
- };
- /**
- * @script{ignore}
- */
- class VehicleNotMeRaycaster : public btVehicleRaycaster
- {
- public:
- VehicleNotMeRaycaster(btDynamicsWorld* world, btCollisionObject* me)
- : _dynamicsWorld(world), _me(me)
- {
- }
- void* castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result)
- {
- ClosestNotMeRayResultCallback rayCallback(from, to, _me);
- _dynamicsWorld->rayTest(from, to, rayCallback);
- if (rayCallback.hasHit())
- {
- const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
- if (body && body->hasContactResponse())
- {
- result.m_hitPointInWorld = rayCallback.m_hitPointWorld;
- result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld;
- result.m_hitNormalInWorld.normalize();
- result.m_distFraction = rayCallback.m_closestHitFraction;
- return (void*)body;
- }
- }
- return 0;
- }
- private:
- btDynamicsWorld* _dynamicsWorld;
- btCollisionObject* _me;
- };
- PhysicsVehicle::PhysicsVehicle(Node* node, const PhysicsCollisionShape::Definition& shape, const PhysicsRigidBody::Parameters& parameters)
- : PhysicsCollisionObject(node), _speedSmoothed(0)
- {
- // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
- // that is where the rigid body gets added to the dynamics world.
- _rigidBody = new PhysicsRigidBody(node, shape, parameters);
- initialize();
- }
- PhysicsVehicle::PhysicsVehicle(Node* node, PhysicsRigidBody* rigidBody)
- : PhysicsCollisionObject(node), _speedSmoothed(0)
- {
- _rigidBody = rigidBody;
- initialize();
- }
- PhysicsVehicle* PhysicsVehicle::create(Node* node, Properties* properties)
- {
- // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
- // that is where the rigid body gets added to the dynamics world.
- PhysicsRigidBody* rigidBody = PhysicsRigidBody::create(node, properties, "VEHICLE");
- PhysicsVehicle* vehicle = new PhysicsVehicle(node, rigidBody);
- // Load the defined vehicle parameters.
- properties->rewind();
- const char* name;
- while ((name = properties->getNextProperty()) != NULL)
- {
- if (strcmp(name, "steeringGain") == 0)
- {
- vehicle->setSteeringGain(properties->getFloat());
- }
- else if (strcmp(name, "brakingForce") == 0)
- {
- vehicle->setBrakingForce(properties->getFloat());
- }
- else if (strcmp(name, "drivingForce") == 0)
- {
- vehicle->setDrivingForce(properties->getFloat());
- }
- else if (strcmp(name, "steerdownSpeed") == 0)
- {
- vehicle->_steerdownSpeed = properties->getFloat();
- }
- else if (strcmp(name, "steerdownGain") == 0)
- {
- vehicle->_steerdownGain = properties->getFloat();
- }
- else if (strcmp(name, "brakedownStart") == 0)
- {
- vehicle->_brakedownStart = properties->getFloat();
- }
- else if (strcmp(name, "brakedownFull") == 0)
- {
- vehicle->_brakedownFull = properties->getFloat();
- }
- else if (strcmp(name, "drivedownStart") == 0)
- {
- vehicle->_drivedownStart = properties->getFloat();
- }
- else if (strcmp(name, "drivedownFull") == 0)
- {
- vehicle->_drivedownFull = properties->getFloat();
- }
- else if (strcmp(name, "boostSpeed") == 0)
- {
- vehicle->_boostSpeed = properties->getFloat();
- }
- else if (strcmp(name, "boostGain") == 0)
- {
- vehicle->_boostGain = properties->getFloat();
- }
- else if (strcmp(name, "downforce") == 0)
- {
- vehicle->_downforce = properties->getFloat();
- }
- else
- {
- // Ignore this case (we've already parsed the rigid body parameters).
- }
- }
- return vehicle;
- }
- void PhysicsVehicle::initialize()
- {
- GP_ASSERT(getNode());
- // Safe default values
- setSteeringGain(0.5f);
- setBrakingForce(350.0f);
- setDrivingForce(2000.0f);
- setSteerdown(0, 1);
- setBrakedown(1000, 0);
- setDrivedown(1000, 0);
- setBoost(0, 1);
- setDownforce(0);
- // Create the vehicle and add it to world
- btRigidBody* body = static_cast<btRigidBody*>(_rigidBody->getCollisionObject());
- btDynamicsWorld* dynamicsWorld = Game::getInstance()->getPhysicsController()->_world;
- _vehicleRaycaster = new VehicleNotMeRaycaster(dynamicsWorld, body);
- _vehicle = bullet_new<btRaycastVehicle>(_vehicleTuning, body, _vehicleRaycaster);
- body->setActivationState(DISABLE_DEACTIVATION);
- dynamicsWorld->addVehicle(_vehicle);
- _vehicle->setCoordinateSystem(0, 1, 2);
- // Advertise self among ancestor nodes so that wheels can bind to self.
- // See PhysicsVehicleWheel and Node for more details.
- for (Node* n = getNode()->getParent(); n; n = n->getParent())
- {
- n->addAdvertisedDescendant(getNode());
- }
- }
- PhysicsVehicle::~PhysicsVehicle()
- {
- // Note that the destructor for PhysicsRigidBody calls removeCollisionObject and so
- // that is where the rigid body gets removed from the dynamics world. The vehicle
- // itself is just an action interface in the dynamics world.
- SAFE_DELETE(_vehicle);
- SAFE_DELETE(_vehicleRaycaster);
- SAFE_DELETE(_rigidBody);
- }
- btCollisionObject* PhysicsVehicle::getCollisionObject() const
- {
- GP_ASSERT(_rigidBody);
- return _rigidBody->getCollisionObject();
- }
- PhysicsCollisionObject::Type PhysicsVehicle::getType() const
- {
- return PhysicsCollisionObject::VEHICLE;
- }
- PhysicsRigidBody* PhysicsVehicle::getRigidBody() const
- {
- GP_ASSERT(_rigidBody);
- return _rigidBody;
- }
- void PhysicsVehicle::setEnabled(bool enable)
- {
- getRigidBody()->setEnabled(enable);
- }
- unsigned int PhysicsVehicle::getNumWheels() const
- {
- return (unsigned int)_wheels.size();
- }
- PhysicsVehicleWheel* PhysicsVehicle::getWheel(unsigned int i)
- {
- return _wheels.at(i);
- }
- void PhysicsVehicle::addWheel(PhysicsVehicleWheel* wheel)
- {
- unsigned i = (unsigned int)_wheels.size();
- _wheels.push_back(wheel);
- wheel->setHost(this, i);
- wheel->addToVehicle(_vehicle);
- }
- float PhysicsVehicle::getSpeedKph() const
- {
- return _vehicle->getCurrentSpeedKmHour();
- }
- float PhysicsVehicle::getSpeedSmoothKph() const
- {
- return _speedSmoothed;
- }
- void PhysicsVehicle::update(float elapsedTime, float steering, float braking, float driving)
- {
- float v = getSpeedKph();
- MathUtil::smooth(&_speedSmoothed, v, elapsedTime, 0, 1200);
- if (elapsedTime > 0)
- {
- // Avoid accumulation of downforce while paused (zero elapsedTime)
- applyDownforce();
- }
- // Adjust control inputs based on vehicle speed.
- steering = getSteering(v, steering);
- driving = getDriving(v, driving, braking);
- braking = getBraking(v, braking);
- // Allow braking to take precedence over driving.
- if (driving > 0 && braking > 0)
- {
- driving = 0;
- }
- PhysicsVehicleWheel* wheel;
- for (int i = 0; i < _vehicle->getNumWheels(); i++)
- {
- wheel = getWheel(i);
- if (wheel->isSteerable())
- {
- _vehicle->setSteeringValue(steering * _steeringGain, i);
- }
- else
- {
- _vehicle->applyEngineForce(driving * _drivingForce, i);
- _vehicle->setBrake(braking * _brakingForce, i);
- }
- wheel->update(elapsedTime);
- wheel->transform(wheel->getNode());
- }
- }
- void PhysicsVehicle::reset()
- {
- _rigidBody->setLinearVelocity(Vector3::zero());
- _rigidBody->setAngularVelocity(Vector3::zero());
- _speedSmoothed = 0;
- }
- float PhysicsVehicle::getSteering(float v, float rawSteering) const
- {
- float gain = 1;
- if (_steerdownSpeed > MATH_FLOAT_SMALL)
- {
- gain = max(_steerdownGain, 1 - (1 - _steerdownGain) * fabs(v) / _steerdownSpeed);
- }
- return rawSteering * gain;
- }
- float PhysicsVehicle::getBraking(float v, float rawBraking) const
- {
- float reduc = 0;
- float delta = _brakedownFull - _brakedownStart;
- if (delta > MATH_FLOAT_SMALL)
- {
- reduc = max(0.0f, (v - _brakedownStart) / delta);
- reduc *= reduc;
- }
- return max(0.0f, rawBraking - reduc);
- }
- float PhysicsVehicle::getDriving(float v, float rawDriving, float rawBraking) const
- {
- float reduc = 0;
- float delta = _drivedownFull - _drivedownStart;
- if (rawBraking == 0 && delta > MATH_FLOAT_SMALL)
- {
- reduc = max(0.0f, (v - _drivedownStart) / delta);
- reduc *= reduc;
- }
- float gain = 1;
- if (_boostSpeed > MATH_FLOAT_SMALL)
- {
- gain = max(1.0f, _boostGain - (_boostGain - 1) * fabs(v) / _boostSpeed);
- }
- return gain * rawDriving - reduc;
- }
- void PhysicsVehicle::applyDownforce()
- {
- float v = _speedSmoothed * KPH_TO_MPS;
- // dynamic pressure
- float q = 0.5f * AIR_DENSITY * v * v;
- // _downforce is the product of reference area and the aerodynamic coefficient
- _rigidBody->applyForce(Vector3(0, -_downforce * q, 0));
- }
- float PhysicsVehicle::getSteeringGain() const
- {
- return _steeringGain;
- }
- void PhysicsVehicle::setSteeringGain(float steeringGain)
- {
- _steeringGain = steeringGain;
- }
- float PhysicsVehicle::getBrakingForce() const
- {
- return _brakingForce;
- }
- void PhysicsVehicle::setBrakingForce(float brakingForce)
- {
- _brakingForce = brakingForce;
- }
- float PhysicsVehicle::getDrivingForce() const
- {
- return _drivingForce;
- }
- void PhysicsVehicle::setDrivingForce(float drivingForce)
- {
- _drivingForce = drivingForce;
- }
- float PhysicsVehicle::getSteerdownSpeed() const
- {
- return _steerdownSpeed;
- }
- float PhysicsVehicle::getSteerdownGain() const
- {
- return _steerdownGain;
- }
- void PhysicsVehicle::setSteerdown(float steerdownSpeed, float steerdownGain)
- {
- _steerdownSpeed = steerdownSpeed;
- _steerdownGain = steerdownGain;
- }
- float PhysicsVehicle::getBrakedownStart() const
- {
- return _brakedownStart;
- }
- float PhysicsVehicle::getBrakedownFull() const
- {
- return _brakedownFull;
- }
- void PhysicsVehicle::setBrakedown(float brakedownStart, float brakedownFull)
- {
- _brakedownStart = brakedownStart;
- _brakedownFull = brakedownFull;
- }
- float PhysicsVehicle::getDrivedownStart() const
- {
- return _drivedownStart;
- }
- float PhysicsVehicle::getDrivedownFull() const
- {
- return _drivedownFull;
- }
- void PhysicsVehicle::setDrivedown(float drivedownStart, float drivedownFull)
- {
- _drivedownStart = drivedownStart;
- _drivedownFull = drivedownFull;
- }
- float PhysicsVehicle::getBoostSpeed() const
- {
- return _boostSpeed;
- }
- float PhysicsVehicle::getBoostGain() const
- {
- return _boostGain;
- }
- void PhysicsVehicle::setBoost(float boostSpeed, float boostGain)
- {
- _boostSpeed = boostSpeed;
- _boostGain = boostGain;
- }
- float PhysicsVehicle::getDownforce() const
- {
- return _downforce;
- }
- void PhysicsVehicle::setDownforce(float downforce)
- {
- _downforce = downforce;
- }
- }
|