PhysicsVehicle.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. #include "Base.h"
  2. #include "Game.h"
  3. #include "MathUtil.h"
  4. #include "Node.h"
  5. #include "PhysicsVehicle.h"
  6. #include "PhysicsVehicleWheel.h"
  7. #define AIR_DENSITY (1.2f)
  8. #define KPH_TO_MPS (1.0f / 3.6f)
  9. namespace gameplay
  10. {
  11. /**
  12. * The default vehicle raycaster in Bullet currently does not filter out the vehicle's own
  13. * rigid body from the ray test which can result in unexpected behavior. These implementations
  14. * are intended to fix that.
  15. *
  16. * @script{ignore}
  17. */
  18. class ClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
  19. {
  20. public:
  21. ClosestNotMeRayResultCallback(const btVector3& from, const btVector3& to, btCollisionObject* me)
  22. : btCollisionWorld::ClosestRayResultCallback(from, to), _me(me)
  23. {
  24. }
  25. btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
  26. {
  27. if (rayResult.m_collisionObject == _me)
  28. return 1.0f;
  29. return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace);
  30. }
  31. private:
  32. btCollisionObject* _me;
  33. };
  34. /**
  35. * @script{ignore}
  36. */
  37. class VehicleNotMeRaycaster : public btVehicleRaycaster
  38. {
  39. public:
  40. VehicleNotMeRaycaster(btDynamicsWorld* world, btCollisionObject* me)
  41. : _dynamicsWorld(world), _me(me)
  42. {
  43. }
  44. void* castRay(const btVector3& from, const btVector3& to, btVehicleRaycasterResult& result)
  45. {
  46. ClosestNotMeRayResultCallback rayCallback(from, to, _me);
  47. _dynamicsWorld->rayTest(from, to, rayCallback);
  48. if (rayCallback.hasHit())
  49. {
  50. const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
  51. if (body && body->hasContactResponse())
  52. {
  53. result.m_hitPointInWorld = rayCallback.m_hitPointWorld;
  54. result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld;
  55. result.m_hitNormalInWorld.normalize();
  56. result.m_distFraction = rayCallback.m_closestHitFraction;
  57. return (void*)body;
  58. }
  59. }
  60. return 0;
  61. }
  62. private:
  63. btDynamicsWorld* _dynamicsWorld;
  64. btCollisionObject* _me;
  65. };
  66. PhysicsVehicle::PhysicsVehicle(Node* node, const PhysicsCollisionShape::Definition& shape, const PhysicsRigidBody::Parameters& parameters)
  67. : PhysicsCollisionObject(node), _speedSmoothed(0)
  68. {
  69. // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
  70. // that is where the rigid body gets added to the dynamics world.
  71. _rigidBody = new PhysicsRigidBody(node, shape, parameters);
  72. initialize();
  73. }
  74. PhysicsVehicle::PhysicsVehicle(Node* node, PhysicsRigidBody* rigidBody)
  75. : PhysicsCollisionObject(node), _speedSmoothed(0)
  76. {
  77. _rigidBody = rigidBody;
  78. initialize();
  79. }
  80. PhysicsVehicle* PhysicsVehicle::create(Node* node, Properties* properties)
  81. {
  82. // Note that the constructor for PhysicsRigidBody calls addCollisionObject and so
  83. // that is where the rigid body gets added to the dynamics world.
  84. PhysicsRigidBody* rigidBody = PhysicsRigidBody::create(node, properties, "VEHICLE");
  85. PhysicsVehicle* vehicle = new PhysicsVehicle(node, rigidBody);
  86. // Load the defined vehicle parameters.
  87. properties->rewind();
  88. const char* name;
  89. while ((name = properties->getNextProperty()) != NULL)
  90. {
  91. if (strcmp(name, "steeringGain") == 0)
  92. {
  93. vehicle->setSteeringGain(properties->getFloat());
  94. }
  95. else if (strcmp(name, "brakingForce") == 0)
  96. {
  97. vehicle->setBrakingForce(properties->getFloat());
  98. }
  99. else if (strcmp(name, "drivingForce") == 0)
  100. {
  101. vehicle->setDrivingForce(properties->getFloat());
  102. }
  103. else if (strcmp(name, "steerdownSpeed") == 0)
  104. {
  105. vehicle->_steerdownSpeed = properties->getFloat();
  106. }
  107. else if (strcmp(name, "steerdownGain") == 0)
  108. {
  109. vehicle->_steerdownGain = properties->getFloat();
  110. }
  111. else if (strcmp(name, "brakedownStart") == 0)
  112. {
  113. vehicle->_brakedownStart = properties->getFloat();
  114. }
  115. else if (strcmp(name, "brakedownFull") == 0)
  116. {
  117. vehicle->_brakedownFull = properties->getFloat();
  118. }
  119. else if (strcmp(name, "drivedownStart") == 0)
  120. {
  121. vehicle->_drivedownStart = properties->getFloat();
  122. }
  123. else if (strcmp(name, "drivedownFull") == 0)
  124. {
  125. vehicle->_drivedownFull = properties->getFloat();
  126. }
  127. else if (strcmp(name, "boostSpeed") == 0)
  128. {
  129. vehicle->_boostSpeed = properties->getFloat();
  130. }
  131. else if (strcmp(name, "boostGain") == 0)
  132. {
  133. vehicle->_boostGain = properties->getFloat();
  134. }
  135. else if (strcmp(name, "downforce") == 0)
  136. {
  137. vehicle->_downforce = properties->getFloat();
  138. }
  139. else
  140. {
  141. // Ignore this case (we've already parsed the rigid body parameters).
  142. }
  143. }
  144. return vehicle;
  145. }
  146. void PhysicsVehicle::initialize()
  147. {
  148. GP_ASSERT(getNode());
  149. // Safe default values
  150. setSteeringGain(0.5f);
  151. setBrakingForce(350.0f);
  152. setDrivingForce(2000.0f);
  153. setSteerdown(0, 1);
  154. setBrakedown(1000, 0);
  155. setDrivedown(1000, 0);
  156. setBoost(0, 1);
  157. setDownforce(0);
  158. // Create the vehicle and add it to world
  159. btRigidBody* body = static_cast<btRigidBody*>(_rigidBody->getCollisionObject());
  160. btDynamicsWorld* dynamicsWorld = Game::getInstance()->getPhysicsController()->_world;
  161. _vehicleRaycaster = new VehicleNotMeRaycaster(dynamicsWorld, body);
  162. _vehicle = bullet_new<btRaycastVehicle>(_vehicleTuning, body, _vehicleRaycaster);
  163. body->setActivationState(DISABLE_DEACTIVATION);
  164. dynamicsWorld->addVehicle(_vehicle);
  165. _vehicle->setCoordinateSystem(0, 1, 2);
  166. // Advertise self among ancestor nodes so that wheels can bind to self.
  167. // See PhysicsVehicleWheel and Node for more details.
  168. for (Node* n = getNode()->getParent(); n; n = n->getParent())
  169. {
  170. n->addAdvertisedDescendant(getNode());
  171. }
  172. }
  173. PhysicsVehicle::~PhysicsVehicle()
  174. {
  175. // Note that the destructor for PhysicsRigidBody calls removeCollisionObject and so
  176. // that is where the rigid body gets removed from the dynamics world. The vehicle
  177. // itself is just an action interface in the dynamics world.
  178. SAFE_DELETE(_vehicle);
  179. SAFE_DELETE(_vehicleRaycaster);
  180. SAFE_DELETE(_rigidBody);
  181. }
  182. btCollisionObject* PhysicsVehicle::getCollisionObject() const
  183. {
  184. GP_ASSERT(_rigidBody);
  185. return _rigidBody->getCollisionObject();
  186. }
  187. PhysicsCollisionObject::Type PhysicsVehicle::getType() const
  188. {
  189. return PhysicsCollisionObject::VEHICLE;
  190. }
  191. PhysicsRigidBody* PhysicsVehicle::getRigidBody() const
  192. {
  193. GP_ASSERT(_rigidBody);
  194. return _rigidBody;
  195. }
  196. void PhysicsVehicle::setEnabled(bool enable)
  197. {
  198. getRigidBody()->setEnabled(enable);
  199. }
  200. unsigned int PhysicsVehicle::getNumWheels() const
  201. {
  202. return (unsigned int)_wheels.size();
  203. }
  204. PhysicsVehicleWheel* PhysicsVehicle::getWheel(unsigned int i)
  205. {
  206. return _wheels.at(i);
  207. }
  208. void PhysicsVehicle::addWheel(PhysicsVehicleWheel* wheel)
  209. {
  210. unsigned i = (unsigned int)_wheels.size();
  211. _wheels.push_back(wheel);
  212. wheel->setHost(this, i);
  213. wheel->addToVehicle(_vehicle);
  214. }
  215. float PhysicsVehicle::getSpeedKph() const
  216. {
  217. return _vehicle->getCurrentSpeedKmHour();
  218. }
  219. float PhysicsVehicle::getSpeedSmoothKph() const
  220. {
  221. return _speedSmoothed;
  222. }
  223. void PhysicsVehicle::update(float elapsedTime, float steering, float braking, float driving)
  224. {
  225. float v = getSpeedKph();
  226. MathUtil::smooth(&_speedSmoothed, v, elapsedTime, 0, 1200);
  227. if (elapsedTime > 0)
  228. {
  229. // Avoid accumulation of downforce while paused (zero elapsedTime)
  230. applyDownforce();
  231. }
  232. // Adjust control inputs based on vehicle speed.
  233. steering = getSteering(v, steering);
  234. driving = getDriving(v, driving, braking);
  235. braking = getBraking(v, braking);
  236. // Allow braking to take precedence over driving.
  237. if (driving > 0 && braking > 0)
  238. {
  239. driving = 0;
  240. }
  241. PhysicsVehicleWheel* wheel;
  242. for (int i = 0; i < _vehicle->getNumWheels(); i++)
  243. {
  244. wheel = getWheel(i);
  245. if (wheel->isSteerable())
  246. {
  247. _vehicle->setSteeringValue(steering * _steeringGain, i);
  248. }
  249. else
  250. {
  251. _vehicle->applyEngineForce(driving * _drivingForce, i);
  252. _vehicle->setBrake(braking * _brakingForce, i);
  253. }
  254. wheel->update(elapsedTime);
  255. wheel->transform(wheel->getNode());
  256. }
  257. }
  258. void PhysicsVehicle::reset()
  259. {
  260. _rigidBody->setLinearVelocity(Vector3::zero());
  261. _rigidBody->setAngularVelocity(Vector3::zero());
  262. _speedSmoothed = 0;
  263. }
  264. float PhysicsVehicle::getSteering(float v, float rawSteering) const
  265. {
  266. float gain = 1;
  267. if (_steerdownSpeed > MATH_FLOAT_SMALL)
  268. {
  269. gain = max(_steerdownGain, 1 - (1 - _steerdownGain) * fabs(v) / _steerdownSpeed);
  270. }
  271. return rawSteering * gain;
  272. }
  273. float PhysicsVehicle::getBraking(float v, float rawBraking) const
  274. {
  275. float reduc = 0;
  276. float delta = _brakedownFull - _brakedownStart;
  277. if (delta > MATH_FLOAT_SMALL)
  278. {
  279. reduc = max(0.0f, (v - _brakedownStart) / delta);
  280. reduc *= reduc;
  281. }
  282. return max(0.0f, rawBraking - reduc);
  283. }
  284. float PhysicsVehicle::getDriving(float v, float rawDriving, float rawBraking) const
  285. {
  286. float reduc = 0;
  287. float delta = _drivedownFull - _drivedownStart;
  288. if (rawBraking == 0 && delta > MATH_FLOAT_SMALL)
  289. {
  290. reduc = max(0.0f, (v - _drivedownStart) / delta);
  291. reduc *= reduc;
  292. }
  293. float gain = 1;
  294. if (_boostSpeed > MATH_FLOAT_SMALL)
  295. {
  296. gain = max(1.0f, _boostGain - (_boostGain - 1) * fabs(v) / _boostSpeed);
  297. }
  298. return gain * rawDriving - reduc;
  299. }
  300. void PhysicsVehicle::applyDownforce()
  301. {
  302. float v = _speedSmoothed * KPH_TO_MPS;
  303. // dynamic pressure
  304. float q = 0.5f * AIR_DENSITY * v * v;
  305. // _downforce is the product of reference area and the aerodynamic coefficient
  306. _rigidBody->applyForce(Vector3(0, -_downforce * q, 0));
  307. }
  308. float PhysicsVehicle::getSteeringGain() const
  309. {
  310. return _steeringGain;
  311. }
  312. void PhysicsVehicle::setSteeringGain(float steeringGain)
  313. {
  314. _steeringGain = steeringGain;
  315. }
  316. float PhysicsVehicle::getBrakingForce() const
  317. {
  318. return _brakingForce;
  319. }
  320. void PhysicsVehicle::setBrakingForce(float brakingForce)
  321. {
  322. _brakingForce = brakingForce;
  323. }
  324. float PhysicsVehicle::getDrivingForce() const
  325. {
  326. return _drivingForce;
  327. }
  328. void PhysicsVehicle::setDrivingForce(float drivingForce)
  329. {
  330. _drivingForce = drivingForce;
  331. }
  332. float PhysicsVehicle::getSteerdownSpeed() const
  333. {
  334. return _steerdownSpeed;
  335. }
  336. float PhysicsVehicle::getSteerdownGain() const
  337. {
  338. return _steerdownGain;
  339. }
  340. void PhysicsVehicle::setSteerdown(float steerdownSpeed, float steerdownGain)
  341. {
  342. _steerdownSpeed = steerdownSpeed;
  343. _steerdownGain = steerdownGain;
  344. }
  345. float PhysicsVehicle::getBrakedownStart() const
  346. {
  347. return _brakedownStart;
  348. }
  349. float PhysicsVehicle::getBrakedownFull() const
  350. {
  351. return _brakedownFull;
  352. }
  353. void PhysicsVehicle::setBrakedown(float brakedownStart, float brakedownFull)
  354. {
  355. _brakedownStart = brakedownStart;
  356. _brakedownFull = brakedownFull;
  357. }
  358. float PhysicsVehicle::getDrivedownStart() const
  359. {
  360. return _drivedownStart;
  361. }
  362. float PhysicsVehicle::getDrivedownFull() const
  363. {
  364. return _drivedownFull;
  365. }
  366. void PhysicsVehicle::setDrivedown(float drivedownStart, float drivedownFull)
  367. {
  368. _drivedownStart = drivedownStart;
  369. _drivedownFull = drivedownFull;
  370. }
  371. float PhysicsVehicle::getBoostSpeed() const
  372. {
  373. return _boostSpeed;
  374. }
  375. float PhysicsVehicle::getBoostGain() const
  376. {
  377. return _boostGain;
  378. }
  379. void PhysicsVehicle::setBoost(float boostSpeed, float boostGain)
  380. {
  381. _boostSpeed = boostSpeed;
  382. _boostGain = boostGain;
  383. }
  384. float PhysicsVehicle::getDownforce() const
  385. {
  386. return _downforce;
  387. }
  388. void PhysicsVehicle::setDownforce(float downforce)
  389. {
  390. _downforce = downforce;
  391. }
  392. }