simplePhysicsComponent.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. //-----------------------------------------------------------------------------
  2. // Torque Game Engine
  3. // Copyright (C) GarageGames.com, Inc.
  4. //-----------------------------------------------------------------------------
  5. #include "T3D/components/physics/simplePhysicsComponent.h"
  6. #include "T3D/components/collision/collisionComponent.h"
  7. #include "platform/platform.h"
  8. #include "console/consoleTypes.h"
  9. #include "core/util/safeDelete.h"
  10. #include "core/resourceManager.h"
  11. #include "core/stream/fileStream.h"
  12. #include "console/consoleTypes.h"
  13. #include "console/consoleObject.h"
  14. #include "ts/tsShapeInstance.h"
  15. #include "core/stream/bitStream.h"
  16. #include "gfx/gfxTransformSaver.h"
  17. #include "console/engineAPI.h"
  18. #include "lighting/lightQuery.h"
  19. #include "T3D/gameBase/gameConnection.h"
  20. #include "collision/collision.h"
  21. //////////////////////////////////////////////////////////////////////////
  22. // Callbacks
  23. IMPLEMENT_CALLBACK( SimplePhysicsComponent, updateMove, void, ( SimplePhysicsComponent* obj ), ( obj ),
  24. "Called when the player updates it's movement, only called if object is set to callback in script(doUpdateMove).\n"
  25. "@param obj the Player object\n" );
  26. //////////////////////////////////////////////////////////////////////////
  27. // Constructor/Destructor
  28. //////////////////////////////////////////////////////////////////////////
  29. SimplePhysicsComponent::SimplePhysicsComponent() : PhysicsComponent()
  30. {
  31. mBuoyancy = 0.f;
  32. mFriction = 0.3f;
  33. mElasticity = 0.4f;
  34. mMaxVelocity = 3000.f;
  35. mSticky = false;
  36. mDrag = 0.5;
  37. mVelocity = Point3F::Zero;
  38. moveSpeed = Point3F(1, 1, 1);
  39. mFriendlyName = "Simple Physics";
  40. mComponentType = "Physics";
  41. mDescription = getDescriptionText("Simple physics Component that allows gravity and impulses.");
  42. }
  43. SimplePhysicsComponent::~SimplePhysicsComponent()
  44. {
  45. for(S32 i = 0;i < mFields.size();++i)
  46. {
  47. ComponentField &field = mFields[i];
  48. SAFE_DELETE_ARRAY(field.mFieldDescription);
  49. }
  50. SAFE_DELETE_ARRAY(mDescription);
  51. }
  52. IMPLEMENT_CONOBJECT(SimplePhysicsComponent);
  53. //////////////////////////////////////////////////////////////////////////
  54. bool SimplePhysicsComponent::onAdd()
  55. {
  56. if(! Parent::onAdd())
  57. return false;
  58. return true;
  59. }
  60. void SimplePhysicsComponent::onRemove()
  61. {
  62. Parent::onRemove();
  63. }
  64. void SimplePhysicsComponent::initPersistFields()
  65. {
  66. Parent::initPersistFields();
  67. addField( "moveSpeed", TypePoint3F, Offset(moveSpeed, SimplePhysicsComponent), "");
  68. }
  69. U32 SimplePhysicsComponent::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  70. {
  71. U32 retMask = Parent::packUpdate(con, mask, stream);
  72. return retMask;
  73. }
  74. void SimplePhysicsComponent::unpackUpdate(NetConnection *con, BitStream *stream)
  75. {
  76. Parent::unpackUpdate(con, stream);
  77. }
  78. //
  79. void SimplePhysicsComponent::processTick()
  80. {
  81. Parent::processTick();
  82. if (!isServerObject() || !isActive())
  83. return;
  84. //
  85. //if (mCollisionObject && !--mCollisionTimeout)
  86. // mCollisionObject = 0;
  87. // Warp to catch up to server
  88. if (mDelta.warpCount < mDelta.warpTicks)
  89. {
  90. mDelta.warpCount++;
  91. // Set new pos.
  92. mOwner->getTransform().getColumn(3,&mDelta.pos);
  93. mDelta.pos += mDelta.warpOffset;
  94. //mDelta.rot[0] = mDelta.rot[1];
  95. //mDelta.rot[1].interpolate(mDelta.warpRot[0],mDelta.warpRot[1],F32(mDelta.warpCount)/mDelta.warpTicks);
  96. MatrixF trans;
  97. mDelta.rot[1].setMatrix(&trans);
  98. trans.setPosition(mDelta.pos);
  99. setTransform(trans);
  100. // Pos backstepping
  101. mDelta.posVec.x = -mDelta.warpOffset.x;
  102. mDelta.posVec.y = -mDelta.warpOffset.y;
  103. mDelta.posVec.z = -mDelta.warpOffset.z;
  104. }
  105. else
  106. {
  107. // Save current rigid state interpolation
  108. mDelta.posVec = mOwner->getPosition();
  109. //mDelta.rot[0] = mOwner->getTransform();
  110. updateForces();
  111. updatePos(TickSec);
  112. // Wrap up interpolation info
  113. mDelta.pos = mOwner->getPosition();
  114. mDelta.posVec -= mOwner->getPosition();
  115. //mDelta.rot[1] = mRigid.angPosition;
  116. // Update container database
  117. setTransform(mOwner->getTransform());
  118. setMaskBits(UpdateMask);
  119. updateContainer();
  120. }
  121. }
  122. void SimplePhysicsComponent::interpolateTick(F32 dt)
  123. {
  124. // Client side interpolation
  125. Point3F pos = mDelta.pos + mDelta.posVec * dt;
  126. MatrixF mat = mOwner->getRenderTransform();
  127. mat.setColumn(3,pos);
  128. mOwner->setRenderTransform(mat);
  129. mDelta.dt = dt;
  130. }
  131. void SimplePhysicsComponent::updatePos(const F32 travelTime)
  132. {
  133. mOwner->getTransform().getColumn(3,&mDelta.posVec);
  134. // When mounted to another object, only Z rotation used.
  135. if (mOwner->isMounted()) {
  136. mVelocity = mOwner->getObjectMount()->getVelocity();
  137. setPosition(Point3F(0.0f, 0.0f, 0.0f));
  138. setMaskBits(UpdateMask);
  139. return;
  140. }
  141. Point3F newPos;
  142. if ( mVelocity.isZero() )
  143. newPos = mDelta.posVec;
  144. else
  145. newPos = _move( travelTime );
  146. //}
  147. // Set new position
  148. // If on the client, calc delta for backstepping
  149. if (isClientObject())
  150. {
  151. mDelta.pos = newPos;
  152. mDelta.posVec = mDelta.posVec - mDelta.pos;
  153. mDelta.dt = 1.0f;
  154. }
  155. setPosition( newPos );
  156. setMaskBits( UpdateMask );
  157. updateContainer();
  158. /*if (!isGhost())
  159. {
  160. // Do mission area callbacks on the server as well
  161. checkMissionArea();
  162. }*/
  163. return;
  164. }
  165. Point3F SimplePhysicsComponent::_move( const F32 travelTime )
  166. {
  167. // Try and move to new pos
  168. F32 totalMotion = 0.0f;
  169. Point3F start;
  170. Point3F initialPosition;
  171. mOwner->getTransform().getColumn(3,&start);
  172. initialPosition = start;
  173. VectorF firstNormal(0.0f, 0.0f, 0.0f);
  174. //F32 maxStep = mDataBlock->maxStepHeight;
  175. F32 time = travelTime;
  176. U32 count = 0;
  177. S32 sMoveRetryCount = 5;
  178. CollisionComponent* colComp = mOwner->getComponent<CollisionComponent>();
  179. if(!colComp)
  180. return start + mVelocity * time;
  181. colComp->clearCollisionList();
  182. for (; count < sMoveRetryCount; count++)
  183. {
  184. F32 speed = mVelocity.len();
  185. if (!speed)
  186. break;
  187. Point3F end = start + mVelocity * time;
  188. Point3F distance = end - start;
  189. bool collided = colComp->checkCollisions(time, &mVelocity, start);
  190. if (colComp->getCollisionList()->getCount() != 0 && colComp->getCollisionList()->getTime() < 1.0f)
  191. {
  192. // Set to collision point
  193. F32 velLen = mVelocity.len();
  194. F32 dt = time * getMin(colComp->getCollisionList()->getTime(), 1.0f);
  195. start += mVelocity * dt;
  196. time -= dt;
  197. totalMotion += velLen * dt;
  198. // Back off...
  199. if ( velLen > 0.f )
  200. {
  201. F32 newT = getMin(0.01f / velLen, dt);
  202. start -= mVelocity * newT;
  203. totalMotion -= velLen * newT;
  204. }
  205. // Pick the surface most parallel to the face that was hit.
  206. U32 colCount = colComp->getCollisionList()->getCount();
  207. const Collision *collision = colComp->getCollision(0);
  208. const Collision *cp = collision + 1;
  209. const Collision *ep = collision + colComp->getCollisionList()->getCount();
  210. for (; cp != ep; cp++)
  211. {
  212. U32 colCountLoop = colComp->getCollisionList()->getCount();
  213. //TODO: Move this somewhere else
  214. if(Entity* colEnt = dynamic_cast<Entity*>(collision->object))
  215. {
  216. if(CollisionComponent *collidingEntityColComp = colEnt->getComponent<CollisionComponent>())
  217. {
  218. if(!collidingEntityColComp->doesBlockColliding())
  219. {
  220. continue;
  221. }
  222. }
  223. }
  224. if (cp->faceDot > collision->faceDot)
  225. collision = cp;
  226. }
  227. //check the last/first one just incase
  228. if(Entity* colEnt = dynamic_cast<Entity*>(collision->object))
  229. {
  230. if(CollisionComponent *collidingEntityColComp = colEnt->getComponent<CollisionComponent>())
  231. {
  232. if(!collidingEntityColComp->doesBlockColliding())
  233. {
  234. //if our ideal surface doesn't stop us, just move along
  235. return start + mVelocity * time;
  236. }
  237. }
  238. }
  239. //F32 bd = _doCollisionImpact( collision, wasFalling );
  240. F32 bd = -mDot( mVelocity, collision->normal);
  241. // Subtract out velocity
  242. F32 sNormalElasticity = 0.01f;
  243. VectorF dv = collision->normal * (bd + sNormalElasticity);
  244. mVelocity += dv;
  245. if (count == 0)
  246. {
  247. firstNormal = collision->normal;
  248. }
  249. else
  250. {
  251. if (count == 1)
  252. {
  253. // Re-orient velocity along the crease.
  254. if (mDot(dv,firstNormal) < 0.0f &&
  255. mDot(collision->normal,firstNormal) < 0.0f)
  256. {
  257. VectorF nv;
  258. mCross(collision->normal,firstNormal,&nv);
  259. F32 nvl = nv.len();
  260. if (nvl)
  261. {
  262. if (mDot(nv,mVelocity) < 0.0f)
  263. nvl = -nvl;
  264. nv *= mVelocity.len() / nvl;
  265. mVelocity = nv;
  266. }
  267. }
  268. }
  269. }
  270. }
  271. else
  272. {
  273. totalMotion += (end - start).len();
  274. start = end;
  275. break;
  276. }
  277. }
  278. U32 colCountThree = colComp->getCollisionList()->getCount();
  279. if (colCountThree != 0)
  280. bool derp = true;
  281. if (count == sMoveRetryCount)
  282. {
  283. // Failed to move
  284. start = initialPosition;
  285. mVelocity.set(0.0f, 0.0f, 0.0f);
  286. }
  287. return start;
  288. }
  289. void SimplePhysicsComponent::updateForces()
  290. {
  291. // Acceleration due to gravity
  292. mVelocity += (mGravity * mGravityMod) * TickMs;
  293. F32 len = mVelocity.len();
  294. if (mMaxVelocity > 0 && mAbs(len) > mMaxVelocity)
  295. {
  296. Point3F excess = mVelocity * (1.0 - (mMaxVelocity / len));
  297. excess *= 0.1f;
  298. mVelocity -= excess;
  299. }
  300. // Container buoyancy & drag
  301. if(mOwner->getContainerInfo().waterCoverage > 0.65f)
  302. mVelocity -= mBuoyancy * (mGravity * mGravityMod) * TickMs;
  303. mVelocity -= mVelocity * mDrag * TickMs;
  304. if( mVelocity.isZero() )
  305. mVelocity = Point3F::Zero;
  306. else
  307. setMaskBits(VelocityMask);
  308. }
  309. //
  310. void SimplePhysicsComponent::setVelocity(const VectorF& vel)
  311. {
  312. Parent::setVelocity(vel);
  313. // Clamp against the maximum velocity.
  314. if ( mMaxVelocity > 0 )
  315. {
  316. F32 len = mVelocity.magnitudeSafe();
  317. if ( len > mMaxVelocity )
  318. {
  319. Point3F excess = mVelocity * ( 1.0f - (mMaxVelocity / len ) );
  320. mVelocity -= excess;
  321. }
  322. }
  323. }