選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

bulletcharactercontroller.cpp 8.9 KiB

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 */