From cc87d08dad735a2fae22d15711b5af9d51b02c7b Mon Sep 17 00:00:00 2001 From: maelstrom Date: Wed, 21 May 2025 21:58:15 +0200 Subject: [PATCH] feat(physics): added collision detection with Touched/TouchEnded --- core/src/objects/base/instance.h | 4 ++-- core/src/objects/part.cpp | 2 -- core/src/objects/part.h | 3 ++- core/src/objects/script.cpp | 11 ++++++--- core/src/objects/workspace.cpp | 39 ++++++++++++++++++++++++++++---- core/src/objects/workspace.h | 14 +++++++++++- 6 files changed, 60 insertions(+), 13 deletions(-) diff --git a/core/src/objects/base/instance.h b/core/src/objects/base/instance.h index 43f0c96..1e9734e 100644 --- a/core/src/objects/base/instance.h +++ b/core/src/objects/base/instance.h @@ -88,8 +88,6 @@ protected: // NOTE: This value is not necessarily present if dataModel is present // Objects under services other than workspace will NOT have this field set std::optional> workspace(); - - template inline std::shared_ptr shared() { return std::dynamic_pointer_cast(this->shared_from_this()); } public: const static InstanceType TYPE; std::string name; @@ -108,6 +106,8 @@ public: bool IsA(std::string className); template bool IsA() { return IsA(T::TYPE.className); } + template inline std::shared_ptr shared() { return std::dynamic_pointer_cast(this->shared_from_this()); } + DescendantsIterator GetDescendantsStart(); DescendantsIterator GetDescendantsEnd(); // Utility functions diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 7a961cf..2f527b3 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -60,8 +60,6 @@ void Part::onUpdated(std::string property) { // When position/rotation/size is manually edited, break all joints, they don't apply anymore if (property != "Anchored") BreakJoints(); - - OnParentUpdated->Fire(); } // Expands provided extents to fit point diff --git a/core/src/objects/part.h b/core/src/objects/part.h index 95a7d3c..94c0c83 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -92,7 +92,8 @@ public: DEF_PROP float frontParamB = 0.5; DEF_PROP float backParamB = 0.5; - DEF_SIGNAL SignalSource OnParentUpdated; + DEF_SIGNAL SignalSource Touched; + DEF_SIGNAL SignalSource TouchEnded; rp::RigidBody* rigidBody = nullptr; diff --git a/core/src/objects/script.cpp b/core/src/objects/script.cpp index 0d4410a..3ac6e67 100644 --- a/core/src/objects/script.cpp +++ b/core/src/objects/script.cpp @@ -15,9 +15,14 @@ int script_wait(lua_State*); int script_delay(lua_State*); Script::Script(): Instance(&TYPE) { - source = "workspace.Part.OnParentUpdated:Connect(function()\n\ - print(\"Yeux d'enfants\")\n\ -end)"; + source = "workspace.Part.Touched:Connect(function(otherPart)\n" + " print(\"Touched by: \", otherPart.Name)\n" + "end)\n" + "\n" + "workspace.Part.TouchEnded:Connect(function(otherPart)\n" + " print(\"Touched ended with: \", otherPart.Name)\n" + "end)\n" + "\n"; } Script::~Script() { diff --git a/core/src/objects/workspace.cpp b/core/src/objects/workspace.cpp index 1b67767..a8f9672 100644 --- a/core/src/objects/workspace.cpp +++ b/core/src/objects/workspace.cpp @@ -1,4 +1,6 @@ #include "workspace.h" +#include "datatypes/meta.h" +#include "datatypes/ref.h" #include "datatypes/vector.h" #include "objects/base/instance.h" #include "objects/jointsservice.h" @@ -6,11 +8,12 @@ #include "objects/datamodel.h" #include "physics/util.h" #include +#include #include rp::PhysicsCommon* Workspace::physicsCommon = new rp::PhysicsCommon; -Workspace::Workspace(): Service(&TYPE) { +Workspace::Workspace(): Service(&TYPE), physicsEventListener(this) { } Workspace::~Workspace() { @@ -18,6 +21,27 @@ Workspace::~Workspace() { physicsCommon->destroyPhysicsWorld(physicsWorld); } +PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {} + +void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) { + for (int i = 0; i < data.getNbContactPairs(); i++) { + auto pair = data.getContactPair(i); + auto type = pair.getEventType(); + if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue; + + auto part0 = reinterpret_cast(pair.getBody1()->getUserData())->shared(); + auto part1 = reinterpret_cast(pair.getBody2()->getUserData())->shared(); + + if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart) { + part0->Touched->Fire({ (Data::Variant)Data::InstanceRef(part1) }); + part1->Touched->Fire({ (Data::Variant)Data::InstanceRef(part0) }); + } else if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactExit) { + part0->TouchEnded->Fire({ (Data::Variant)Data::InstanceRef(part1) }); + part1->TouchEnded->Fire({ (Data::Variant)Data::InstanceRef(part0) }); + } + } +} + void Workspace::InitService() { if (initialized) return; initialized = true; @@ -31,7 +55,7 @@ void Workspace::InitService() { // physicsWorld->setSleepLinearVelocity(10); // physicsWorld->setSleepAngularVelocity(5); - // physicsWorld->setEventListener(&eventListener); + physicsWorld->setEventListener(&physicsEventListener); // Sync all parts for (auto it = this->GetDescendantsStart(); it != this->GetDescendantsEnd(); it++) { @@ -71,10 +95,17 @@ void Workspace::SyncPartPhysics(std::shared_ptr part) { rp::BoxShape* shape = physicsCommon->createBoxShape(glmToRp(part->size * glm::vec3(0.5f))); - if (part->rigidBody->getNbColliders() > 0) + // Recreate the rigidbody if the shape changes + if (part->rigidBody->getNbColliders() > 0 + && dynamic_cast(part->rigidBody->getCollider(0)->getCollisionShape())->getHalfExtents() != shape->getHalfExtents()) { + // TODO: This causes Touched to get called twice. Fix this. part->rigidBody->removeCollider(part->rigidBody->getCollider(0)); + part->rigidBody->addCollider(shape, rp::Transform()); + } + + if (part->rigidBody->getNbColliders() == 0) + part->rigidBody->addCollider(shape, rp::Transform()); - part->rigidBody->addCollider(shape, rp::Transform()); part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC); part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11); diff --git a/core/src/objects/workspace.h b/core/src/objects/workspace.h index e1fe8e5..934b326 100644 --- a/core/src/objects/workspace.h +++ b/core/src/objects/workspace.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -35,11 +36,22 @@ class RotateV; typedef std::function)> RaycastFilter; +class Workspace; +class PhysicsEventListener : public rp::EventListener { + friend Workspace; + Workspace* workspace; + + PhysicsEventListener(Workspace*); + + void onContact(const rp::CollisionCallback::CallbackData&) override; +}; + class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service { AUTOGEN_PREAMBLE rp::PhysicsWorld* physicsWorld = nullptr; - static rp::PhysicsCommon* physicsCommon; + static rp::PhysicsCommon* physicsCommon; + PhysicsEventListener physicsEventListener; friend Part; friend Snap;