feat(joint): added motor

This commit is contained in:
maelstrom 2025-05-01 16:45:12 +02:00
parent e5f543ef4a
commit 47d720f438
9 changed files with 102 additions and 3 deletions

View file

@ -0,0 +1,54 @@
#include "rotatev.h"
#include "objects/jointsservice.h"
#include "objects/part.h"
#include "objects/workspace.h"
#include "rendering/renderer.h"
#include <reactphysics3d/constraint/HingeJoint.h>
#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> 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<rp::HingeJoint*>(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;
}

View file

@ -0,0 +1,21 @@
#pragma once
#include "objects/annotation.h"
#include "objects/base/instance.h"
#include "objects/joint/jointinstance.h"
#include <memory>
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<RotateV> New() { return std::make_shared<RotateV>(); };
static inline std::shared_ptr<Instance> Create() { return std::make_shared<RotateV>(); };
};

View file

@ -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<std::string, const InstanceType*> INSTANCE_MAP = {
{ "Part", &Part::TYPE },
{ "Snap", &Snap::TYPE },
{ "Weld", &Weld::TYPE },
{ "Rotate", &Rotate::TYPE },
{ "RotateV", &RotateV::TYPE },
{ "JointInstance", &JointInstance::TYPE },
{ "Script", &Script::TYPE },

View file

@ -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<std::shared_ptr<JointInstance>> 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)

View file

@ -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<Part> otherPart);
friend JointInstance;
friend Workspace;
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>> child, std::optional<std::shared_ptr<Instance>> newParent) override;
void onUpdated(std::string);

View file

@ -3,6 +3,7 @@
#include "objects/jointsservice.h"
#include "objects/joint/jointinstance.h"
#include "physics/util.h"
#include <memory>
#include <reactphysics3d/engine/PhysicsCommon.h>
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<JointInstance> motor = joint.lock()->CastTo<JointInstance>().expect();
part->rigidBody->enableGravity(false);
part->rigidBody->setAngularVelocity((motor->part0.lock()->cframe * motor->c0).LookVector() * 10.f);
}
}
}

View file

@ -28,6 +28,7 @@ class Part;
class Snap;
class Weld;
class Rotate;
class RotateV;
typedef std::function<FilterResult(std::shared_ptr<Part>)> 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;

View file

@ -17,6 +17,7 @@ enum SurfaceType {
SurfaceInlets = 4,
SurfaceUniversal = 5,
SurfaceHinge = 6,
SurfaceMotor = 7,
};
namespace Data { class Vector3; } using Data::Vector3;

View file

@ -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;
}