CharacterSpaceShipTest.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2023 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include <TestFramework.h>
  5. #include <Tests/Character/CharacterSpaceShipTest.h>
  6. #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
  7. #include <Jolt/Physics/Collision/Shape/RotatedTranslatedShape.h>
  8. #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
  9. #include <Jolt/Physics/Collision/Shape/CylinderShape.h>
  10. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  11. #include <Layers.h>
  12. JPH_IMPLEMENT_RTTI_VIRTUAL(CharacterSpaceShipTest)
  13. {
  14. JPH_ADD_BASE_CLASS(CharacterSpaceShipTest, Test)
  15. }
  16. void CharacterSpaceShipTest::Initialize()
  17. {
  18. // Dimensions of our space ship
  19. constexpr float cSpaceShipHeight = 2.0f;
  20. constexpr float cSpaceShipRingHeight = 0.2f;
  21. constexpr float cSpaceShipRadius = 100.0f;
  22. const RVec3 cShipInitialPosition(-25, 15, 0);
  23. // Create floor for reference
  24. CreateFloor();
  25. // Create 'player' character
  26. Ref<CharacterVirtualSettings> settings = new CharacterVirtualSettings();
  27. settings->mShape = RotatedTranslatedShapeSettings(Vec3(0, 0.5f * cCharacterHeightStanding + cCharacterRadiusStanding, 0), Quat::sIdentity(), new CapsuleShape(0.5f * cCharacterHeightStanding, cCharacterRadiusStanding)).Create().Get();
  28. settings->mSupportingVolume = Plane(Vec3::sAxisY(), -cCharacterRadiusStanding); // Accept contacts that touch the lower sphere of the capsule
  29. mCharacter = new CharacterVirtual(settings, cShipInitialPosition + Vec3(0, cSpaceShipHeight, 0), Quat::sIdentity(), 0, mPhysicsSystem);
  30. mCharacter->SetListener(this);
  31. // Create the space ship
  32. StaticCompoundShapeSettings compound;
  33. compound.SetEmbedded();
  34. for (float h = cSpaceShipRingHeight; h < cSpaceShipHeight; h += cSpaceShipRingHeight)
  35. compound.AddShape(Vec3::sZero(), Quat::sIdentity(), new CylinderShape(h, sqrt(Square(cSpaceShipRadius) - Square(cSpaceShipRadius - cSpaceShipHeight - cSpaceShipRingHeight + h))));
  36. mSpaceShip = mBodyInterface->CreateAndAddBody(BodyCreationSettings(&compound, cShipInitialPosition, Quat::sIdentity(), EMotionType::Kinematic, Layers::MOVING), EActivation::Activate);
  37. mSpaceShipPrevTransform = mBodyInterface->GetCenterOfMassTransform(mSpaceShip);
  38. }
  39. void CharacterSpaceShipTest::ProcessInput(const ProcessInputParams &inParams)
  40. {
  41. // Determine controller input
  42. Vec3 control_input = Vec3::sZero();
  43. if (inParams.mKeyboard->IsKeyPressed(DIK_LEFT)) control_input.SetZ(-1);
  44. if (inParams.mKeyboard->IsKeyPressed(DIK_RIGHT)) control_input.SetZ(1);
  45. if (inParams.mKeyboard->IsKeyPressed(DIK_UP)) control_input.SetX(1);
  46. if (inParams.mKeyboard->IsKeyPressed(DIK_DOWN)) control_input.SetX(-1);
  47. if (control_input != Vec3::sZero())
  48. control_input = control_input.Normalized();
  49. // Calculate the desired velocity in local space to the ship based on the camera forward
  50. RMat44 new_space_ship_transform = mBodyInterface->GetCenterOfMassTransform(mSpaceShip);
  51. Vec3 cam_fwd = new_space_ship_transform.GetRotation().Multiply3x3Transposed(inParams.mCameraState.mForward);
  52. cam_fwd.SetY(0.0f);
  53. cam_fwd = cam_fwd.NormalizedOr(Vec3::sAxisX());
  54. Quat rotation = Quat::sFromTo(Vec3::sAxisX(), cam_fwd);
  55. control_input = rotation * control_input;
  56. // Smooth the player input in local space to the ship
  57. mDesiredVelocity = 0.25f * control_input * cCharacterSpeed + 0.75f * mDesiredVelocity;
  58. // Check actions
  59. mJump = inParams.mKeyboard->IsKeyPressedAndTriggered(DIK_RCONTROL, mWasJump);
  60. }
  61. void CharacterSpaceShipTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
  62. {
  63. // Update scene time
  64. mTime += inParams.mDeltaTime;
  65. // Update the character so it stays relative to the space ship
  66. RMat44 new_space_ship_transform = mBodyInterface->GetCenterOfMassTransform(mSpaceShip);
  67. mCharacter->SetPosition(new_space_ship_transform * mSpaceShipPrevTransform.Inversed() * mCharacter->GetPosition());
  68. // Update the character rotation and its up vector to match the new up vector of the ship
  69. mCharacter->SetUp(new_space_ship_transform.GetAxisY());
  70. mCharacter->SetRotation(new_space_ship_transform.GetQuaternion());
  71. // Draw character pre update (the sim is also drawn pre update)
  72. // Note that we have first updated the position so that it matches the new position of the ship
  73. #ifdef JPH_DEBUG_RENDERER
  74. mCharacter->GetShape()->Draw(mDebugRenderer, mCharacter->GetCenterOfMassTransform(), Vec3::sReplicate(1.0f), Color::sGreen, false, true);
  75. #endif // JPH_DEBUG_RENDERER
  76. // Determine new character velocity
  77. Vec3 current_vertical_velocity = mCharacter->GetLinearVelocity().Dot(mSpaceShipPrevTransform.GetAxisY()) * mCharacter->GetUp();
  78. Vec3 ground_velocity = mCharacter->GetGroundVelocity();
  79. Vec3 new_velocity;
  80. if (mCharacter->GetGroundState() == CharacterVirtual::EGroundState::OnGround // If on ground
  81. && (current_vertical_velocity.GetY() - ground_velocity.GetY()) < 0.1f) // And not moving away from ground
  82. {
  83. // Assume velocity of ground when on ground
  84. new_velocity = ground_velocity;
  85. // Jump
  86. if (mJump)
  87. new_velocity += cJumpSpeed * mCharacter->GetUp();
  88. }
  89. else
  90. new_velocity = current_vertical_velocity;
  91. // Gravity always acts relative to the ship
  92. Vec3 gravity = new_space_ship_transform.Multiply3x3(mPhysicsSystem->GetGravity());
  93. new_velocity += gravity * inParams.mDeltaTime;
  94. // Transform player input to world space
  95. new_velocity += new_space_ship_transform.Multiply3x3(mDesiredVelocity);
  96. // Update character velocity
  97. mCharacter->SetLinearVelocity(new_velocity);
  98. // Update the character position
  99. CharacterVirtual::ExtendedUpdateSettings update_settings;
  100. mCharacter->ExtendedUpdate(inParams.mDeltaTime,
  101. gravity,
  102. update_settings,
  103. mPhysicsSystem->GetDefaultBroadPhaseLayerFilter(Layers::MOVING),
  104. mPhysicsSystem->GetDefaultLayerFilter(Layers::MOVING),
  105. { },
  106. { },
  107. *mTempAllocator);
  108. // Update previous transform
  109. mSpaceShipPrevTransform = new_space_ship_transform;
  110. // Calculate new velocity
  111. UpdateShipVelocity();
  112. }
  113. void CharacterSpaceShipTest::UpdateShipVelocity()
  114. {
  115. // Make it a rocky ride...
  116. mSpaceShipLinearVelocity = Vec3(Sin(mTime), 0, Cos(mTime)) * 50.0f;
  117. mSpaceShipAngularVelocity = Vec3(Sin(2.0f * mTime), 1, Cos(2.0f * mTime)) * 0.5f;
  118. mBodyInterface->SetLinearAndAngularVelocity(mSpaceShip, mSpaceShipLinearVelocity, mSpaceShipAngularVelocity);
  119. }
  120. void CharacterSpaceShipTest::GetInitialCamera(CameraState& ioState) const
  121. {
  122. // This will become the local space offset, look down the x axis and slightly down
  123. ioState.mPos = RVec3::sZero();
  124. ioState.mForward = Vec3(10.0f, -2.0f, 0).Normalized();
  125. }
  126. RMat44 CharacterSpaceShipTest::GetCameraPivot(float inCameraHeading, float inCameraPitch) const
  127. {
  128. // Pivot is center of character + distance behind based on the heading and pitch of the camera
  129. Vec3 fwd = Vec3(Cos(inCameraPitch) * Cos(inCameraHeading), Sin(inCameraPitch), Cos(inCameraPitch) * Sin(inCameraHeading));
  130. return RMat44::sTranslation(mCharacter->GetPosition() + Vec3(0, cCharacterHeightStanding + cCharacterRadiusStanding, 0) - 5.0f * fwd);
  131. }
  132. void CharacterSpaceShipTest::SaveState(StateRecorder &inStream) const
  133. {
  134. mCharacter->SaveState(inStream);
  135. inStream.Write(mTime);
  136. inStream.Write(mSpaceShipPrevTransform);
  137. }
  138. void CharacterSpaceShipTest::RestoreState(StateRecorder &inStream)
  139. {
  140. mCharacter->RestoreState(inStream);
  141. inStream.Read(mTime);
  142. inStream.Read(mSpaceShipPrevTransform);
  143. // Calculate new velocity
  144. UpdateShipVelocity();
  145. }
  146. void CharacterSpaceShipTest::SaveInputState(StateRecorder &inStream) const
  147. {
  148. inStream.Write(mDesiredVelocity);
  149. inStream.Write(mJump);
  150. }
  151. void CharacterSpaceShipTest::RestoreInputState(StateRecorder &inStream)
  152. {
  153. inStream.Read(mDesiredVelocity);
  154. inStream.Read(mJump);
  155. }
  156. void CharacterSpaceShipTest::OnAdjustBodyVelocity(const CharacterVirtual *inCharacter, const Body &inBody2, Vec3 &ioLinearVelocity, Vec3 &ioAngularVelocity)
  157. {
  158. // Cancel out velocity of space ship, we move relative to this which means we don't feel any of the acceleration of the ship (= engage inertial dampeners!)
  159. ioLinearVelocity -= mSpaceShipLinearVelocity;
  160. ioAngularVelocity -= mSpaceShipAngularVelocity;
  161. }