From 577ad312b89e31902b82bd9456e9cecb0a56785e Mon Sep 17 00:00:00 2001 From: maelstrom Date: Tue, 19 Aug 2025 21:22:19 +0200 Subject: [PATCH] refactor(physics): refactored part code into PhysRigidBody --- core/src/objects/part/basepart.cpp | 5 +- core/src/objects/part/basepart.h | 13 +---- core/src/objects/part/part.cpp | 30 +----------- core/src/objects/part/part.h | 4 -- core/src/objects/part/wedgepart.cpp | 26 +++++----- core/src/objects/part/wedgepart.h | 1 - core/src/partassembly.cpp | 2 +- core/src/physics/world.cpp | 75 +++++++++++++++++++---------- core/src/physics/world.h | 17 +++++++ 9 files changed, 86 insertions(+), 87 deletions(-) diff --git a/core/src/objects/part/basepart.cpp b/core/src/objects/part/basepart.cpp index c14e5a7..84ef405 100644 --- a/core/src/objects/part/basepart.cpp +++ b/core/src/objects/part/basepart.cpp @@ -27,15 +27,14 @@ BasePart::BasePart(const InstanceType* type, PartConstructParams params): PVInst BasePart::~BasePart() { // This relies on physicsCommon still existing. Be very careful. - if (this->rigidBody && workspace() != nullptr) { + if (workspace() != nullptr) { workspace()->RemoveBody(shared()); } } void BasePart::OnAncestryChanged(nullable std::shared_ptr child, nullable std::shared_ptr newParent) { - if (this->rigidBody) - this->rigidBody->setIsActive(workspace() != nullptr); + this->rigidBody.setActive(workspace() != nullptr); if (workspace() != nullptr) workspace()->SyncPartPhysics(std::dynamic_pointer_cast(this->shared_from_this())); diff --git a/core/src/objects/part/basepart.h b/core/src/objects/part/basepart.h index ce837bd..5da89d0 100644 --- a/core/src/objects/part/basepart.h +++ b/core/src/objects/part/basepart.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include @@ -10,16 +9,10 @@ #include "datatypes/vector.h" #include "objects/base/instance.h" #include "enum/surface.h" -#include -#include -#include -#include -#include #include #include "objects/annotation.h" #include "objects/pvinstance.h" - -namespace rp = reactphysics3d; +#include "physics/world.h" // For easy construction from C++. Maybe should be removed? struct PartConstructParams { @@ -59,8 +52,6 @@ protected: void OnAncestryChanged(nullable std::shared_ptr child, nullable std::shared_ptr newParent) override; void onUpdated(std::string); - virtual void updateCollider(rp::PhysicsCommon* common) = 0; - BasePart(const InstanceType*); BasePart(const InstanceType*, PartConstructParams params); public: @@ -110,7 +101,7 @@ public: DEF_SIGNAL SignalSource Touched; DEF_SIGNAL SignalSource TouchEnded; - rp::RigidBody* rigidBody = nullptr; + PhysRigidBody rigidBody; inline SurfaceType GetSurfaceFromFace(NormalId face) { return surfaceFromFace(face); } float GetSurfaceParamA(Vector3 face); diff --git a/core/src/objects/part/part.cpp b/core/src/objects/part/part.cpp index 795dbb1..e95059f 100644 --- a/core/src/objects/part/part.cpp +++ b/core/src/objects/part/part.cpp @@ -4,39 +4,11 @@ #include Part::Part(): BasePart(&TYPE) { - _lastShape = shape; - _lastSize = size; } -Part::Part(PartConstructParams params): BasePart(&TYPE, params) { - _lastShape = shape; - _lastSize = size; -} - -void Part::updateCollider(rp::PhysicsCommon* common) { - rp::CollisionShape* physShape; - if (shape == PartType::Ball) { - physShape = common->createSphereShape(glm::min(size.X(), size.Y(), size.Z()) * 0.5f); - } else if (shape == PartType::Block) { - physShape = common->createBoxShape(glmToRp(size * glm::vec3(0.5f))); - } - - // Recreate the rigidbody if the shape changes - if (rigidBody->getNbColliders() > 0 && (_lastShape != shape || _lastSize != size)) { - // TODO: This causes Touched to get called twice. Fix this. - rigidBody->removeCollider(rigidBody->getCollider(0)); - rigidBody->addCollider(physShape, rp::Transform()); - } - - if (rigidBody->getNbColliders() == 0) - rigidBody->addCollider(physShape, rp::Transform()); - - - _lastShape = shape; - _lastSize = size; +Part::Part(PartConstructParams params): BasePart(&TYPE, params) { } Vector3 Part::GetEffectiveSize() { return shape == PartType::Ball ? (Vector3)glm::vec3(glm::min(size.X(), size.Y(), size.Z())) : size; - } \ No newline at end of file diff --git a/core/src/objects/part/part.h b/core/src/objects/part/part.h index b267969..5da81b9 100644 --- a/core/src/objects/part/part.h +++ b/core/src/objects/part/part.h @@ -6,11 +6,7 @@ class DEF_INST Part : public BasePart { AUTOGEN_PREAMBLE - - PartType _lastShape; - Vector3 _lastSize; protected: - void updateCollider(rp::PhysicsCommon* common) override; public: Part(); diff --git a/core/src/objects/part/wedgepart.cpp b/core/src/objects/part/wedgepart.cpp index 7d877af..a9cf38a 100644 --- a/core/src/objects/part/wedgepart.cpp +++ b/core/src/objects/part/wedgepart.cpp @@ -12,21 +12,21 @@ WedgePart::WedgePart(PartConstructParams params): BasePart(&TYPE, params) { } -void WedgePart::updateCollider(rp::PhysicsCommon* common) { - Logger::fatalError("Wedges are currently disabled! Please do not use them or your editor may crash\n"); - rp::ConvexMeshShape* shape = common->createConvexMeshShape(wedgePhysMesh, glmToRp(size * glm::vec3(0.5f))); +// void WedgePart::updateCollider(rp::PhysicsCommon* common) { +// Logger::fatalError("Wedges are currently disabled! Please do not use them or your editor may crash\n"); +// rp::ConvexMeshShape* shape = common->createConvexMeshShape(wedgePhysMesh, glmToRp(size * glm::vec3(0.5f))); - // Recreate the rigidbody if the shape changes - if (rigidBody->getNbColliders() > 0 - && dynamic_cast(rigidBody->getCollider(0)->getCollisionShape())->getScale() != shape->getScale()) { - // TODO: This causes Touched to get called twice. Fix this. - rigidBody->removeCollider(rigidBody->getCollider(0)); - rigidBody->addCollider(shape, rp::Transform()); - } +// // Recreate the rigidbody if the shape changes +// if (rigidBody->getNbColliders() > 0 +// && dynamic_cast(rigidBody->getCollider(0)->getCollisionShape())->getScale() != shape->getScale()) { +// // TODO: This causes Touched to get called twice. Fix this. +// rigidBody->removeCollider(rigidBody->getCollider(0)); +// rigidBody->addCollider(shape, rp::Transform()); +// } - if (rigidBody->getNbColliders() == 0) - rigidBody->addCollider(shape, rp::Transform()); -} +// if (rigidBody->getNbColliders() == 0) +// rigidBody->addCollider(shape, rp::Transform()); +// } void WedgePart::createWedgeShape(rp::PhysicsCommon* common) { // https://www.reactphysics3d.com/documentation/index.html#creatingbody diff --git a/core/src/objects/part/wedgepart.h b/core/src/objects/part/wedgepart.h index b96f3be..8285774 100644 --- a/core/src/objects/part/wedgepart.h +++ b/core/src/objects/part/wedgepart.h @@ -7,7 +7,6 @@ class DEF_INST_(hidden) WedgePart : public BasePart { AUTOGEN_PREAMBLE protected: - void updateCollider(rp::PhysicsCommon* common) override; static void createWedgeShape(rp::PhysicsCommon* common); friend Workspace; diff --git a/core/src/partassembly.cpp b/core/src/partassembly.cpp index 3d44375..6292eaa 100644 --- a/core/src/partassembly.cpp +++ b/core/src/partassembly.cpp @@ -61,7 +61,7 @@ PartAssembly PartAssembly::FromSelection(std::shared_ptr selection) { void PartAssembly::SetCollisionsEnabled(bool enabled) { for (auto part : parts) { - part->rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled); + part->rigidBody.setCollisionsEnabled(enabled); } } diff --git a/core/src/physics/world.cpp b/core/src/physics/world.cpp index 6cd3301..ebe917c 100644 --- a/core/src/physics/world.cpp +++ b/core/src/physics/world.cpp @@ -5,7 +5,7 @@ #include "objects/part/basepart.h" #include "physics/util.h" #include -#include "reactphysics3d/constraint/HingeJoint.h" +#include #include "timeutil.h" #include #include "objects/service/workspace.h" @@ -78,12 +78,12 @@ void PhysWorld::step(float deltaTime) { // TODO: Add list of tracked parts in workspace based on their ancestry using inWorkspace property of Instance for (std::shared_ptr part : simulatedBodies) { - if (!part->rigidBody) continue; + if (!part->rigidBody.rigidBody) continue; // Sync properties - const rp::Transform& transform = part->rigidBody->getTransform(); + const rp::Transform& transform = part->rigidBody.rigidBody->getTransform(); part->cframe = CFrame(transform); - part->velocity = part->rigidBody->getLinearVelocity(); + part->velocity = part->rigidBody.rigidBody->getLinearVelocity(); // part->rigidBody->enableGravity(true); // RotateV/Motor joint @@ -93,7 +93,7 @@ void PhysWorld::step(float deltaTime) { std::shared_ptr motor = joint.lock()->CastTo().expect(); float rate = motor->part0.lock()->GetSurfaceParamB(-motor->c0.LookVector().Unit()) * 30; // part->rigidBody->enableGravity(false); - part->rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate); + part->rigidBody.rigidBody->setAngularVelocity(-(motor->part0.lock()->cframe * motor->c0).LookVector() * rate); } } @@ -111,32 +111,32 @@ void PhysWorld::removeBody(std::shared_ptr part) { void PhysWorld::syncBodyProperties(std::shared_ptr part) { rp::Transform transform = part->cframe; - if (!part->rigidBody) { - part->rigidBody = worldImpl->createRigidBody(transform); + if (!part->rigidBody.rigidBody) { + part->rigidBody.rigidBody = worldImpl->createRigidBody(transform); } else { - part->rigidBody->setTransform(transform); + part->rigidBody.rigidBody->setTransform(transform); } - part->updateCollider(&physicsCommon); + part->rigidBody.updateCollider(part); - part->rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC); - part->rigidBody->getCollider(0)->setCollisionCategoryBits(0b11); + part->rigidBody.rigidBody->setType(part->anchored ? rp::BodyType::STATIC : rp::BodyType::DYNAMIC); + part->rigidBody.rigidBody->getCollider(0)->setCollisionCategoryBits(0b11); - part->rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide); - part->rigidBody->getCollider(0)->setIsTrigger(!part->canCollide); + part->rigidBody.rigidBody->getCollider(0)->setIsSimulationCollider(part->canCollide); + part->rigidBody.rigidBody->getCollider(0)->setIsTrigger(!part->canCollide); - rp::Material& material = part->rigidBody->getCollider(0)->getMaterial(); + rp::Material& material = part->rigidBody.rigidBody->getCollider(0)->getMaterial(); material.setFrictionCoefficient(0.35); material.setMassDensity(1.f); //https://github.com/DanielChappuis/reactphysics3d/issues/170#issuecomment-691514860 - part->rigidBody->updateMassFromColliders(); - part->rigidBody->updateLocalInertiaTensorFromColliders(); + part->rigidBody.rigidBody->updateMassFromColliders(); + part->rigidBody.rigidBody->updateLocalInertiaTensorFromColliders(); - part->rigidBody->setLinearVelocity(part->velocity); + part->rigidBody.rigidBody->setLinearVelocity(part->velocity); // part->rigidBody->setMass(density * part->size.x * part->size.y * part->size.z); - part->rigidBody->setUserData(&*part); + part->rigidBody.rigidBody->setUserData(&*part); } // Ray-casting @@ -199,8 +199,8 @@ std::optional PhysWorld::castRay(Vector3 point, Vector3 rot PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr part0, std::shared_ptr part1) { // error checking - if (part0->rigidBody == nullptr - || part1->rigidBody == nullptr + if (part0->rigidBody.rigidBody == nullptr + || part1->rigidBody.rigidBody == nullptr || !part0->workspace() || !part1->workspace() || part0->workspace()->physicsWorld != shared_from_this() @@ -208,15 +208,15 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr ) { Logger::fatalError("Failed to create joint between two parts due to the call being invalid"); panic(); }; if (PhysJointGlueInfo* info = dynamic_cast(&type)) { - return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint)); } else if (PhysJointWeldInfo* info = dynamic_cast(&type)) { - return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint)); } else if (PhysJointSnapInfo* info = dynamic_cast(&type)) { - return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint)); + return worldImpl->createJoint(rp::FixedJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint)); } else if (PhysJointHingeInfo* info = dynamic_cast(&type)) { - return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis)); + return worldImpl->createJoint(rp::HingeJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint, info->rotationAxis)); } else if (PhysJointMotorInfo* info = dynamic_cast(&type)) { - auto implInfo = rp::HingeJointInfo(part0->rigidBody, part1->rigidBody, info->anchorPoint, info->rotationAxis); + auto implInfo = rp::HingeJointInfo(part0->rigidBody.rigidBody, part1->rigidBody.rigidBody, info->anchorPoint, info->rotationAxis); implInfo.isCollisionEnabled = false; return worldImpl->createJoint(implInfo); @@ -230,5 +230,30 @@ PhysJoint PhysWorld::createJoint(PhysJointInfo& type, std::shared_ptr } void PhysWorld::destroyJoint(PhysJoint joint) { + worldImpl->destroyJoint(joint.joint); +} +void PhysRigidBody::updateCollider(std::shared_ptr bPart) { + if (std::shared_ptr part = std::dynamic_pointer_cast(bPart)) { + rp::CollisionShape* physShape; + if (part->shape == PartType::Ball) { + physShape = physicsCommon.createSphereShape(glm::min(part->size.X(), part->size.Y(), part->size.Z()) * 0.5f); + } else if (part->shape == PartType::Block) { + physShape = physicsCommon.createBoxShape(glmToRp(part->size * glm::vec3(0.5f))); + } + + // Recreate the rigidbody if the shape changes + if (rigidBody->getNbColliders() > 0 && (_lastShape != part->shape || _lastSize != part->size)) { + // TODO: This causes Touched to get called twice. Fix this. + rigidBody->removeCollider(rigidBody->getCollider(0)); + rigidBody->addCollider(physShape, rp::Transform()); + } + + if (rigidBody->getNbColliders() == 0) + rigidBody->addCollider(physShape, rp::Transform()); + + + _lastShape = part->shape; + _lastSize = part->size; + } } \ No newline at end of file diff --git a/core/src/physics/world.h b/core/src/physics/world.h index 588fbfb..3ed1c51 100644 --- a/core/src/physics/world.h +++ b/core/src/physics/world.h @@ -1,6 +1,8 @@ #pragma once #include "datatypes/vector.h" +#include "enum/part.h" +#include "reactphysics3d/body/RigidBody.h" #include #include #include @@ -55,6 +57,21 @@ public: inline PhysJoint() {} }; +class PhysRigidBody { + rp::RigidBody* rigidBody = nullptr; + inline PhysRigidBody(rp::RigidBody* rigidBody) : rigidBody(rigidBody) {} + Vector3 _lastSize; + PartType _lastShape; + + friend PhysWorld; +public: + inline PhysRigidBody() {} + + inline void setActive(bool active) { if (!rigidBody) return; rigidBody->setIsActive(active); } + inline void setCollisionsEnabled(bool enabled) { if (!rigidBody) return; rigidBody->getCollider(0)->setIsWorldQueryCollider(enabled); } + void updateCollider(std::shared_ptr); +}; + class PhysWorld : public std::enable_shared_from_this { rp::PhysicsWorld* worldImpl; PhysicsEventListener physicsEventListener;