diff --git a/core/src/objects/joint/rotatev.cpp b/core/src/objects/joint/rotatev.cpp new file mode 100644 index 0000000..20776e4 --- /dev/null +++ b/core/src/objects/joint/rotatev.cpp @@ -0,0 +1,54 @@ +#include "rotatev.h" +#include "objects/jointsservice.h" +#include "objects/part.h" +#include "objects/workspace.h" +#include "rendering/renderer.h" +#include + +#define PI 3.14159 + +RotateV::RotateV(): JointInstance(&TYPE) { +} + +RotateV::~RotateV() { +} +static CFrame XYZToZXY(glm::vec3(0, 0, 0), -glm::vec3(1, 0, 0), glm::vec3(0, 0, 1)); + +void RotateV::buildJoint() { + // Only if both parts are set, are not the same part, are part of a workspace, and are part of the same workspace, we build the joint + if (part0.expired() || part1.expired() || part0.lock() == part1.lock() || !workspaceOfPart(part0.lock()) || workspaceOfPart(part0.lock()) != workspaceOfPart(part1.lock())) return; + + // Don't build the joint if we're not part of either a workspace or JointsService + if ((!GetParent() || GetParent().value()->GetClass() != &JointsService::TYPE) && !workspace()) return; + + std::shared_ptr workspace = workspaceOfPart(part0.lock()).value(); + if (!workspace->physicsWorld) return; + + + // Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it + // used to be rather than specifying an anchor rotation, so whatever. + CFrame newFrame = part0.lock()->cframe * (c0 * c1.Inverse()); + part1.lock()->cframe = newFrame; + workspace->SyncPartPhysics(part1.lock()); + // Do NOT use Abs() in this scenario. For some reason that breaks it + rp::HingeJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (part0.lock()->cframe * c0).Position(), -(part0.lock()->cframe * c0).LookVector().Unit()); + + jointInfo.isCollisionEnabled = false; + + this->joint = dynamic_cast(workspace->physicsWorld->createJoint(jointInfo)); + jointWorkspace = workspace; + + + // part1.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b10); + // part1.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b10); + // part0.lock()->rigidBody->getCollider(0)->setCollideWithMaskBits(0b01); + // part0.lock()->rigidBody->getCollider(0)->setCollisionCategoryBits(0b01); +} + +void RotateV::breakJoint() { + // If the joint doesn't exist, or its workspace expired (not our problem anymore), then no need to do anything + if (!this->joint || jointWorkspace.expired() || !jointWorkspace.lock()->physicsWorld) return; + + jointWorkspace.lock()->physicsWorld->destroyJoint(this->joint); + this->joint = nullptr; +} \ No newline at end of file diff --git a/core/src/objects/joint/rotatev.h b/core/src/objects/joint/rotatev.h new file mode 100644 index 0000000..5e32c6b --- /dev/null +++ b/core/src/objects/joint/rotatev.h @@ -0,0 +1,21 @@ +#pragma once + +#include "objects/annotation.h" +#include "objects/base/instance.h" +#include "objects/joint/jointinstance.h" +#include + +class DEF_INST RotateV : public JointInstance { + AUTOGEN_PREAMBLE + + rp::HingeJoint* joint = nullptr; + + virtual void buildJoint() override; + virtual void breakJoint() override; +public: + RotateV(); + ~RotateV(); + + static inline std::shared_ptr New() { return std::make_shared(); }; + static inline std::shared_ptr Create() { return std::make_shared(); }; +}; \ No newline at end of file diff --git a/core/src/objects/meta.cpp b/core/src/objects/meta.cpp index 8b3a473..dc1b0bd 100644 --- a/core/src/objects/meta.cpp +++ b/core/src/objects/meta.cpp @@ -1,5 +1,8 @@ #include "meta.h" #include "objects/joint/jointinstance.h" +#include "objects/joint/rotate.h" +#include "objects/joint/rotatev.h" +#include "objects/joint/weld.h" #include "objects/jointsservice.h" #include "objects/part.h" #include "objects/joint/snap.h" @@ -14,6 +17,9 @@ std::map INSTANCE_MAP = { { "Part", &Part::TYPE }, { "Snap", &Snap::TYPE }, + { "Weld", &Weld::TYPE }, + { "Rotate", &Rotate::TYPE }, + { "RotateV", &RotateV::TYPE }, { "JointInstance", &JointInstance::TYPE }, { "Script", &Script::TYPE }, diff --git a/core/src/objects/part.cpp b/core/src/objects/part.cpp index 21538d6..80e380e 100644 --- a/core/src/objects/part.cpp +++ b/core/src/objects/part.cpp @@ -7,6 +7,7 @@ #include "datatypes/vector.h" #include "objects/base/member.h" #include "objects/joint/rotate.h" +#include "objects/joint/rotatev.h" #include "objects/joint/weld.h" #include "objects/jointsservice.h" #include "objects/joint/jointinstance.h" @@ -214,6 +215,8 @@ std::optional> makeJointFromSurfaces(SurfaceType return Snap::New(); if (a == SurfaceHinge) return Rotate::New(); + if (a == SurfaceMotor) + return RotateV::New(); return std::nullopt; } @@ -257,7 +260,7 @@ void Part::MakeJoints() { SurfaceType otherSurface = surfaceFromFace(faceFromNormal(otherFace)); // If it is a hinge, only attach if actually touching the "hinge" - if (mySurface == SurfaceHinge && !checkSurfacesTouching(surfaceFrame, Vector3(0.4, 0.4, 0.4), myFace, otherFace, otherPart)) continue; + if ((mySurface == SurfaceHinge || mySurface == SurfaceMotor) && !checkSurfacesTouching(surfaceFrame, Vector3(0.4, 0.4, 0.4), myFace, otherFace, otherPart)) continue; // Create contacts // Contact always occurs at the center of Part0's surface (even if that point does not overlap both surfaces) diff --git a/core/src/objects/part.h b/core/src/objects/part.h index e3ebbce..476f68d 100644 --- a/core/src/objects/part.h +++ b/core/src/objects/part.h @@ -26,7 +26,7 @@ struct PartConstructParams { bool locked = false; }; -class Snap; +class Workspace; class DEF_INST_(explorer_icon="part") Part : public Instance { AUTOGEN_PREAMBLE @@ -46,6 +46,7 @@ protected: bool checkSurfacesTouching(CFrame surfaceFrame, Vector3 size, Vector3 myFace, Vector3 otherFace, std::shared_ptr otherPart); friend JointInstance; + friend Workspace; void OnAncestryChanged(std::optional> child, std::optional> newParent) override; void onUpdated(std::string); diff --git a/core/src/objects/workspace.cpp b/core/src/objects/workspace.cpp index 7c8b47d..1e9727c 100644 --- a/core/src/objects/workspace.cpp +++ b/core/src/objects/workspace.cpp @@ -3,6 +3,7 @@ #include "objects/jointsservice.h" #include "objects/joint/jointinstance.h" #include "physics/util.h" +#include #include rp::PhysicsCommon* Workspace::physicsCommon = new rp::PhysicsCommon; @@ -102,6 +103,15 @@ void Workspace::PhysicsStep(float deltaTime) { const rp::Transform& transform = part->rigidBody->getTransform(); part->cframe = CFrame(transform); part->velocity = part->rigidBody->getLinearVelocity(); + + part->rigidBody->enableGravity(true); + for (auto& joint : part->secondaryJoints) { + if (joint.expired() || !joint.lock()->IsA("RotateV")) continue; + + std::shared_ptr motor = joint.lock()->CastTo().expect(); + part->rigidBody->enableGravity(false); + part->rigidBody->setAngularVelocity((motor->part0.lock()->cframe * motor->c0).LookVector() * 10.f); + } } } diff --git a/core/src/objects/workspace.h b/core/src/objects/workspace.h index 5d424b4..1853cb0 100644 --- a/core/src/objects/workspace.h +++ b/core/src/objects/workspace.h @@ -28,6 +28,7 @@ class Part; class Snap; class Weld; class Rotate; +class RotateV; typedef std::function)> RaycastFilter; @@ -41,6 +42,7 @@ class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service { friend Snap; friend Weld; friend Rotate; + friend RotateV; protected: void InitService() override; bool initialized = false; diff --git a/core/src/rendering/surface.h b/core/src/rendering/surface.h index 1ee6d9e..e2e45fa 100644 --- a/core/src/rendering/surface.h +++ b/core/src/rendering/surface.h @@ -17,6 +17,7 @@ enum SurfaceType { SurfaceInlets = 4, SurfaceUniversal = 5, SurfaceHinge = 6, + SurfaceMotor = 7, }; namespace Data { class Vector3; } using Data::Vector3; diff --git a/editor/placedocument.cpp b/editor/placedocument.cpp index c075d69..a65d673 100644 --- a/editor/placedocument.cpp +++ b/editor/placedocument.cpp @@ -122,6 +122,7 @@ void PlaceDocument::init() { // part0->backSurface = SurfaceWeld; // part1->frontSurface = SurfaceWeld; - part0->backSurface = SurfaceHinge; + // part0->backSurface = SurfaceHinge; + part0->backSurface = SurfaceMotor; // part1->frontSurface = SurfaceHinge; } \ No newline at end of file