You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bulletcharactercontroller.cpp 8.9 KiB

преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
преди 12 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
  5. // (c) 2009-2013 Cdric Lecacheur <jordx@free.fr>
  6. // (c) 2009-2013 Benjamin "Touky" Huet <huet.benjamin@gmail.com>
  7. // This program is free software; you can redistribute it and/or
  8. // modify it under the terms of the Do What The Fuck You Want To
  9. // Public License, Version 2, as published by Sam Hocevar. See
  10. // http://www.wtfpl.net/ for more details.
  11. //
  12. #if defined HAVE_CONFIG_H
  13. # include "config.h"
  14. #endif
  15. #define USE_LOL_CTRLR_CHARAC
  16. #ifdef HAVE_PHYS_USE_BULLET
  17. #include "core.h"
  18. #include <stdio.h>
  19. #include "lolbtphysicsintegration.h"
  20. #include "lolphysics.h"
  21. #include "easycharactercontroller.h"
  22. #include "bulletcharactercontroller.h"
  23. //#include "LinearMath/btIDebugDraw.h"
  24. //#include "BulletCollision/CollisionDispatch/btGhostObject.h"
  25. //#include "BulletCollision/CollisionShapes/btMultiSphereShape.h"
  26. //#include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h"
  27. //#include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h"
  28. //#include "BulletCollision/CollisionDispatch/btCollisionWorld.h"
  29. //#include "LinearMath/btDefaultMotionState.h"
  30. #endif //HAVE_PHYS_USE_BULLET
  31. namespace lol
  32. {
  33. namespace phys
  34. {
  35. #ifdef USE_LOL_CTRLR_CHARAC
  36. #ifdef HAVE_PHYS_USE_BULLET
  37. //When called, will try to remove Character controller from its collision.
  38. bool BulletKinematicCharacterController::RecoverFromPenetration(btCollisionWorld* CollisionWorld)
  39. {
  40. bool HasPenetration = false;
  41. //Retrieve all pair with us colliding.
  42. CollisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghost_object->getOverlappingPairCache(), CollisionWorld->getDispatchInfo(), CollisionWorld->getDispatcher());
  43. m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin());
  44. float MaxPen = .0f;
  45. for (int i = 0; i < m_ghost_object->getOverlappingPairCache()->getNumOverlappingPairs(); i++)
  46. {
  47. m_manifold_array.resize(0);
  48. //this is the equivalent of the "Touch algorithm". Maybe refactor ?
  49. btBroadphasePair* CollisionPair = &m_ghost_object->getOverlappingPairCache()->getOverlappingPairArray()[i];
  50. if (CollisionPair->m_algorithm)
  51. CollisionPair->m_algorithm->getAllContactManifolds(m_manifold_array);
  52. for (int j = 0; j < m_manifold_array.size(); ++j)
  53. {
  54. btPersistentManifold* CurMfold = m_manifold_array[j];
  55. //Normal direction differs if we're Body0
  56. float DirSign = CurMfold->getBody0() == m_ghost_object ? -1.f : 1.f;
  57. for (int k = 0; k < CurMfold->getNumContacts(); k++)
  58. {
  59. const btManifoldPoint& MfPoint = CurMfold->getContactPoint(k);
  60. float Dist = MfPoint.getDistance();
  61. if (Dist < .0f)
  62. {
  63. if (Dist < MaxPen)
  64. {
  65. MaxPen = Dist;
  66. m_touching_normal = BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign;
  67. }
  68. m_current_position += BT2LOL_VEC3(MfPoint.m_normalWorldOnB) * DirSign * Dist * .2f;
  69. HasPenetration = true;
  70. }
  71. }
  72. }
  73. }
  74. btTransform GObjMx = m_ghost_object->getWorldTransform();
  75. GObjMx.setOrigin(LOL2BTU_VEC3(m_current_position));
  76. m_ghost_object->setWorldTransform(GObjMx);
  77. return HasPenetration;
  78. }
  79. //When the Controller hits a wall, we modify the target so the controller will MoveStep along the wall.
  80. void BulletKinematicCharacterController::UpdateTargetOnHit(const vec3& HitNormal, float TangentMag, float NormalMag)
  81. {
  82. vec3 Movedir = m_target_position - m_current_position;
  83. float MoveLength = (float)length(Movedir);
  84. if (MoveLength > SIMD_EPSILON)
  85. {
  86. Movedir = normalize(Movedir);
  87. vec3 ReflectDir = normalize(GetReflectedDir(Movedir, HitNormal));
  88. vec3 ParallelDir = ProjectDirOnNorm(ReflectDir, HitNormal);
  89. vec3 PerpindicularDir = ProjectDirOnNormPerpindicular(ReflectDir, HitNormal);
  90. m_target_position = m_current_position;
  91. if (NormalMag != .0f)
  92. m_target_position += PerpindicularDir * NormalMag * MoveLength;
  93. }
  94. }
  95. //Handles the actual Movement. It actually moves in the 3 dimensions, function name is confusing.
  96. void BulletKinematicCharacterController::DoMove(btCollisionWorld* CollisionWorld, const vec3& MoveStep, float DeltaTime)
  97. {
  98. // phase 2: forward and strafe
  99. m_target_position = m_current_position + MoveStep;
  100. btTransform SweepStart, SweepEnd;
  101. SweepStart.setIdentity();
  102. SweepEnd.setIdentity();
  103. float Fraction = 1.f;
  104. float SqDist = .0f;
  105. if (m_touching_contact && dot(m_normalized_direction, m_touching_normal) > .0f)
  106. UpdateTargetOnHit(m_touching_normal);
  107. //Let's loop on movement, until Movement fraction if below 0.01, which means we've reached our destination.
  108. //Or until we'tried 10 times.
  109. int MaxMoveLoop = 10;
  110. while (Fraction > .01f && MaxMoveLoop-- > 0)
  111. {
  112. SweepStart.setOrigin(LOL2BTU_VEC3(m_current_position));
  113. SweepEnd.setOrigin(LOL2BTU_VEC3(m_target_position));
  114. vec3 SweepDirNeg(m_current_position - m_target_position);
  115. ClosestNotMeConvexResultCallback SweepCallback(m_ghost_object, SweepDirNeg, .0f);
  116. SweepCallback.m_collisionFilterGroup = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
  117. SweepCallback.m_collisionFilterMask = GetGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
  118. //The sweep test is done with an added margin, so we use it and then discard it
  119. float SavedMargin = m_convex_shape->getMargin();
  120. m_convex_shape->setMargin(SavedMargin + m_added_margin); //Apply Added Margin
  121. if (m_do_gobject_sweep_test)
  122. m_ghost_object->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  123. else
  124. CollisionWorld->convexSweepTest (m_convex_shape, SweepStart, SweepEnd, SweepCallback, CollisionWorld->getDispatchInfo().m_allowedCcdPenetration);
  125. m_convex_shape->setMargin(SavedMargin); //Restore saved margin
  126. Fraction -= SweepCallback.m_closestHitFraction;
  127. if (SweepCallback.hasHit())
  128. {
  129. //We moved only a Fraction
  130. float HitDist = (float)length(BT2LOLU_VEC3(SweepCallback.m_hitPointWorld) - m_current_position);
  131. UpdateTargetOnHit(BT2LOL_VEC3(SweepCallback.m_hitNormalWorld));
  132. vec3 NewDir = m_target_position - m_current_position;
  133. SqDist = sqlength(NewDir);
  134. if (SqDist > SIMD_EPSILON)
  135. {
  136. NewDir = normalize(NewDir);
  137. //See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners."
  138. if (dot(NewDir, m_normalized_direction) <= .0f)
  139. break;
  140. }
  141. else
  142. break;
  143. }
  144. else //We moved whole way
  145. m_current_position = m_target_position;
  146. }
  147. }
  148. //The PreStep is done in order to recover from any HasPenetration.
  149. void BulletKinematicCharacterController::PreStep(btCollisionWorld* CollisionWorld)
  150. {
  151. int MaxPenetrationLoop = 0;
  152. m_touching_contact = false;
  153. while (RecoverFromPenetration(CollisionWorld))
  154. {
  155. MaxPenetrationLoop++;
  156. m_touching_contact = true;
  157. if (MaxPenetrationLoop > 4)
  158. break;
  159. }
  160. m_current_position = BT2LOLU_VEC3(m_ghost_object->getWorldTransform().getOrigin());
  161. m_target_position = m_current_position;
  162. }
  163. //And so we step :
  164. //StepUpfirst, then movement, then StepDownon the ground.
  165. void BulletKinematicCharacterController::PlayerStep(btCollisionWorld* CollisionWorld, float DeltaTime)
  166. {
  167. // quick check...
  168. if (!m_use_walk_direction && m_velocity_time_interval <= .0f)
  169. return; // no motion
  170. // Update fall velocity.
  171. //m_velocity -= m_gravity * DeltaTime;
  172. btTransform NewTransform;
  173. NewTransform = m_ghost_object->getWorldTransform();
  174. vec3 MoveStep(.0f);
  175. if (m_use_walk_direction)
  176. MoveStep = m_walk_direction;
  177. else
  178. {
  179. //Still have some time left for moving!
  180. float dtMoving = (DeltaTime < m_velocity_time_interval) ? DeltaTime : m_velocity_time_interval;
  181. m_velocity_time_interval -= DeltaTime;
  182. // how far will we MoveStep while we are moving?
  183. MoveStep = m_walk_direction * dtMoving;
  184. }
  185. //Okay, step !
  186. DoMove(CollisionWorld, MoveStep, DeltaTime);
  187. //Movement finished, update World transform
  188. NewTransform.setOrigin(LOL2BTU_VEC3(m_current_position));
  189. m_ghost_object->setWorldTransform(NewTransform);
  190. }
  191. //should MoveStep Jump logic in EasyCC
  192. void BulletKinematicCharacterController::Jump()
  193. {
  194. if (!CanJump())
  195. return;
  196. m_vertical_velocity = m_jump_speed;
  197. m_was_jumping = true;
  198. }
  199. #endif // HAVE_PHYS_USE_BULLET
  200. #endif // USE_LOL_CTRLR_CHARAC
  201. } /* namespace phys */
  202. } /* namespace lol */