|
@@ -6,6 +6,8 @@
|
|
|
#include "PhysicsTestContext.h"
|
|
|
#include "Layers.h"
|
|
|
#include "LoggingContactListener.h"
|
|
|
+#include <Jolt/Physics/Collision/Shape/StaticCompoundShape.h>
|
|
|
+#include <Jolt/Physics/Collision/Shape/SphereShape.h>
|
|
|
|
|
|
TEST_SUITE("ContactListenerTests")
|
|
|
{
|
|
@@ -262,4 +264,104 @@ TEST_SUITE("ContactListenerTests")
|
|
|
CHECK(remove.mBody2 == body.GetID()); // Highest ID second
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ TEST_CASE("TestWereBodiesInContact")
|
|
|
+ {
|
|
|
+ for (int sign = -1; sign <= 1; sign += 2)
|
|
|
+ {
|
|
|
+ PhysicsTestContext c(1.0f / 60.0f, 1, 1);
|
|
|
+
|
|
|
+ PhysicsSystem *s = c.GetSystem();
|
|
|
+ BodyInterface &bi = c.GetBodyInterface();
|
|
|
+
|
|
|
+ Body &floor = c.CreateFloor();
|
|
|
+
|
|
|
+ // Two spheres at a distance so that when one sphere leaves the floor the body can still be touching the floor with the other sphere
|
|
|
+ Ref<StaticCompoundShapeSettings> compound_shape = new StaticCompoundShapeSettings;
|
|
|
+ compound_shape->AddShape(Vec3(-2, 0, 0), Quat::sIdentity(), new SphereShape(1));
|
|
|
+ compound_shape->AddShape(Vec3(2, 0, 0), Quat::sIdentity(), new SphereShape(1));
|
|
|
+ Body &body = *bi.CreateBody(BodyCreationSettings(compound_shape, RVec3(0, 0.999f, 0), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING));
|
|
|
+ bi.AddBody(body.GetID(), EActivation::Activate);
|
|
|
+
|
|
|
+ class ContactListenerImpl : public ContactListener
|
|
|
+ {
|
|
|
+ public:
|
|
|
+ ContactListenerImpl(PhysicsSystem *inSystem) : mSystem(inSystem) { }
|
|
|
+
|
|
|
+ virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
|
|
|
+ {
|
|
|
+ ++mAdded;
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override
|
|
|
+ {
|
|
|
+ ++mRemoved;
|
|
|
+ mWasInContact = mSystem->WereBodiesInContact(inSubShapePair.GetBody1ID(), inSubShapePair.GetBody2ID());
|
|
|
+ CHECK(mWasInContact == mSystem->WereBodiesInContact(inSubShapePair.GetBody2ID(), inSubShapePair.GetBody1ID())); // Returned value should be the same regardless of order
|
|
|
+ }
|
|
|
+
|
|
|
+ int GetAddCount() const
|
|
|
+ {
|
|
|
+ return mAdded - mRemoved;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Reset()
|
|
|
+ {
|
|
|
+ mAdded = 0;
|
|
|
+ mRemoved = 0;
|
|
|
+ mWasInContact = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ PhysicsSystem * mSystem;
|
|
|
+
|
|
|
+ int mAdded = 0;
|
|
|
+
|
|
|
+ int mRemoved = 0;
|
|
|
+ bool mWasInContact = false;
|
|
|
+ };
|
|
|
+
|
|
|
+ // Set listener
|
|
|
+ ContactListenerImpl listener(s);
|
|
|
+ s->SetContactListener(&listener);
|
|
|
+
|
|
|
+ // If the simulation hasn't run yet, we can't be in contact
|
|
|
+ CHECK(!s->WereBodiesInContact(floor.GetID(), body.GetID()));
|
|
|
+
|
|
|
+ // Step the simulation to allow detecting the contact
|
|
|
+ c.SimulateSingleStep();
|
|
|
+
|
|
|
+ // Should be in contact now
|
|
|
+ CHECK(s->WereBodiesInContact(floor.GetID(), body.GetID()));
|
|
|
+ CHECK(s->WereBodiesInContact(body.GetID(), floor.GetID()));
|
|
|
+ CHECK(listener.GetAddCount() == 1);
|
|
|
+ listener.Reset();
|
|
|
+
|
|
|
+ // Impulse on one side
|
|
|
+ bi.AddImpulse(body.GetID(), Vec3(0, 10000, 0), RVec3(Real(-sign * 2), 0, 0));
|
|
|
+ c.SimulateSingleStep(); // One step to detach from the ground (but starts penetrating so will not send a remove callback)
|
|
|
+ CHECK(listener.GetAddCount() == 0);
|
|
|
+ c.SimulateSingleStep(); // One step to get contact remove callback
|
|
|
+
|
|
|
+ // Should still be in contact
|
|
|
+ // Note that we may get a remove and an add callback because manifold reduction has combined the collision with both spheres into 1 contact manifold.
|
|
|
+ // At that point it has to select one of the sub shapes for the contact and if that sub shape no longer collides we get a remove for this sub shape and then an add callback for the other sub shape.
|
|
|
+ CHECK(s->WereBodiesInContact(floor.GetID(), body.GetID()));
|
|
|
+ CHECK(s->WereBodiesInContact(body.GetID(), floor.GetID()));
|
|
|
+ CHECK(listener.GetAddCount() == 0);
|
|
|
+ CHECK((listener.mRemoved == 0 || listener.mWasInContact));
|
|
|
+ listener.Reset();
|
|
|
+
|
|
|
+ // Impulse on the other side
|
|
|
+ bi.AddImpulse(body.GetID(), Vec3(0, 10000, 0), RVec3(Real(sign * 2), 0, 0));
|
|
|
+ c.SimulateSingleStep(); // One step to detach from the ground (but starts penetrating so will not send a remove callback)
|
|
|
+ CHECK(listener.GetAddCount() == 0);
|
|
|
+ c.SimulateSingleStep(); // One step to get contact remove callback
|
|
|
+
|
|
|
+ // Should no longer be in contact
|
|
|
+ CHECK(!s->WereBodiesInContact(floor.GetID(), body.GetID()));
|
|
|
+ CHECK(!s->WereBodiesInContact(body.GetID(), floor.GetID()));
|
|
|
+ CHECK(listener.GetAddCount() == -1);
|
|
|
+ CHECK((listener.mRemoved == 1 && !listener.mWasInContact));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|