ContactListenerTest.cpp 4.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #include <TestFramework.h>
  4. #include <Tests/General/ContactListenerTest.h>
  5. #include <Jolt/Physics/Collision/Shape/BoxShape.h>
  6. #include <Jolt/Physics/Collision/Shape/CapsuleShape.h>
  7. #include <Jolt/Physics/Collision/Shape/SphereShape.h>
  8. #include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
  9. #include <Jolt/Physics/Collision/EstimateCollisionResponse.h>
  10. #include <Jolt/Physics/Body/BodyCreationSettings.h>
  11. #include <Layers.h>
  12. #include <Renderer/DebugRendererImp.h>
  13. JPH_IMPLEMENT_RTTI_VIRTUAL(ContactListenerTest)
  14. {
  15. JPH_ADD_BASE_CLASS(ContactListenerTest, Test)
  16. }
  17. void ContactListenerTest::Initialize()
  18. {
  19. // Floor
  20. CreateFloor();
  21. RefConst<Shape> box_shape = new BoxShape(Vec3(0.5f, 1.0f, 2.0f));
  22. // Dynamic body 1
  23. Body &body1 = *mBodyInterface->CreateBody(BodyCreationSettings(box_shape, RVec3(0, 10, 0), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING));
  24. body1.SetAllowSleeping(false);
  25. mBodyInterface->AddBody(body1.GetID(), EActivation::Activate);
  26. // Dynamic body 2
  27. Body &body2 = *mBodyInterface->CreateBody(BodyCreationSettings(box_shape, RVec3(5, 10, 0), Quat::sRotation(Vec3::sAxisX(), 0.25f * JPH_PI), EMotionType::Dynamic, Layers::MOVING));
  28. body2.SetAllowSleeping(false);
  29. mBodyInterface->AddBody(body2.GetID(), EActivation::Activate);
  30. // Dynamic body 3
  31. Body &body3 = *mBodyInterface->CreateBody(BodyCreationSettings(new SphereShape(2.0f), RVec3(10, 10, 0), Quat::sRotation(Vec3::sAxisX(), 0.25f * JPH_PI), EMotionType::Dynamic, Layers::MOVING));
  32. body3.SetAllowSleeping(false);
  33. mBodyInterface->AddBody(body3.GetID(), EActivation::Activate);
  34. // Dynamic body 4
  35. Ref<StaticCompoundShapeSettings> compound_shape = new StaticCompoundShapeSettings;
  36. compound_shape->AddShape(Vec3::sZero(), Quat::sIdentity(), new CapsuleShape(5, 1));
  37. compound_shape->AddShape(Vec3(0, -5, 0), Quat::sIdentity(), new SphereShape(2));
  38. compound_shape->AddShape(Vec3(0, 5, 0), Quat::sIdentity(), new SphereShape(2));
  39. Body &body4 = *mBodyInterface->CreateBody(BodyCreationSettings(compound_shape, RVec3(15, 10, 0), Quat::sRotation(Vec3::sAxisX(), 0.25f * JPH_PI), EMotionType::Dynamic, Layers::MOVING));
  40. body4.SetAllowSleeping(false);
  41. mBodyInterface->AddBody(body4.GetID(), EActivation::Activate);
  42. // Store bodies for later use
  43. mBody[0] = &body1;
  44. mBody[1] = &body2;
  45. mBody[2] = &body3;
  46. mBody[3] = &body4;
  47. }
  48. void ContactListenerTest::PostPhysicsUpdate(float inDeltaTime)
  49. {
  50. for (Body *body : mBody)
  51. Trace("State, body: %08x, v=%s, w=%s", body->GetID().GetIndex(), ConvertToString(body->GetLinearVelocity()).c_str(), ConvertToString(body->GetAngularVelocity()).c_str());
  52. }
  53. ValidateResult ContactListenerTest::OnContactValidate(const Body &inBody1, const Body &inBody2, RVec3Arg inBaseOffset, const CollideShapeResult &inCollisionResult)
  54. {
  55. // Body 1 and 2 should never collide
  56. return ((&inBody1 == mBody[0] && &inBody2 == mBody[1]) || (&inBody1 == mBody[1] && &inBody2 == mBody[0]))? ValidateResult::RejectAllContactsForThisBodyPair : ValidateResult::AcceptAllContactsForThisBodyPair;
  57. }
  58. void ContactListenerTest::OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
  59. {
  60. // Make body 1 bounce only when a new contact point is added but not when it is persisted (its restitution is normally 0)
  61. if (&inBody1 == mBody[0] || &inBody2 == mBody[0])
  62. {
  63. JPH_ASSERT(ioSettings.mCombinedRestitution == 0.0f);
  64. ioSettings.mCombinedRestitution = 1.0f;
  65. }
  66. // Estimate the contact impulses. Note that these won't be 100% accurate unless you set the friction of the bodies to 0 (EstimateCollisionResponse ignores friction)
  67. ContactImpulses impulses;
  68. Vec3 v1, w1, v2, w2;
  69. EstimateCollisionResponse(inBody1, inBody2, inManifold, v1, w1, v2, w2, impulses, ioSettings.mCombinedRestitution);
  70. // Trace the result
  71. String impulses_str;
  72. for (float impulse : impulses)
  73. impulses_str += StringFormat("%f ", (double)impulse);
  74. Trace("Estimated velocity after collision, body1: %08x, v=%s, w=%s, body2: %08x, v=%s, w=%s, impulses: %s",
  75. inBody1.GetID().GetIndex(), ConvertToString(v1).c_str(), ConvertToString(w1).c_str(),
  76. inBody2.GetID().GetIndex(), ConvertToString(v2).c_str(), ConvertToString(w2).c_str(),
  77. impulses_str.c_str());
  78. }