ソースを参照

CharacterVirtual should ignore collisions with sensors (#449)

Jorrit Rouwe 2 年 前
コミット
249745c1ad

+ 16 - 6
Jolt/Physics/Character/CharacterVirtual.cpp

@@ -140,12 +140,16 @@ void CharacterVirtual::ContactCollector::AddHit(const CollideShapeResult &inResu
 	BodyLockRead lock(mSystem->GetBodyLockInterface(), inResult.mBodyID2);
 	if (lock.SucceededAndIsInBroadPhase())
 	{
+		// We don't collide with sensors, note that you should set up your collision layers so that sensors don't collide with the character.
+		// Rejecting the contact here means a lot of extra work for the collision detection system.
 		const Body &body = lock.GetBody();
-
-		mContacts.emplace_back();
-		Contact &contact = mContacts.back();
-		sFillContactProperties(mCharacter, contact, body, mUp, mBaseOffset, *this, inResult);
-		contact.mFraction = 0.0f;
+		if (!body.IsSensor())
+		{
+			mContacts.emplace_back();
+			Contact &contact = mContacts.back();
+			sFillContactProperties(mCharacter, contact, body, mUp, mBaseOffset, *this, inResult);
+			contact.mFraction = 0.0f;
+		}
 	}
 }
 
@@ -170,8 +174,14 @@ void CharacterVirtual::ContactCastCollector::AddHit(const ShapeCastResult &inRes
 			if (!lock.SucceededAndIsInBroadPhase())
 				return;
 
+			// We don't collide with sensors, note that you should set up your collision layers so that sensors don't collide with the character.
+			// Rejecting the contact here means a lot of extra work for the collision detection system.
+			const Body &body = lock.GetBody();
+			if (body.IsSensor())
+				return;
+
 			// Convert the hit result into a contact
-			sFillContactProperties(mCharacter, contact, lock.GetBody(), mUp, mBaseOffset, *this, inResult);
+			sFillContactProperties(mCharacter, contact, body, mUp, mBaseOffset, *this, inResult);
 		}
 			
 		contact.mFraction = inResult.mFraction;

+ 9 - 0
Samples/Tests/Character/CharacterBaseTest.cpp

@@ -71,6 +71,7 @@ static const float cMeshWallStepEnd = 4.0f;
 static const int cMeshWallSegments = 25;
 static const RVec3 cHalfCylinderPosition(5.0f, 0, 8.0f);
 static const RVec3 cMeshBoxPosition(30.0f, 1.5f, 5.0f);
+static const RVec3 cSensorPosition(30, 0.9f, -5);
 
 void CharacterBaseTest::Initialize()
 {
@@ -447,6 +448,14 @@ void CharacterBaseTest::Initialize()
 			BodyCreationSettings box(&mesh, cMeshBoxPosition, Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING);
 			mBodyInterface->CreateAndAddBody(box, EActivation::DontActivate);
 		}
+
+		// Create a sensor. 
+		// Note that the CharacterVirtual doesn't interact with sensors, you should pair it with a Character object (see CharacterVirtual class comments)
+		{
+			BodyCreationSettings sensor(new BoxShape(Vec3::sReplicate(1.0f)), cSensorPosition, Quat::sIdentity(), EMotionType::Kinematic, Layers::SENSOR);
+			sensor.mIsSensor = true;
+			mSensorBody = mBodyInterface->CreateAndAddBody(sensor, EActivation::Activate);
+		}
 	}
 	else
 	{

+ 3 - 0
Samples/Tests/Character/CharacterBaseTest.h

@@ -70,6 +70,9 @@ protected:
 	// Conveyor belt body
 	BodyID					mConveyorBeltBody;
 
+	// Sensor body
+	BodyID					mSensorBody;
+
 private:
 	// Shape types
 	enum class EType

+ 15 - 0
Samples/Tests/Character/CharacterTest.cpp

@@ -102,3 +102,18 @@ void CharacterTest::HandleInput(Vec3Arg inMovementDirection, bool inJump, bool i
 		mCharacter->SetLinearVelocity(new_velocity);
 	}
 }
+
+void CharacterTest::OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
+{
+	// Draw a box around the character when it enters the sensor
+	if (inBody1.GetID() == mSensorBody)
+		mDebugRenderer->DrawBox(inBody2.GetWorldSpaceBounds(), Color::sGreen, DebugRenderer::ECastShadow::Off, DebugRenderer::EDrawMode::Wireframe);
+	else if (inBody2.GetID() == mSensorBody)
+		mDebugRenderer->DrawBox(inBody1.GetWorldSpaceBounds(), Color::sGreen, DebugRenderer::ECastShadow::Off, DebugRenderer::EDrawMode::Wireframe);
+}
+
+void CharacterTest::OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings)
+{
+	// Same behavior as contact added
+	OnContactAdded(inBody1, inBody2, inManifold, ioSettings);
+}

+ 8 - 1
Samples/Tests/Character/CharacterTest.h

@@ -7,7 +7,7 @@
 #include <Jolt/Physics/Character/Character.h>
 
 // Simple test that test the Character class. Allows the user to move around with the arrow keys and jump with the J button.
-class CharacterTest : public CharacterBaseTest
+class CharacterTest : public CharacterBaseTest, public ContactListener
 {
 public:
 	JPH_DECLARE_RTTI_VIRTUAL(CharacterTest)
@@ -28,6 +28,13 @@ public:
 	virtual void			SaveState(StateRecorder &inStream) const override;
 	virtual void			RestoreState(StateRecorder &inStream) override;
 
+	// If this test implements a contact listener, it should be returned here
+	virtual ContactListener *GetContactListener() override	{ return this; }
+
+	// See: ContactListener
+	virtual void			OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
+	virtual void			OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override;
+
 protected:
 	// Get position of the character
 	virtual RVec3			GetCharacterPosition() const override				{ return mCharacter->GetPosition(); }