25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

242 lines
8.8 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net>
  5. // (c) 2009-2013 Cédric 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 "core.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 */