playerControllerComponent.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  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/trigger.h"
  40. #include "T3D/components/collision/collisionTrigger.h"
  41. // Movement constants
  42. static F32 sVerticalStepDot = 0.173f; // 80
  43. static F32 sMinFaceDistance = 0.01f;
  44. static F32 sTractionDistance = 0.04f;
  45. static F32 sNormalElasticity = 0.01f;
  46. static U32 sMoveRetryCount = 5;
  47. static F32 sMaxImpulseVelocity = 200.0f;
  48. //////////////////////////////////////////////////////////////////////////
  49. // Callbacks
  50. IMPLEMENT_CALLBACK(PlayerControllerComponent, updateMove, void, (PlayerControllerComponent* obj), (obj),
  51. "Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n"
  52. "@param obj the Player object\n");
  53. //////////////////////////////////////////////////////////////////////////
  54. // Constructor/Destructor
  55. //////////////////////////////////////////////////////////////////////////
  56. PlayerControllerComponent::PlayerControllerComponent() : PhysicsComponent()
  57. {
  58. mBuoyancy = 0.f;
  59. mFriction = 0.3f;
  60. mElasticity = 0.4f;
  61. mMaxVelocity = 3000.f;
  62. mVelocity = VectorF::Zero;
  63. mContactTimer = 0;
  64. mSticky = false;
  65. mFalling = false;
  66. mSwimming = false;
  67. mInWater = false;
  68. mDelta.pos = mDelta.posVec = Point3F::Zero;
  69. mDelta.warpTicks = mDelta.warpCount = 0;
  70. mDelta.rot[0].identity();
  71. mDelta.rot[1].identity();
  72. mDelta.dt = 1;
  73. mUseDirectMoveInput = false;
  74. mFriendlyName = "Player Controller";
  75. mComponentType = "Physics";
  76. mDescription = getDescriptionText("A general-purpose physics player controller.");
  77. //mNetFlags.set(Ghostable | ScopeAlways);
  78. mMass = 9.0f; // from ShapeBase
  79. mDrag = 1.0f; // from ShapeBase
  80. maxStepHeight = 1.0f;
  81. moveSurfaceAngle = 60.0f;
  82. contactSurfaceAngle = 85.0f;
  83. fallingSpeedThreshold = -10.0f;
  84. horizMaxSpeed = 80.0f;
  85. horizMaxAccel = 100.0f;
  86. horizResistSpeed = 38.0f;
  87. horizResistFactor = 1.0f;
  88. upMaxSpeed = 80.0f;
  89. upMaxAccel = 100.0f;
  90. upResistSpeed = 38.0f;
  91. upResistFactor = 1.0f;
  92. // Air control
  93. airControl = 0.0f;
  94. //Grav mod
  95. mGravityMod = 1;
  96. mInputVelocity = Point3F(0, 0, 0);
  97. mPhysicsRep = nullptr;
  98. mPhysicsWorld = nullptr;
  99. mOwnerCollisionComp = nullptr;
  100. mIntegrationCount = 0;
  101. }
  102. PlayerControllerComponent::~PlayerControllerComponent()
  103. {
  104. for (S32 i = 0; i < mFields.size(); ++i)
  105. {
  106. ComponentField &field = mFields[i];
  107. SAFE_DELETE_ARRAY(field.mFieldDescription);
  108. }
  109. SAFE_DELETE_ARRAY(mDescription);
  110. }
  111. IMPLEMENT_CO_NETOBJECT_V1(PlayerControllerComponent);
  112. //////////////////////////////////////////////////////////////////////////
  113. bool PlayerControllerComponent::onAdd()
  114. {
  115. if (!Parent::onAdd())
  116. return false;
  117. return true;
  118. }
  119. void PlayerControllerComponent::onRemove()
  120. {
  121. Parent::onRemove();
  122. SAFE_DELETE(mPhysicsRep);
  123. }
  124. void PlayerControllerComponent::onComponentAdd()
  125. {
  126. Parent::onComponentAdd();
  127. CollisionComponent *collisionComp = mOwner->getComponent<CollisionComponent>();
  128. if (collisionComp)
  129. {
  130. collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
  131. mOwnerCollisionComp = collisionComp;
  132. }
  133. updatePhysics();
  134. }
  135. void PlayerControllerComponent::componentAddedToOwner(Component *comp)
  136. {
  137. if (comp->getId() == getId())
  138. return;
  139. CollisionComponent *collisionComp = dynamic_cast<CollisionComponent*>(comp);
  140. if (collisionComp)
  141. {
  142. collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
  143. mOwnerCollisionComp = collisionComp;
  144. updatePhysics();
  145. }
  146. }
  147. void PlayerControllerComponent::componentRemovedFromOwner(Component *comp)
  148. {
  149. if (comp->getId() == getId()) //?????????
  150. return;
  151. CollisionComponent *collisionComp = dynamic_cast<CollisionComponent*>(comp);
  152. if (collisionComp)
  153. {
  154. collisionComp->onCollisionChanged.notify(this, &PlayerControllerComponent::updatePhysics);
  155. mOwnerCollisionComp = nullptr;
  156. updatePhysics();
  157. }
  158. }
  159. void PlayerControllerComponent::updatePhysics(PhysicsCollision *collision)
  160. {
  161. if (!PHYSICSMGR)
  162. return;
  163. mPhysicsWorld = PHYSICSMGR->getWorld(isServerObject() ? "server" : "client");
  164. //first, clear the old physRep
  165. SAFE_DELETE(mPhysicsRep);
  166. mPhysicsRep = PHYSICSMGR->createPlayer();
  167. F32 runSurfaceCos = mCos(mDegToRad(moveSurfaceAngle));
  168. Point3F ownerBounds = mOwner->getObjBox().getExtents() * mOwner->getScale();
  169. mPhysicsRep->init("", ownerBounds, runSurfaceCos, maxStepHeight, mOwner, mPhysicsWorld);
  170. mPhysicsRep->setTransform(mOwner->getTransform());
  171. }
  172. void PlayerControllerComponent::initPersistFields()
  173. {
  174. Parent::initPersistFields();
  175. addField("inputVelocity", TypePoint3F, Offset(mInputVelocity, PlayerControllerComponent), "");
  176. addField("useDirectMoveInput", TypeBool, Offset(mUseDirectMoveInput, PlayerControllerComponent), "");
  177. }
  178. U32 PlayerControllerComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  179. {
  180. U32 retMask = Parent::packUpdate(con, mask, stream);
  181. return retMask;
  182. }
  183. void PlayerControllerComponent::unpackUpdate(NetConnection *con, BitStream *stream)
  184. {
  185. Parent::unpackUpdate(con, stream);
  186. }
  187. //
  188. void PlayerControllerComponent::processTick()
  189. {
  190. Parent::processTick();
  191. if (!isServerObject() || !isActive())
  192. return;
  193. // Warp to catch up to server
  194. if (mDelta.warpCount < mDelta.warpTicks)
  195. {
  196. mDelta.warpCount++;
  197. // Set new pos.
  198. mDelta.pos = mOwner->getPosition();
  199. mDelta.pos += mDelta.warpOffset;
  200. mDelta.rot[0] = mDelta.rot[1];
  201. mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks);
  202. MatrixF trans;
  203. mDelta.rot[1].setMatrix(&trans);
  204. trans.setPosition(mDelta.pos);
  205. mOwner->setTransform(trans);
  206. // Pos backstepping
  207. mDelta.posVec.x = -mDelta.warpOffset.x;
  208. mDelta.posVec.y = -mDelta.warpOffset.y;
  209. mDelta.posVec.z = -mDelta.warpOffset.z;
  210. }
  211. else
  212. {
  213. // Save current rigid state interpolation
  214. mDelta.posVec = mOwner->getPosition();
  215. mDelta.rot[0] = mOwner->getTransform();
  216. updateMove();
  217. updatePos(TickSec);
  218. // Wrap up interpolation info
  219. mDelta.pos = mOwner->getPosition();
  220. mDelta.posVec -= mOwner->getPosition();
  221. mDelta.rot[1] = mOwner->getTransform();
  222. // Update container database
  223. setTransform(mOwner->getTransform());
  224. setMaskBits(VelocityMask);
  225. setMaskBits(PositionMask);
  226. }
  227. }
  228. void PlayerControllerComponent::interpolateTick(F32 dt)
  229. {
  230. }
  231. void PlayerControllerComponent::ownerTransformSet(MatrixF *mat)
  232. {
  233. if (mPhysicsRep)
  234. mPhysicsRep->setTransform(mOwner->getTransform());
  235. }
  236. void PlayerControllerComponent::setTransform(const MatrixF& mat)
  237. {
  238. mOwner->setTransform(mat);
  239. setMaskBits(UpdateMask);
  240. }
  241. //
  242. void PlayerControllerComponent::updateMove()
  243. {
  244. if (!PHYSICSMGR)
  245. return;
  246. Move *move = &mOwner->lastMove;
  247. //If we're not set to use mUseDirectMoveInput, then we allow for an override in the form of mInputVelocity
  248. if (!mUseDirectMoveInput)
  249. {
  250. move->x = mInputVelocity.x;
  251. move->y = mInputVelocity.y;
  252. move->z = mInputVelocity.z;
  253. }
  254. // Is waterCoverage high enough to be 'swimming'?
  255. {
  256. bool swimming = mOwner->getContainerInfo().waterCoverage > 0.65f/* && canSwim()*/;
  257. if (swimming != mSwimming)
  258. {
  259. mSwimming = swimming;
  260. }
  261. }
  262. // Update current orientation
  263. MatrixF zRot;
  264. zRot.set(EulerF(0.0f, 0.0f, mOwner->getRotation().asEulerF().z));
  265. // Desired move direction & speed
  266. VectorF moveVec;
  267. F32 moveSpeed = mInputVelocity.len();
  268. zRot.getColumn(0, &moveVec);
  269. moveVec *= move->x;
  270. VectorF tv;
  271. zRot.getColumn(1, &tv);
  272. moveVec += tv * move->y;
  273. // Acceleration due to gravity
  274. VectorF acc(mPhysicsWorld->getGravity() * mGravityMod * TickSec);
  275. // Determine ground contact normal. Only look for contacts if
  276. // we can move and aren't mounted.
  277. mContactInfo.contactNormal = VectorF::Zero;
  278. mContactInfo.jump = false;
  279. mContactInfo.run = false;
  280. if (!mOwner->isMounted())
  281. findContact(&mContactInfo.run, &mContactInfo.jump, &mContactInfo.contactNormal);
  282. if (mContactInfo.jump)
  283. mJumpSurfaceNormal = mContactInfo.contactNormal;
  284. // If we don't have a runSurface but we do have a contactNormal,
  285. // then we are standing on something that is too steep.
  286. // Deflect the force of gravity by the normal so we slide.
  287. // We could also try aligning it to the runSurface instead,
  288. // but this seems to work well.
  289. if (!mContactInfo.run && !mContactInfo.contactNormal.isZero())
  290. acc = (acc - 2 * mContactInfo.contactNormal * mDot(acc, mContactInfo.contactNormal));
  291. // Acceleration on run surface
  292. if (mContactInfo.run && !mSwimming)
  293. {
  294. mContactTimer = 0;
  295. VectorF pv = moveVec;
  296. // Adjust the player's requested dir. to be parallel
  297. // to the contact surface.
  298. F32 pvl = pv.len();
  299. // Convert to acceleration
  300. if (pvl)
  301. pv *= moveSpeed / pvl;
  302. VectorF runAcc = pv - (mVelocity + acc);
  303. F32 runSpeed = runAcc.len();
  304. // Clamp acceleration, player also accelerates faster when
  305. // in his hard landing recover state.
  306. F32 maxAcc;
  307. maxAcc = (horizMaxAccel / mMass) * TickSec;
  308. if (runSpeed > maxAcc)
  309. runAcc *= maxAcc / runSpeed;
  310. acc += runAcc;
  311. }
  312. else if (!mSwimming && airControl > 0.0f)
  313. {
  314. VectorF pv;
  315. pv = moveVec;
  316. F32 pvl = pv.len();
  317. if (pvl)
  318. pv *= moveSpeed / pvl;
  319. VectorF runAcc = pv - (mVelocity + acc);
  320. runAcc.z = 0;
  321. runAcc.x = runAcc.x * airControl;
  322. runAcc.y = runAcc.y * airControl;
  323. F32 runSpeed = runAcc.len();
  324. // We don't test for sprinting when performing air control
  325. F32 maxAcc = (horizMaxAccel / mMass) * TickSec * 0.3f;
  326. if (runSpeed > maxAcc)
  327. runAcc *= maxAcc / runSpeed;
  328. acc += runAcc;
  329. // There are no special air control animations
  330. // so... increment this unless you really want to
  331. // play the run anims in the air.
  332. mContactTimer++;
  333. }
  334. else if (mSwimming)
  335. {
  336. // Remove acc into contact surface (should only be gravity)
  337. // Clear out floating point acc errors, this will allow
  338. // the player to "rest" on the ground.
  339. F32 vd = -mDot(acc, mContactInfo.contactNormal);
  340. if (vd > 0.0f)
  341. {
  342. VectorF dv = mContactInfo.contactNormal * (vd + 0.002f);
  343. acc += dv;
  344. if (acc.len() < 0.0001f)
  345. acc.set(0.0f, 0.0f, 0.0f);
  346. }
  347. // get the head pitch and add it to the moveVec
  348. // This more accurate swim vector calc comes from Matt Fairfax
  349. MatrixF xRot;
  350. xRot.set(EulerF(mOwner->getRotation().asEulerF().x, 0, 0));
  351. zRot.set(EulerF(0, 0, mOwner->getRotation().asEulerF().z));//reset prior uses
  352. MatrixF rot;
  353. rot.mul(zRot, xRot);
  354. rot.getColumn(0, &moveVec);
  355. moveVec *= move->x;
  356. rot.getColumn(1, &tv);//reset prior uses
  357. moveVec += tv * move->y;
  358. rot.getColumn(2, &tv);
  359. moveVec += tv * move->z;
  360. // Force a 0 move if there is no energy, and only drain
  361. // move energy if we're moving.
  362. VectorF swimVec = moveVec;
  363. // If we are swimming but close enough to the shore/ground
  364. // we can still have a surface-normal. In this case align the
  365. // velocity to the normal to make getting out of water easier.
  366. moveVec.normalize();
  367. F32 isSwimUp = mDot(moveVec, mContactInfo.contactNormal);
  368. if (!mContactInfo.contactNormal.isZero() && isSwimUp < 0.1f)
  369. {
  370. F32 pvl = swimVec.len();
  371. if (pvl)
  372. {
  373. VectorF nn;
  374. mCross(swimVec, VectorF(0.0f, 0.0f, 1.0f), &nn);
  375. nn *= 1.0f / pvl;
  376. VectorF cv = mContactInfo.contactNormal;
  377. cv -= nn * mDot(nn, cv);
  378. swimVec -= cv * mDot(swimVec, cv);
  379. }
  380. }
  381. F32 swimVecLen = swimVec.len();
  382. // Convert to acceleration.
  383. if (swimVecLen)
  384. swimVec *= moveSpeed / swimVecLen;
  385. VectorF swimAcc = swimVec - (mVelocity + acc);
  386. F32 swimSpeed = swimAcc.len();
  387. // Clamp acceleration.
  388. F32 maxAcc = (horizMaxAccel / mMass) * TickSec;
  389. if (swimSpeed > maxAcc)
  390. swimAcc *= maxAcc / swimSpeed;
  391. acc += swimAcc;
  392. mContactTimer++;
  393. }
  394. else
  395. mContactTimer++;
  396. // Add in force from physical zones...
  397. acc += (mOwner->getContainerInfo().appliedForce / mMass) * TickSec;
  398. // Adjust velocity with all the move & gravity acceleration
  399. // TG: I forgot why doesn't the TickSec multiply happen here...
  400. mVelocity += acc;
  401. // apply horizontal air resistance
  402. F32 hvel = mSqrt(mVelocity.x * mVelocity.x + mVelocity.y * mVelocity.y);
  403. if (hvel > horizResistSpeed)
  404. {
  405. F32 speedCap = hvel;
  406. if (speedCap > horizMaxSpeed)
  407. speedCap = horizMaxSpeed;
  408. speedCap -= horizResistFactor * TickSec * (speedCap - horizResistSpeed);
  409. F32 scale = speedCap / hvel;
  410. mVelocity.x *= scale;
  411. mVelocity.y *= scale;
  412. }
  413. if (mVelocity.z > upResistSpeed)
  414. {
  415. if (mVelocity.z > upMaxSpeed)
  416. mVelocity.z = upMaxSpeed;
  417. mVelocity.z -= upResistFactor * TickSec * (mVelocity.z - upResistSpeed);
  418. }
  419. // Apply drag
  420. mVelocity -= mVelocity * mDrag * TickSec;
  421. // Clamp very small velocity to zero
  422. if (mVelocity.isZero())
  423. mVelocity = Point3F::Zero;
  424. // If we are not touching anything and have sufficient -z vel,
  425. // we are falling.
  426. if (mContactInfo.run)
  427. {
  428. mFalling = false;
  429. }
  430. else
  431. {
  432. VectorF vel;
  433. mOwner->getWorldToObj().mulV(mVelocity, &vel);
  434. mFalling = vel.z < fallingSpeedThreshold;
  435. }
  436. // Enter/Leave Liquid
  437. if (!mInWater && mOwner->getContainerInfo().waterCoverage > 0.0f)
  438. {
  439. mInWater = true;
  440. }
  441. else if (mInWater && mOwner->getContainerInfo().waterCoverage <= 0.0f)
  442. {
  443. mInWater = false;
  444. }
  445. }
  446. void PlayerControllerComponent::updatePos(const F32 travelTime)
  447. {
  448. if (!PHYSICSMGR)
  449. return;
  450. PROFILE_SCOPE(PlayerControllerComponent_UpdatePos);
  451. Point3F newPos;
  452. Collision col;
  453. dMemset(&col, 0, sizeof(col));
  454. static CollisionList collisionList;
  455. collisionList.clear();
  456. newPos = mPhysicsRep->move(mVelocity * travelTime, collisionList);
  457. bool haveCollisions = false;
  458. if (collisionList.getCount() > 0)
  459. {
  460. mFalling = false;
  461. haveCollisions = true;
  462. //TODO: clean this up so the phys component doesn't have to tell the col interface to do this
  463. CollisionComponent* colComp = mOwner->getComponent<CollisionComponent>();
  464. if (colComp)
  465. {
  466. colComp->handleCollisionList(collisionList, mVelocity);
  467. }
  468. }
  469. if (haveCollisions)
  470. {
  471. // Pick the collision that most closely matches our direction
  472. VectorF velNormal = mVelocity;
  473. velNormal.normalizeSafe();
  474. const Collision *collision = &collisionList[0];
  475. F32 collisionDot = mDot(velNormal, collision->normal);
  476. const Collision *cp = collision + 1;
  477. const Collision *ep = collision + collisionList.getCount();
  478. for (; cp != ep; cp++)
  479. {
  480. F32 dp = mDot(velNormal, cp->normal);
  481. if (dp < collisionDot)
  482. {
  483. collisionDot = dp;
  484. collision = cp;
  485. }
  486. }
  487. // Modify our velocity based on collisions
  488. for (U32 i = 0; i<collisionList.getCount(); ++i)
  489. {
  490. F32 bd = -mDot(mVelocity, collisionList[i].normal);
  491. VectorF dv = collisionList[i].normal * (bd + sNormalElasticity);
  492. mVelocity += dv;
  493. }
  494. // Store the last collision for use later on. The handle collision
  495. // code only expects a single collision object.
  496. if (collisionList.getCount() > 0)
  497. col = collisionList[collisionList.getCount() - 1];
  498. // We'll handle any player-to-player collision, and the last collision
  499. // with other obejct types.
  500. for (U32 i = 0; i<collisionList.getCount(); ++i)
  501. {
  502. Collision& colCheck = collisionList[i];
  503. if (colCheck.object)
  504. {
  505. col = colCheck;
  506. }
  507. }
  508. }
  509. updateContainer();
  510. MatrixF newMat;
  511. newMat.setPosition(newPos);
  512. mPhysicsRep->setTransform(newMat);
  513. mOwner->setPosition(newPos);
  514. }
  515. //
  516. void PlayerControllerComponent::setVelocity(const VectorF& vel)
  517. {
  518. mVelocity = vel;
  519. // Clamp against the maximum velocity.
  520. if (mMaxVelocity > 0)
  521. {
  522. F32 len = mVelocity.magnitudeSafe();
  523. if (len > mMaxVelocity)
  524. {
  525. Point3F excess = mVelocity * (1.0f - (mMaxVelocity / len));
  526. mVelocity -= excess;
  527. }
  528. }
  529. setMaskBits(VelocityMask);
  530. }
  531. void PlayerControllerComponent::findContact(bool *run, bool *jump, VectorF *contactNormal)
  532. {
  533. SceneObject *contactObject = NULL;
  534. Vector<SceneObject*> overlapObjects;
  535. mPhysicsRep->findContact(&contactObject, contactNormal, &overlapObjects);
  536. F32 vd = (*contactNormal).z;
  537. *run = vd > mCos(mDegToRad(moveSurfaceAngle));
  538. *jump = vd > mCos(mDegToRad(contactSurfaceAngle));
  539. // Check for triggers
  540. for (U32 i = 0; i < overlapObjects.size(); i++)
  541. {
  542. SceneObject *obj = overlapObjects[i];
  543. U32 objectMask = obj->getTypeMask();
  544. // Check: triggers, corpses and items...
  545. //
  546. if (objectMask & TriggerObjectType)
  547. {
  548. if (Trigger* pTrigger = dynamic_cast<Trigger*>(obj))
  549. {
  550. pTrigger->potentialEnterObject(mOwner);
  551. }
  552. else if (CollisionTrigger* pTriggerEx = dynamic_cast<CollisionTrigger*>(obj))
  553. {
  554. if (pTriggerEx)
  555. pTriggerEx->potentialEnterObject(mOwner);
  556. }
  557. //Add any other custom classes and the sort here that should be filtered against
  558. /*else if (TriggerExample* pTriggerEx = dynamic_cast<TriggerExample*>(obj))
  559. {
  560. if (pTriggerEx)
  561. pTriggerEx->potentialEnterObject(mOwner);
  562. }*/
  563. }
  564. }
  565. mContactInfo.contacted = contactObject != NULL;
  566. mContactInfo.contactObject = contactObject;
  567. if (mContactInfo.contacted)
  568. mContactInfo.contactNormal = *contactNormal;
  569. mContactInfo.run = *run;
  570. mContactInfo.jump = *jump;
  571. }
  572. void PlayerControllerComponent::applyImpulse(const Point3F &pos, const VectorF &vec)
  573. {
  574. AssertFatal(!mIsNaN(vec), "Player::applyImpulse() - The vector is NaN!");
  575. // Players ignore angular velocity
  576. VectorF vel;
  577. vel.x = vec.x / getMass();
  578. vel.y = vec.y / getMass();
  579. vel.z = vec.z / getMass();
  580. // Make sure the impulse isn't too bigg
  581. F32 len = vel.magnitudeSafe();
  582. if (len > sMaxImpulseVelocity)
  583. {
  584. Point3F excess = vel * (1.0f - (sMaxImpulseVelocity / len));
  585. vel -= excess;
  586. }
  587. setVelocity(mVelocity + vel);
  588. }
  589. DefineEngineMethod(PlayerControllerComponent, applyImpulse, bool, (Point3F pos, VectorF vel), ,
  590. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  591. "@param pos impulse world position\n"
  592. "@param vel impulse velocity (impulse force F = m * v)\n"
  593. "@return Always true\n"
  594. "@note Not all objects that derrive from GameBase have this defined.\n")
  595. {
  596. object->applyImpulse(pos, vel);
  597. return true;
  598. }
  599. DefineEngineMethod(PlayerControllerComponent, getContactNormal, Point3F, (), ,
  600. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  601. "@param pos impulse world position\n"
  602. "@param vel impulse velocity (impulse force F = m * v)\n"
  603. "@return Always true\n"
  604. "@note Not all objects that derrive from GameBase have this defined.\n")
  605. {
  606. return object->getContactNormal();
  607. }
  608. DefineEngineMethod(PlayerControllerComponent, getContactObject, SceneObject*, (), ,
  609. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  610. "@param pos impulse world position\n"
  611. "@param vel impulse velocity (impulse force F = m * v)\n"
  612. "@return Always true\n"
  613. "@note Not all objects that derrive from GameBase have this defined.\n")
  614. {
  615. return object->getContactObject();
  616. }
  617. DefineEngineMethod(PlayerControllerComponent, isContacted, bool, (), ,
  618. "@brief Apply an impulse to this object as defined by a world position and velocity vector.\n\n"
  619. "@param pos impulse world position\n"
  620. "@param vel impulse velocity (impulse force F = m * v)\n"
  621. "@return Always true\n"
  622. "@note Not all objects that derrive from GameBase have this defined.\n")
  623. {
  624. return object->isContacted();
  625. }