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.8 KiB

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