PhysicsPlayerController.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Physics2/PhysicsPlayerController.h>
  6. #include <AnKi/Physics2/PhysicsWorld.h>
  7. #include <AnKi/Physics2/PhysicsCollisionShape.h>
  8. namespace anki {
  9. namespace v2 {
  10. thread_local static StaticTempAllocator<1_MB> g_tempAllocator;
  11. PhysicsPlayerController::PhysicsPlayerController()
  12. : PhysicsObjectBase(PhysicsObjectType::kPlayerController)
  13. {
  14. }
  15. PhysicsPlayerController::~PhysicsPlayerController()
  16. {
  17. m_jphCharacter.destroy();
  18. }
  19. void PhysicsPlayerController::init(const PhysicsPlayerControllerInitInfo& init)
  20. {
  21. m_standingShape = PhysicsWorld::getSingleton().newCapsuleCollisionShape(init.m_standingHeight, init.m_waistWidth);
  22. m_crouchingShape = PhysicsWorld::getSingleton().newCapsuleCollisionShape(init.m_crouchingHeight, init.m_waistWidth);
  23. m_innerStandingShape =
  24. PhysicsWorld::getSingleton().newCapsuleCollisionShape(init.m_standingHeight * kInnerShapeFraction, init.m_waistWidth * kInnerShapeFraction);
  25. m_innerCrouchingShape =
  26. PhysicsWorld::getSingleton().newCapsuleCollisionShape(init.m_crouchingHeight * kInnerShapeFraction, init.m_waistWidth * kInnerShapeFraction);
  27. JPH::CharacterVirtualSettings settings;
  28. settings.SetEmbedded();
  29. settings.mMaxSlopeAngle = kMaxSlopeAngle;
  30. settings.mMaxStrength = kMaxStrength;
  31. settings.mShape = &m_standingShape->m_capsule;
  32. settings.mBackFaceMode = kBackFaceMode;
  33. settings.mCharacterPadding = kCharacterPadding;
  34. settings.mPenetrationRecoverySpeed = kPenetrationRecoverySpeed;
  35. settings.mPredictiveContactDistance = kPredictiveContactDistance;
  36. settings.mSupportingVolume = JPH::Plane(JPH::Vec3::sAxisY(), -init.m_waistWidth); // Accept contacts that touch the lower sphere of the capsule
  37. settings.mEnhancedInternalEdgeRemoval = kEnhancedInternalEdgeRemoval;
  38. settings.mInnerBodyShape = &m_innerStandingShape->m_capsule;
  39. settings.mInnerBodyLayer = JPH::ObjectLayer(PhysicsLayer::kPlayerController);
  40. m_jphCharacter.construct(&settings, toJPH(init.m_initialPosition), JPH::Quat::sIdentity(), ptrToNumber(static_cast<PhysicsObjectBase*>(this)),
  41. &PhysicsWorld::getSingleton().m_jphPhysicsSystem);
  42. m_position = init.m_initialPosition;
  43. setUserData(init.m_userData);
  44. }
  45. void PhysicsPlayerController::prePhysicsUpdate(Second dt)
  46. {
  47. const Bool bJump = m_input.m_jumpSpeed > 0.0f;
  48. const JPH::Vec3 inMovementDirection = toJPH(m_input.m_forwardDir);
  49. const Bool playerControlsHorizontalVelocity = m_controlMovementDuringJump || m_jphCharacter->IsSupported();
  50. if(playerControlsHorizontalVelocity)
  51. {
  52. // Smooth the player input
  53. m_desiredVelocity = kEnableCharacterInertia ? 0.25f * inMovementDirection * m_input.m_forwardSpeed + 0.75f * m_desiredVelocity
  54. : inMovementDirection * m_input.m_forwardSpeed;
  55. // True if the player intended to move
  56. m_allowSliding = !inMovementDirection.IsNearZero();
  57. }
  58. else
  59. {
  60. // While in air we allow sliding
  61. m_allowSliding = true;
  62. }
  63. // Update the character rotation and its up vector to match the up vector set by the user settings
  64. const JPH::Quat characterUpRotation = JPH::Quat::sEulerAngles(JPH::Vec3(0.0f, 0.0f, 0.0f));
  65. m_jphCharacter->SetUp(characterUpRotation.RotateAxisY());
  66. m_jphCharacter->SetRotation(characterUpRotation);
  67. // A cheaper way to update the character's ground velocity,
  68. // the platforms that the character is standing on may have changed velocity
  69. m_jphCharacter->UpdateGroundVelocity();
  70. // Determine new basic velocity
  71. const JPH::Vec3 currentVerticalVelocity = m_jphCharacter->GetLinearVelocity().Dot(m_jphCharacter->GetUp()) * m_jphCharacter->GetUp();
  72. const JPH::Vec3 groundVelocity = m_jphCharacter->GetGroundVelocity();
  73. JPH::Vec3 newVelocity;
  74. bool movingTowardsGround = (currentVerticalVelocity.GetY() - groundVelocity.GetY()) < 0.1f;
  75. if(m_jphCharacter->GetGroundState() == JPH::CharacterVirtual::EGroundState::OnGround // If on ground
  76. && (kEnableCharacterInertia
  77. ? movingTowardsGround // Inertia enabled: And not moving away from ground
  78. : !m_jphCharacter->IsSlopeTooSteep(m_jphCharacter->GetGroundNormal()))) // Inertia disabled: And not on a slope that is too steep
  79. {
  80. // Assume velocity of ground when on ground
  81. newVelocity = groundVelocity;
  82. // Jump
  83. if(bJump && movingTowardsGround)
  84. {
  85. newVelocity += m_input.m_jumpSpeed * m_jphCharacter->GetUp();
  86. }
  87. }
  88. else
  89. {
  90. newVelocity = currentVerticalVelocity;
  91. }
  92. // Gravity
  93. const auto& physicsSystem = *PhysicsWorld::getSingleton().m_jphPhysicsSystem;
  94. newVelocity += (characterUpRotation * physicsSystem.GetGravity()) * F32(dt);
  95. if(playerControlsHorizontalVelocity)
  96. {
  97. // Player input
  98. newVelocity += characterUpRotation * m_desiredVelocity;
  99. }
  100. else
  101. {
  102. // Preserve horizontal velocity
  103. const JPH::Vec3 currentHorizontalVelocity = m_jphCharacter->GetLinearVelocity() - currentVerticalVelocity;
  104. newVelocity += currentHorizontalVelocity;
  105. }
  106. // Update character velocity
  107. m_jphCharacter->SetLinearVelocity(newVelocity);
  108. // Stance switch
  109. if(m_crouching != m_input.m_crouching)
  110. {
  111. m_crouching = m_input.m_crouching;
  112. const Bool isStanding = m_jphCharacter->GetShape() == &m_standingShape->m_shapeBase;
  113. const JPH::Shape* shape = (isStanding) ? &m_crouchingShape->m_shapeBase : &m_standingShape->m_shapeBase;
  114. if(m_jphCharacter->SetShape(shape, 1.5f * physicsSystem.GetPhysicsSettings().mPenetrationSlop,
  115. physicsSystem.GetDefaultBroadPhaseLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)),
  116. physicsSystem.GetDefaultLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)), {}, {}, g_tempAllocator))
  117. {
  118. const JPH::Shape* innerShape = (isStanding) ? &m_innerCrouchingShape->m_capsule : &m_innerCrouchingShape->m_capsule;
  119. m_jphCharacter->SetInnerBodyShape(innerShape);
  120. }
  121. }
  122. if(m_input.m_updated)
  123. {
  124. m_input.m_updated = false;
  125. m_input = {};
  126. }
  127. // Settings for our update function
  128. JPH::CharacterVirtual::ExtendedUpdateSettings updateSettings;
  129. if(!kEnableStickToFloor)
  130. {
  131. updateSettings.mStickToFloorStepDown = JPH::Vec3::sZero();
  132. }
  133. else
  134. {
  135. updateSettings.mStickToFloorStepDown = -m_jphCharacter->GetUp() * updateSettings.mStickToFloorStepDown.Length();
  136. }
  137. if(!kEnableWalkStairs)
  138. {
  139. updateSettings.mWalkStairsStepUp = JPH::Vec3::sZero();
  140. }
  141. else
  142. {
  143. updateSettings.mWalkStairsStepUp = m_jphCharacter->GetUp() * updateSettings.mWalkStairsStepUp.Length();
  144. }
  145. // Update the character position
  146. JPH::PhysicsSystem& system = *PhysicsWorld::getSingleton().m_jphPhysicsSystem;
  147. m_jphCharacter->ExtendedUpdate(F32(dt), -m_jphCharacter->GetUp() * system.GetGravity().Length(), updateSettings,
  148. system.GetDefaultBroadPhaseLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)),
  149. system.GetDefaultLayerFilter(JPH::ObjectLayer(PhysicsLayer::kPlayerController)), {}, {}, g_tempAllocator);
  150. }
  151. void PhysicsPlayerController::postPhysicsUpdate()
  152. {
  153. const Vec3 newPos = toAnKi(m_jphCharacter->GetPosition());
  154. if(newPos != m_position)
  155. {
  156. m_position = newPos;
  157. ++m_positionVersion;
  158. }
  159. }
  160. } // namespace v2
  161. } // namespace anki