PhysicsStepListenerTests.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
  2. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  3. // SPDX-License-Identifier: MIT
  4. #include "UnitTestFramework.h"
  5. #include "PhysicsTestContext.h"
  6. #include "Layers.h"
  7. #include <Jolt/Physics/PhysicsStepListener.h>
  8. TEST_SUITE("StepListenerTest")
  9. {
  10. // Custom step listener that keeps track how often it has been called
  11. class TestStepListener : public PhysicsStepListener
  12. {
  13. public:
  14. virtual void OnStep(const PhysicsStepListenerContext &inContext) override
  15. {
  16. CHECK(inContext.mDeltaTime == mExpectedDeltaTime);
  17. CHECK(inContext.mIsFirstStep == ((mCount % mExpectedSteps) == 0));
  18. int new_count = mCount.fetch_add(1) + 1;
  19. CHECK(inContext.mIsLastStep == ((new_count % mExpectedSteps) == 0));
  20. }
  21. atomic<int> mCount = 0;
  22. int mExpectedSteps;
  23. float mExpectedDeltaTime = 0.0f;
  24. };
  25. // Perform the actual listener test with a variable amount of collision steps
  26. static void DoTest(int inCollisionSteps)
  27. {
  28. PhysicsTestContext c(1.0f / 60.0f, inCollisionSteps);
  29. // Initialize and add listeners
  30. TestStepListener listeners[10];
  31. for (TestStepListener &l : listeners)
  32. {
  33. l.mExpectedDeltaTime = 1.0f / 60.0f / inCollisionSteps;
  34. l.mExpectedSteps = inCollisionSteps;
  35. }
  36. for (TestStepListener &l : listeners)
  37. c.GetSystem()->AddStepListener(&l);
  38. // Stepping without delta time should not trigger step listeners
  39. c.SimulateNoDeltaTime();
  40. for (TestStepListener &l : listeners)
  41. CHECK(l.mCount == 0);
  42. // Stepping with delta time should call the step listeners as they can activate bodies
  43. c.SimulateSingleStep();
  44. for (TestStepListener &l : listeners)
  45. CHECK(l.mCount == inCollisionSteps);
  46. // Adding an active body should have no effect, step listeners should still be called
  47. c.CreateBox(RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sOne());
  48. // Step the simulation
  49. c.SimulateSingleStep();
  50. for (TestStepListener &l : listeners)
  51. CHECK(l.mCount == 2 * inCollisionSteps);
  52. // Unregister all listeners
  53. for (TestStepListener &l : listeners)
  54. c.GetSystem()->RemoveStepListener(&l);
  55. // Step the simulation
  56. c.SimulateSingleStep();
  57. // Check that no further callbacks were triggered
  58. for (TestStepListener &l : listeners)
  59. CHECK(l.mCount == 2 * inCollisionSteps);
  60. }
  61. // Test the step listeners with a single collision step
  62. TEST_CASE("TestStepListener1")
  63. {
  64. DoTest(1);
  65. }
  66. // Test the step listeners with two collision steps
  67. TEST_CASE("TestStepListener2")
  68. {
  69. DoTest(2);
  70. }
  71. // Test the step listeners with four collision steps
  72. TEST_CASE("TestStepListener4")
  73. {
  74. DoTest(4);
  75. }
  76. // Activate a body in a step listener
  77. TEST_CASE("TestActivateInStepListener")
  78. {
  79. PhysicsTestContext c(1.0f / 60.0f, 2);
  80. c.ZeroGravity();
  81. // Create a box
  82. Body &body = c.CreateBox(RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, EMotionQuality::Discrete, Layers::MOVING, Vec3::sOne(), EActivation::DontActivate);
  83. body.GetMotionProperties()->SetLinearDamping(0.0f);
  84. BodyID body_id = body.GetID();
  85. static const Vec3 cVelocity(10.0f, 0, 0);
  86. class MyStepListener : public PhysicsStepListener
  87. {
  88. public:
  89. MyStepListener(const BodyID &inBodyID, BodyInterface &inBodyInterface) : mBodyInterface(inBodyInterface), mBodyID(inBodyID) { }
  90. virtual void OnStep(const PhysicsStepListenerContext &inContext) override
  91. {
  92. if (inContext.mIsFirstStep)
  93. {
  94. // We activate the body and set a velocity in the first step
  95. CHECK(!mBodyInterface.IsActive(mBodyID));
  96. mBodyInterface.SetLinearVelocity(mBodyID, cVelocity);
  97. CHECK(mBodyInterface.IsActive(mBodyID));
  98. }
  99. else
  100. {
  101. // In the second step, the body should already have been activated
  102. CHECK(mBodyInterface.IsActive(mBodyID));
  103. }
  104. }
  105. private:
  106. BodyInterface & mBodyInterface;
  107. BodyID mBodyID;
  108. };
  109. MyStepListener listener(body_id, c.GetSystem()->GetBodyInterfaceNoLock());
  110. c.GetSystem()->AddStepListener(&listener);
  111. c.SimulateSingleStep();
  112. BodyInterface &bi = c.GetBodyInterface();
  113. CHECK(bi.IsActive(body_id));
  114. CHECK(bi.GetLinearVelocity(body_id) == cVelocity);
  115. CHECK(bi.GetPosition(body_id) == RVec3(c.GetDeltaTime() * cVelocity));
  116. }
  117. }