playerControllerComponent.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "T3D/components/physics/playerControllerComponent.h"
  23. #include "platform/platform.h"
  24. #include "console/consoleTypes.h"
  25. #include "core/util/safeDelete.h"
  26. #include "core/resourceManager.h"
  27. #include "core/stream/fileStream.h"
  28. #include "console/consoleTypes.h"
  29. #include "console/consoleObject.h"
  30. #include "ts/tsShapeInstance.h"
  31. #include "core/stream/bitStream.h"
  32. #include "gfx/gfxTransformSaver.h"
  33. #include "console/engineAPI.h"
  34. #include "lighting/lightQuery.h"
  35. #include "T3D/gameBase/gameConnection.h"
  36. #include "collision/collision.h"
  37. #include "T3D/physics/physicsPlayer.h"
  38. #include "T3D/physics/physicsPlugin.h"
  39. #include "T3D/components/collision/collisionInterfaces.h"
  40. #include "T3D/trigger.h"
  41. #include "T3D/components/collision/collisionTrigger.h"
  42. // Movement constants
  43. static F32 sVerticalStepDot = 0.173f; // 80
  44. static F32 sMinFaceDistance = 0.01f;
  45. static F32 sTractionDistance = 0.04f;
  46. static F32 sNormalElasticity = 0.01f;
  47. static U32 sMoveRetryCount = 5;
  48. static F32 sMaxImpulseVelocity = 200.0f;
  49. //////////////////////////////////////////////////////////////////////////
  50. // Callbacks
  51. IMPLEMENT_CALLBACK(PlayerControllerComponent, updateMove, void, (PlayerControllerComponent* obj), (obj),
  52. "Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n"
  53. "@param obj the Player object\n");
  54. //////////////////////////////////////////////////////////////////////////
  55. // Constructor/Destructor
  56. //////////////////////////////////////////////////////////////////////////
  57. PlayerControllerComponent::PlayerControllerComponent() : Component()
  58. {
  59. addComponentField("isStatic", "If enabled, object will not simulate physics", "bool", "0", "");
  60. addComponentField("gravity", "The direction of gravity affecting this object, as a vector", "vector", "0 0 -9", "");
  61. addComponentField("drag", "The drag coefficient that constantly affects the object", "float", "0.7", "");
  62. addComponentField("mass", "The mass of the object", "float", "1", "");
  63. mBuoyancy = 0.f;
  64. mFriction = 0.3f;
  65. mElasticity = 0.4f;
  66. mMaxVelocity = 3000.f;
  67. mVelocity = VectorF::Zero;
  68. mContactTimer = 0;
  69. mSticky = false;
  70. mFalling = false;
  71. mSwimming = false;
  72. mInWater = false;
  73. mDelta.pos = mDelta.posVec = Point3F::Zero;
  74. mDelta.warpTicks = mDelta.warpCount = 0;
  75. mDelta.rot[0].identity();
  76. mDelta.rot[1].identity();
  77. mDelta.dt = 1;
  78. mUseDirectMoveInput = false;
  79. mFriendlyName = "Player Controller";
  80. mComponentType = "Physics";
  81. mDescription = getDescriptionText("A general-purpose physics player controller.");
  82. //mNetFlags.set(Ghostable | ScopeAlways);
  83. mMass = 9.0f; // from ShapeBase
  84. mDrag = 1.0f; // from ShapeBase
  85. maxStepHeight = 1.0f;
  86. moveSurfaceAngle = 60.0f;
  87. contactSurfaceAngle = 85.0f;
  88. fallingSpeedThreshold = -10.0f;
  89. horizMaxSpeed = 80.0f;
  90. horizMaxAccel = 100.0f;
  91. horizResistSpeed = 38.0f;
  92. horizResistFactor = 1.0f;
  93. upMaxSpeed = 80.0f;
  94. upMaxAccel = 100.0f;
  95. upResistSpeed = 38.0f;
  96. upResistFactor = 1.0f;
  97. // Air control
  98. airControl = 0.0f;
  99. //Grav mod
  100. mGravityMod = 1;
  101. mInputVelocity = Point3F(0, 0, 0);
  102. mPhysicsRep = NULL;
  103. mPhysicsWorld = NULL;
  104. }
  105. PlayerControllerComponent::~PlayerControllerComponent()
  106. {
  107. for (S32 i = 0; i < mFields.size(); ++i)
  108. {
  109. ComponentField &field = mFields[i];
  110. SAFE_DELETE_ARRAY(field.mFieldDescription);
  111. }
  112. SAFE_DELETE_ARRAY(mDescription);
  113. }
  114. IMPLEMENT_CO_NETOBJECT_V1(PlayerControllerComponent);
  115. //////////////////////////////////////////////////////////////////////////
  116. bool PlayerControllerComponent::onAdd()
  117. {
  118. if (!Parent::onAdd())
  119. return false;
  120. return true;
  121. }
  122. void PlayerControllerComponent::onRemove()
  123. {
  124. Parent::onRemove();
  125. SAFE_DELETE(mPhysicsRep);
  126. }
  127. void PlayerControllerComponent::onComponentAdd()
  128. {
  129. Parent::onComponentAdd();
  130. updatePhysics();
  131. }
  132. void PlayerControllerComponent::componentAddedToOwner(Component *comp)
  133. {
  134. if (comp->getId() == getId())
  135. return;
  136. //test if this is a shape component!
  137. CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
  138. if (collisionInterface)
  139. {
  140. collisionInterface->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
  141. mOwnerCollisionInterface = collisionInterface;
  142. updatePhysics();
  143. }
  144. }
  145. void PlayerControllerComponent::componentRemovedFromOwner(Component *comp)
  146. {
  147. if (comp->getId() == getId()) //?????????
  148. return;
  149. //test if this is a shape component!
  150. CollisionInterface *collisionInterface = dynamic_cast<CollisionInterface*>(comp);
  151. if (collisionInterface)
  152. {
  153. collisionInterface->onCollisionChanged.remove(this, &PlayerControllerComponent::updatePhysics);
  154. mOwnerCollisionInterface = NULL;
  155. updatePhysics();
  156. }
  157. }
  158. void PlayerControllerComponent::updatePhysics(PhysicsCollision *collision)
  159. {
  160. if (!PHYSICSMGR)
  161. return;
  162. mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
  163. //first, clear the old physRep
  164. SAFE_DELETE(mPhysicsRep);
  165. mPhysicsRep = PHYSICSMGR->createPlayer();
  166. F32 runSurfaceCos = mCos(mDegToRad(moveSurfaceAngle));
  167. Point3F ownerBounds = mOwner->getObjBox().getExtents() * mOwner->getScale();
  168. mPhysicsRep->init("", ownerBounds, runSurfaceCos, maxStepHeight, mOwner, mPhysicsWorld);
  169. mPhysicsRep->setTransform(mOwner->getTransform());
  170. }
  171. void PlayerControllerComponent::initPersistFields()
  172. {
  173. Parent::initPersistFields();
  174. addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), "");
  175. addField("useDirectMoveInput", TypePoint3F, Offset(mUseDirectMoveInput, PlayerControllerComponent), "");
  176. }
  177. U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  178. {
  179. U32 retMask = Parent::packUpdate(con, mask, stream);
  180. return retMask;
  181. }
  182. void PlayerControllerComponent::unpackUpdate(NetConnection *con, BitStream *stream)
  183. {
  184. Parent::unpackUpdate(con, stream);
  185. }
  186. //
  187. void PlayerControllerComponent::processTick()
  188. {
  189. Parent::processTick();
  190. if (!isServerObject() || !isActive())
  191. return;
  192. // Warp to catch up to server
  193. if (mDelta.warpCount < mDelta.warpTicks)
  194. {
  195. mDelta.warpCount++;
  196. // Set new pos.
  197. mDelta.pos = mOwner->getPosition();
  198. mDelta.pos += mDelta.warpOffset;
  199. mDelta.rot[0] = mDelta.rot[1];
  200. mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks);
  201. MatrixF trans;
  202. mDelta.rot[1].setMatrix(&trans);
  203. trans.setPosition(mDelta.pos);
  204. mOwner->setTransform(trans);
  205. // Pos backstepping
  206. mDelta.posVec.x = -mDelta.warpOffset.x;
  207. mDelta.posVec.y = -mDelta.warpOffset.y;
  208. mDelta.posVec.z = -mDelta.warpOffset.z;
  209. }
  210. else
  211. {
  212. // Save current rigid state interpolation
  213. mDelta.posVec = mOwner->getPosition();
  214. mDelta.rot[0] = mOwner->getTransform();
  215. updateMove();
  216. updatePos(TickSec);
  217. // Wrap up interpolation info
  218. mDelta.pos = mOwner->getPosition();
  219. mDelta.posVec -= mOwner->getPosition();
  220. mDelta.rot[1] = mOwner->getTransform();
  221. // Update container database
  222. setTransform(mOwner->getTransform());
  223. setMaskBits(VelocityMask);
  224. setMaskBits(PositionMask);
  225. }
  226. }
  227. void PlayerControllerComponent::interpolateTick(F32 dt)
  228. {
  229. }
  230. void PlayerControllerComponent::ownerTransformSet(MatrixF *mat)
  231. {
  232. if (mPhysicsRep)
  233. mPhysicsRep->setTransform(mOwner->getTransform());
  234. }
  235. void PlayerControllerComponent::setTransform(const MatrixF& mat)
  236. {
  237. mOwner->setTransform(mat);
  238. setMaskBits(UpdateMask);
  239. }
  240. //
  241. void PlayerControllerComponent::updateMove()
  242. {
  243. if (!PHYSICSMGR)
  244. return;
  245. Move *move = &mOwner->lastMove;
  246. //If we're not set to use mUseDirectMoveInput, then we allow for an override in the form of mInputVelocity
  247. if (!mUseDirectMoveInput)
  248. {
  249. move->x = mInputVelocity.x;
  250. move->y = mInputVelocity.y;
  251. move->z = mInputVelocity.z;
  252. }
  253. // Is waterCoverage high enough to be 'swimming'?
  254. {
  255. bool swimming = mOwner->getContainerInfo().waterCoverage > 0.65f/* && canSwim()*/;
  256. if (swimming != mSwimming)
  257. {
  258. mSwimming = swimming;
  259. }
  260. }
  261. // Update current orientation
  262. bool doStandardMove = true;
  263. GameConnection* con = mOwner->getControllingClient();
  264. #ifdef TORQUE_EXTENDED_MOVE
  265. // Work with an absolute rotation from the ExtendedMove class?
  266. if (con && con->getControlSchemeAbsoluteRotation())
  267. {
  268. doStandardMove = false;
  269. const ExtendedMove* emove = dynamic_cast<const ExtendedMove*>(move);
  270. U32 emoveIndex = smExtendedMoveHeadPosRotIndex;
  271. if (emoveIndex >= ExtendedMove::MaxPositionsRotations)
  272. emoveIndex = 0;
  273. if (emove->EulerBasedRotation[emoveIndex])
  274. {
  275. // Head pitch
  276. mHead.x += (emove->rotX[emoveIndex] - mLastAbsolutePitch);
  277. // Do we also include the relative yaw value?
  278. if (con->getControlSchemeAddPitchToAbsRot())
  279. {
  280. F32 x = move->pitch;
  281. if (x > M_PI_F)
  282. x -= M_2PI_F;
  283. mHead.x += x;
  284. }
  285. // Constrain the range of mHead.x
  286. while (mHead.x < -M_PI_F)
  287. mHead.x += M_2PI_F;
  288. while (mHead.x > M_PI_F)
  289. mHead.x -= M_2PI_F;
  290. // Rotate (heading) head or body?
  291. if (move->freeLook && ((isMounted() && getMountNode() == 0) || (con && !con->isFirstPerson())))
  292. {
  293. // Rotate head
  294. mHead.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
  295. // Do we also include the relative yaw value?
  296. if (con->getControlSchemeAddYawToAbsRot())
  297. {
  298. F32 z = move->yaw;
  299. if (z > M_PI_F)
  300. z -= M_2PI_F;
  301. mHead.z += z;
  302. }
  303. // Constrain the range of mHead.z
  304. while (mHead.z < 0.0f)
  305. mHead.z += M_2PI_F;
  306. while (mHead.z > M_2PI_F)
  307. mHead.z -= M_2PI_F;
  308. }
  309. else
  310. {
  311. // Rotate body
  312. mRot.z += (emove->rotZ[emoveIndex] - mLastAbsoluteYaw);
  313. // Do we also include the relative yaw value?
  314. if (con->getControlSchemeAddYawToAbsRot())
  315. {
  316. F32 z = move->yaw;
  317. if (z > M_PI_F)
  318. z -= M_2PI_F;
  319. mRot.z += z;
  320. }
  321. // Constrain the range of mRot.z
  322. while (mRot.z < 0.0f)
  323. mRot.z += M_2PI_F;
  324. while (mRot.z > M_2PI_F)
  325. mRot.z -= M_2PI_F;
  326. }
  327. mLastAbsoluteYaw = emove->rotZ[emoveIndex];
  328. mLastAbsolutePitch = emove->rotX[emoveIndex];
  329. // Head bank
  330. mHead.y = emove->rotY[emoveIndex];
  331. // Constrain the range of mHead.y
  332. while (mHead.y > M_PI_F)
  333. mHead.y -= M_2PI_F;
  334. }
  335. }
  336. #endif
  337. MatrixF zRot;
  338. zRot.set(EulerF(0.0f, 0.0f, mOwner->getRotation().asEulerF().z));
  339. // Desired move direction & speed
  340. VectorF moveVec;
  341. F32 moveSpeed = mInputVelocity.len();
  342. zRot.getColumn(0, &moveVec);
  343. moveVec *= move->x;
  344. VectorF tv;
  345. zRot.getColumn(1, &tv);
  346. moveVec += tv * move->y;
  347. // Acceleration due to gravity
  348. VectorF acc(mPhysicsWorld->getGravity() * mGravityMod * TickSec);
  349. // Determine ground contact normal. Only look for contacts if
  350. // we can move and aren't mounted.
  351. mContactInfo.contactNormal = VectorF::Zero;
  352. mContactInfo.jump = false;
  353. mContactInfo.run = false;
  354. bool jumpSurface = false, runSurface = false;
  355. if (!mOwner->isMounted())
  356. findContact(&mContactInfo.run, &mContactInfo.jump, &mContactInfo.contactNormal);
  357. if (mContactInfo.jump)
  358. mJumpSurfaceNormal = mContactInfo.contactNormal;
  359. // If we don't have a runSurface but we do have a contactNormal,
  360. // then we are standing on something that is too steep.
  361. // Deflect the force of gravity by the normal so we slide.
  362. // We could also try aligning it to the runSurface instead,
  363. // but this seems to work well.
  364. if (!mContactInfo.run && !mContactInfo.contactNormal.isZero())
  365. acc = (acc - 2 * mContactInfo.contactNormal * mDot(acc, mContactInfo.contactNormal));
  366. // Acceleration on run surface
  367. if (mContactInfo.run && !mSwimming)
  368. {
  369. mContactTimer = 0;
  370. VectorF pv = moveVec;
  371. // Adjust the player's requested dir. to be parallel
  372. // to the contact surface.
  373. F32 pvl = pv.len();
  374. // Convert to acceleration
  375. if (pvl)
  376. pv *= moveSpeed / pvl;
  377. VectorF runAcc = pv - (mVelocity + acc);
  378. F32 runSpeed = runAcc.len();
  379. // Clamp acceleration, player also accelerates faster when
  380. // in his hard landing recover state.
  381. F32 maxAcc;
  382. maxAcc = (horizMaxAccel / mMass) * TickSec;
  383. if (runSpeed > maxAcc)
  384. runAcc *= maxAcc / runSpeed;
  385. acc += runAcc;
  386. }
  387. else if (!mSwimming && airControl > 0.0f)
  388. {
  389. VectorF pv;
  390. pv = moveVec;
  391. F32 pvl = pv.len();
  392. if (pvl)
  393. pv *= moveSpeed / pvl;
  394. VectorF runAcc = pv - (mVelocity + acc);
  395. runAcc.z = 0;
  396. runAcc.x = runAcc.x * airControl;
  397. runAcc.y = runAcc.y * airControl;
  398. F32 runSpeed = runAcc.len();
  399. // We don't test for sprinting when performing air control
  400. F32 maxAcc = (horizMaxAccel / mMass) * TickSec * 0.3f;
  401. if (runSpeed > maxAcc)
  402. runAcc *= maxAcc / runSpeed;
  403. acc += runAcc;
  404. // There are no special air control animations
  405. // so... increment this unless you really want to
  406. // play the run anims in the air.
  407. mContactTimer++;
  408. }
  409. else if (mSwimming)
  410. {
  411. // Remove acc into contact surface (should only be gravity)
  412. // Clear out floating point acc errors, this will allow
  413. // the player to "rest" on the ground.
  414. F32 vd = -mDot(acc, mContactInfo.contactNormal);
  415. if (vd > 0.0f)
  416. {
  417. VectorF dv = mContactInfo.contactNormal * (vd + 0.002f);
  418. acc += dv;
  419. if (acc.len() < 0.0001f)
  420. acc.set(0.0f, 0.0f, 0.0f);
  421. }
  422. // get the head pitch and add it to the moveVec
  423. // This more accurate swim vector calc comes from Matt Fairfax
  424. MatrixF xRot, zRot;
  425. xRot.set(EulerF(mOwner->getRotation().asEulerF().x, 0, 0));
  426. zRot.set(EulerF(0, 0, mOwner->getRotation().asEulerF().z));
  427. MatrixF rot;
  428. rot.mul(zRot, xRot);
  429. rot.getColumn(0, &moveVec);
  430. moveVec *= move->x;
  431. VectorF tv;
  432. rot.getColumn(1, &tv);
  433. moveVec += tv * move->y;
  434. rot.getColumn(2, &tv);
  435. moveVec += tv * move->z;
  436. // Force a 0 move if there is no energy, and only drain
  437. // move energy if we're moving.
  438. VectorF swimVec = moveVec;
  439. // If we are swimming but close enough to the shore/ground
  440. // we can still have a surface-normal. In this case align the
  441. // velocity to the normal to make getting out of water easier.
  442. moveVec.normalize();
  443. F32 isSwimUp = mDot(moveVec, mContactInfo.contactNormal);
  444. if (!mContactInfo.contactNormal.isZero() && isSwimUp < 0.1f)
  445. {
  446. F32 pvl = swimVec.len();
  447. if (pvl)
  448. {
  449. VectorF nn;
  450. mCross(swimVec, VectorF(0.0f, 0.0f, 1.0f), &nn);
  451. nn *= 1.0f / pvl;
  452. VectorF cv = mContactInfo.contactNormal;
  453. cv -= nn * mDot(nn, cv);
  454. swimVec -= cv * mDot(swimVec, cv);
  455. }
  456. }
  457. F32 swimVecLen = swimVec.len();
  458. // Convert to acceleration.
  459. if (swimVecLen)
  460. swimVec *= moveSpeed / swimVecLen;
  461. VectorF swimAcc = swimVec - (mVelocity + acc);
  462. F32 swimSpeed = swimAcc.len();
  463. // Clamp acceleration.
  464. F32 maxAcc = (horizMaxAccel / mMass) * TickSec;
  465. if (swimSpeed > maxAcc)
  466. swimAcc *= maxAcc / swimSpeed;
  467. acc += swimAcc;
  468. mContactTimer++;
  469. }
  470. else
  471. mContactTimer++;
  472. // Add in force from physical zones...
  473. acc += (mOwner->getContainerInfo().appliedForce / mMass) * TickSec;
  474. // Adjust velocity with all the move & gravity acceleration
  475. // TG: I forgot why doesn't the TickSec multiply happen here...
  476. mVelocity += acc;
  477. // apply horizontal air resistance
  478. F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
  479. if (hvel > horizResistSpeed)
  480. {
  481. F32 speedCap = hvel;
  482. if (speedCap > horizMaxSpeed)
  483. speedCap = horizMaxSpeed;
  484. speedCap -= horizResistFactor * TickSec * (speedCap - horizResistSpeed);
  485. F32 scale = speedCap / hvel;
  486. mVelocity.x *= scale;
  487. mVelocity.y *= scale;
  488. }
  489. if (mVelocity.z > upResistSpeed)
  490. {
  491. if (mVelocity.z > upMaxSpeed)
  492. mVelocity.z = upMaxSpeed;
  493. mVelocity.z -= upResistFactor * TickSec * (mVelocity.z - upResistSpeed);
  494. }
  495. // Apply drag
  496. mVelocity -= mVelocity * mDrag * TickSec;
  497. // Clamp very small velocity to zero
  498. if (mVelocity.isZero())
  499. mVelocity = Point3F::Zero;
  500. // If we are not touching anything and have sufficient -z vel,
  501. // we are falling.
  502. if (mContactInfo.run)
  503. {
  504. mFalling = false;
  505. }
  506. else
  507. {
  508. VectorF vel;
  509. mOwner->getWorldToObj().mulV(mVelocity, &vel);
  510. mFalling = vel.z < fallingSpeedThreshold;
  511. }
  512. // Enter/Leave Liquid
  513. if (!mInWater && mOwner->getContainerInfo().waterCoverage > 0.0f)
  514. {
  515. mInWater = true;
  516. }
  517. else if (mInWater && mOwner->getContainerInfo().waterCoverage <= 0.0f)
  518. {
  519. mInWater = false;
  520. }
  521. }
  522. void PlayerControllerComponent::updatePos(const F32 travelTime)
  523. {
  524. if (!PHYSICSMGR)
  525. return;
  526. PROFILE_SCOPE(PlayerControllerComponent_UpdatePos);
  527. Point3F newPos;
  528. Collision col;
  529. dMemset(&col, 0, sizeof(col));
  530. static CollisionList collisionList;
  531. collisionList.clear();
  532. newPos = mPhysicsRep->move(mVelocity * travelTime, collisionList);
  533. bool haveCollisions = false;
  534. bool wasFalling = mFalling;
  535. if (collisionList.getCount() > 0)
  536. {
  537. mFalling = false;
  538. haveCollisions = true;
  539. //TODO: clean this up so the phys component doesn't have to tell the col interface to do this
  540. CollisionInterface* colInterface = mOwner->getComponent<CollisionInterface>();
  541. if (colInterface)
  542. {
  543. colInterface->handleCollisionList(collisionList, mVelocity);
  544. }
  545. }
  546. if (haveCollisions)
  547. {
  548. // Pick the collision that most closely matches our direction
  549. VectorF velNormal = mVelocity;
  550. velNormal.normalizeSafe();
  551. const Collision *collision = &collisionList[0];
  552. F32 collisionDot = mDot(velNormal, collision->normal);
  553. const Collision *cp = collision + 1;
  554. const Collision *ep = collision + collisionList.getCount();
  555. for (; cp != ep; cp++)
  556. {
  557. F32 dp = mDot(velNormal, cp->normal);
  558. if (dp < collisionDot)
  559. {
  560. collisionDot = dp;
  561. collision = cp;
  562. }
  563. }
  564. // Modify our velocity based on collisions
  565. for (U32 i = 0; i<collisionList.getCount(); ++i)
  566. {
  567. F32 bd = -mDot(mVelocity, collisionList[i].normal);
  568. VectorF dv = collisionList[i].normal * (bd + sNormalElasticity);
  569. mVelocity += dv;
  570. }
  571. // Store the last collision for use later on. The handle collision
  572. // code only expects a single collision object.
  573. if (collisionList.getCount() > 0)
  574. col = collisionList[collisionList.getCount() - 1];
  575. // We'll handle any player-to-player collision, and the last collision
  576. // with other obejct types.
  577. for (U32 i = 0; i<collisionList.getCount(); ++i)
  578. {
  579. Collision& colCheck = collisionList[i];
  580. if (colCheck.object)
  581. {
  582. col = colCheck;
  583. }
  584. }
  585. }
  586. MatrixF newMat;
  587. newMat.setPosition(newPos);
  588. mPhysicsRep->setTransform(newMat);
  589. mOwner->setPosition(newPos);
  590. }
  591. //
  592. void PlayerControllerComponent::setVelocity(const VectorF& vel)
  593. {
  594. mVelocity = vel;
  595. // Clamp against the maximum velocity.
  596. if (mMaxVelocity > 0)
  597. {
  598. F32 len = mVelocity.magnitudeSafe();
  599. if (len > mMaxVelocity)
  600. {
  601. Point3F excess = mVelocity * (1.0f - (mMaxVelocity / len));
  602. mVelocity -= excess;
  603. }
  604. }
  605. setMaskBits(VelocityMask);
  606. }
  607. void PlayerControllerComponent::findContact(bool *run, bool *jump, VectorF *contactNormal)
  608. {
  609. SceneObject *contactObject = NULL;
  610. Vector<SceneObject*> overlapObjects;
  611. mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects);
  612. F32 vd = (*contactNormal).z;
  613. *run = vd > mCos(mDegToRad(moveSurfaceAngle));
  614. *jump = vd > mCos(mDegToRad(contactSurfaceAngle));
  615. // Check for triggers
  616. for (U32 i = 0; i < overlapObjects.size(); i++)
  617. {
  618. SceneObject *obj = overlapObjects[i];
  619. U32 objectMask = obj->getTypeMask();
  620. // Check: triggers, corpses and items...
  621. //
  622. if (objectMask & TriggerObjectType)
  623. {
  624. if (Trigger* pTrigger = dynamic_cast<Trigger*>(obj))
  625. {
  626. pTrigger->potentialEnterObject(mOwner);
  627. }
  628. else if (CollisionTrigger* pTriggerEx = dynamic_cast<CollisionTrigger*>(obj))
  629. {
  630. if (pTriggerEx)
  631. pTriggerEx->potentialEnterObject(mOwner);
  632. }
  633. //Add any other custom classes and the sort here that should be filtered against
  634. /*else if (TriggerExample* pTriggerEx = dynamic_cast<TriggerExample*>(obj))
  635. {
  636. if (pTriggerEx)
  637. pTriggerEx->potentialEnterObject(mOwner);
  638. }*/
  639. }
  640. }
  641. mContactInfo.contacted = contactObject != NULL;
  642. mContactInfo.contactObject = contactObject;
  643. if (mContactInfo.contacted)
  644. mContactInfo.contactNormal = *contactNormal;
  645. }
  646. void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec)
  647. {
  648. AssertFatal(!mIsNaN(vec), "Player::applyImpulse() - The vector is NaN!");
  649. // Players ignore angular velocity
  650. VectorF vel;
  651. vel.x = vec.x / getMass();
  652. vel.y = vec.y / getMass();
  653. vel.z = vec.z / getMass();
  654. // Make sure the impulse isn't too bigg
  655. F32 len = vel.magnitudeSafe();
  656. if (len > sMaxImpulseVelocity)
  657. {
  658. Point3F excess = vel * (1.0f - (sMaxImpulseVelocity / len));
  659. vel -= excess;
  660. }
  661. setVelocity(mVelocity + vel);
  662. }
  663. DefineEngineMethod(PlayerControllerComponent, applyImpulse, bool, (Point3F pos, VectorF vel), ,
  664. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  665. "@param pos impulse world position\n"
  666. "@param vel impulse velocity (impulse force F = m * v)\n"
  667. "@return Always true\n"
  668. "@note Not all objects that derrive from GameBase have this defined.\n")
  669. {
  670. object->applyImpulse(pos, vel);
  671. return true;
  672. }
  673. DefineEngineMethod(PlayerControllerComponent, getContactNormal, Point3F, (), ,
  674. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  675. "@param pos impulse world position\n"
  676. "@param vel impulse velocity (impulse force F = m * v)\n"
  677. "@return Always true\n"
  678. "@note Not all objects that derrive from GameBase have this defined.\n")
  679. {
  680. return object->getContactNormal();
  681. }
  682. DefineEngineMethod(PlayerControllerComponent, getContactObject, SceneObject*, (), ,
  683. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  684. "@param pos impulse world position\n"
  685. "@param vel impulse velocity (impulse force F = m * v)\n"
  686. "@return Always true\n"
  687. "@note Not all objects that derrive from GameBase have this defined.\n")
  688. {
  689. return object->getContactObject();
  690. }
  691. DefineEngineMethod(PlayerControllerComponent, isContacted, bool, (), ,
  692. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  693. "@param pos impulse world position\n"
  694. "@param vel impulse velocity (impulse force F = m * v)\n"
  695. "@return Always true\n"
  696. "@note Not all objects that derrive from GameBase have this defined.\n")
  697. {
  698. return object->isContacted();
  699. }