// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. #pragma once #include "Joint.h" #include "Limits.h" /// /// Specifies axes that the D6 joint can constrain motion on. /// API_ENUM() enum class D6JointAxis { /// /// Movement on the X axis. /// X = 0, /// /// Movement on the Y axis. /// Y = 1, /// /// Movement on the Z axis. /// Z = 2, /// /// Rotation around the X axis. /// Twist = 3, /// /// Rotation around the Y axis. /// SwingY = 4, /// /// Rotation around the Z axis. /// SwingZ = 5, API_ENUM(Attributes="HideInEditor") MAX }; /// /// Specifies type of constraint placed on a specific axis. /// API_ENUM() enum class D6JointMotion { /// /// Axis is immovable. /// Locked, /// /// Axis will be constrained by the specified limits. /// Limited, /// /// Axis will not be constrained. /// Free, API_ENUM(Attributes="HideInEditor") MAX }; /// /// Type of drives that can be used for moving or rotating bodies attached to the joint. /// /// /// Each drive is an implicit force-limited damped spring: /// force = spring * (target position - position) + damping * (targetVelocity - velocity) /// /// Alternatively, the spring may be configured to generate a specified acceleration instead of a force. /// /// A linear axis is affected by drive only if the corresponding drive flag is set.There are two possible models /// for angular drive : swing / twist, which may be used to drive one or more angular degrees of freedom, or slerp, /// which may only be used to drive all three angular degrees simultaneously. /// API_ENUM() enum class D6JointDriveType { /// /// Linear movement on the X axis using the linear drive model. /// X = 0, /// /// Linear movement on the Y axis using the linear drive model. /// Y = 1, /// /// Linear movement on the Z axis using the linear drive model. /// Z = 2, /// /// Rotation around the Y axis using the twist/swing angular drive model. Should not be used together with Slerp mode. /// Swing = 3, /// /// Rotation around the Z axis using the twist/swing angular drive model. Should not be used together with Slerp mode. /// Twist = 4, /// /// Rotation using spherical linear interpolation. Uses the SLERP angular drive mode which performs rotation /// by interpolating the quaternion values directly over the shortest path (applies to all three axes, which /// they all must be unlocked). /// Slerp = 5, API_ENUM(Attributes="HideInEditor") MAX }; /// /// Specifies parameters for a drive that will attempt to move the joint bodies to the specified drive position and velocity. /// API_STRUCT() struct D6JointDrive { DECLARE_SCRIPTING_TYPE_MINIMAL(D6JointDrive); /// /// The spring strength. Force proportional to the position error. /// API_FIELD() float Stiffness = 0.0f; /// /// Damping strength. Force proportional to the velocity error. /// API_FIELD() float Damping = 0.0f; /// /// The maximum force the drive can apply. /// API_FIELD() float ForceLimit = MAX_float; /// /// If true the drive will generate acceleration instead of forces. Acceleration drives are easier to tune as they account for the masses of the actors to which the joint is attached. /// API_FIELD() bool Acceleration = false; public: bool operator==(const D6JointDrive& other) const { return Stiffness == other.Stiffness && Damping == other.Damping && ForceLimit == other.ForceLimit && Acceleration == other.Acceleration; } }; /// /// Physics joint that is the most customizable type of joint. This joint type can be used to create all other built-in joint /// types, and to design your own custom ones, but is less intuitive to use. Allows a specification of a linear /// constraint (for example for a slider), twist constraint (rotating around X) and swing constraint (rotating around Y and Z). /// It also allows you to constrain limits to only specific axes or completely lock specific axes. /// /// API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Joints/D6 Joint\"), ActorToolbox(\"Physics\")") class FLAXENGINE_API D6Joint : public Joint { DECLARE_SCENE_OBJECT(D6Joint); private: D6JointMotion _motion[static_cast(D6JointAxis::MAX)]; D6JointDrive _drive[static_cast(D6JointDriveType::MAX)]; LimitLinear _limitLinear; LimitAngularRange _limitTwist; LimitConeRange _limitSwing; public: /// /// Gets the motion type around the specified axis. /// /// Each axis may independently specify that the degree of freedom is locked (blocking relative movement along or around this axis), limited by the corresponding limit, or free. /// The axis the degree of freedom around which the motion type is specified. /// The value. API_FUNCTION() FORCE_INLINE D6JointMotion GetMotion(const D6JointAxis axis) const { return _motion[static_cast(axis)]; } /// /// Sets the motion type around the specified axis. /// /// Each axis may independently specify that the degree of freedom is locked (blocking relative movement along or around this axis), limited by the corresponding limit, or free. /// The axis the degree of freedom around which the motion type is specified. /// The value. API_FUNCTION() void SetMotion(const D6JointAxis axis, const D6JointMotion value); /// /// Gets the drive parameters for the specified drive type. /// /// The type of drive being specified. /// The value. API_FUNCTION() FORCE_INLINE D6JointDrive GetDrive(const D6JointDriveType index) const { return _drive[static_cast(index)]; } /// /// Sets the drive parameters for the specified drive type. /// /// The type of drive being specified. /// The value. API_FUNCTION() void SetDrive(const D6JointDriveType index, const D6JointDrive& value); public: /// /// Determines the linear limit used for constraining translation degrees of freedom. /// API_PROPERTY(Attributes="EditorOrder(200), EditorDisplay(\"Joint\")") FORCE_INLINE LimitLinear GetLimitLinear() const { return _limitLinear; } /// /// Determines the linear limit used for constraining translation degrees of freedom. /// API_PROPERTY() void SetLimitLinear(const LimitLinear& value); /// /// Determines the angular limit used for constraining the twist (rotation around X) degree of freedom. /// API_PROPERTY(Attributes="EditorOrder(210), EditorDisplay(\"Joint\")") FORCE_INLINE LimitAngularRange GetLimitTwist() const { return _limitTwist; } /// /// Determines the angular limit used for constraining the twist (rotation around X) degree of freedom. /// API_PROPERTY() void SetLimitTwist(const LimitAngularRange& value); /// /// Determines the cone limit used for constraining the swing (rotation around Y and Z) degree of freedom. /// API_PROPERTY(Attributes="EditorOrder(220), EditorDisplay(\"Joint\")") FORCE_INLINE LimitConeRange GetLimitSwing() const { return _limitSwing; } /// /// Determines the cone limit used for constraining the swing (rotation around Y and Z) degree of freedom. /// API_PROPERTY() void SetLimitSwing(const LimitConeRange& value); public: /// /// Gets the drive's target position relative to the joint's first body. /// API_PROPERTY(Attributes="HideInEditor") Vector3 GetDrivePosition() const; /// /// Sets the drive's target position relative to the joint's first body. /// API_PROPERTY() void SetDrivePosition(const Vector3& value); /// /// Gets the drive's target rotation relative to the joint's first body. /// API_PROPERTY(Attributes="HideInEditor") Quaternion GetDriveRotation() const; /// /// Sets the drive's target rotation relative to the joint's first body. /// API_PROPERTY() void SetDriveRotation(const Quaternion& value); /// /// Gets the drive's target linear velocity. /// API_PROPERTY(Attributes="HideInEditor") Vector3 GetDriveLinearVelocity() const; /// /// Sets the drive's target linear velocity. /// API_PROPERTY() void SetDriveLinearVelocity(const Vector3& value); /// /// Gets the drive's target angular velocity. /// API_PROPERTY(Attributes="HideInEditor") Vector3 GetDriveAngularVelocity() const; /// /// Sets the drive's target angular velocity. /// API_PROPERTY() void SetDriveAngularVelocity(const Vector3& value); public: /// /// Gets the twist angle of the joint (in the range (-2*Pi, 2*Pi]). /// API_PROPERTY() float GetCurrentTwist() const; /// /// Gets the current swing angle of the joint from the Y axis. /// API_PROPERTY() float GetCurrentSwingY() const; /// /// Gets the current swing angle of the joint from the Z axis. /// API_PROPERTY() float GetCurrentSwingZ() const; public: // [Joint] #if USE_EDITOR void OnDebugDrawSelected() override; #endif void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; protected: // [Joint] void* CreateJoint(const PhysicsJointDesc& desc) override; };