// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Level/Actor.h" #include "Engine/Physics/Types.h" #include "Engine/Scripting/ScriptingObjectReference.h" class IPhysicsActor; /// /// A base class for all Joint types. Joints constrain how two rigidbodies move relative to one another (for example a door hinge). /// One of the bodies in the joint must always be movable (non-kinematic and non-static). /// /// /// Joint constraint is created between the parent physic actor (rigidbody, character controller, etc.) and the specified target actor. /// /// API_CLASS(Abstract) class FLAXENGINE_API Joint : public Actor { DECLARE_SCENE_OBJECT_ABSTRACT(Joint); protected: void* _joint; float _breakForce; float _breakTorque; Vector3 _targetAnchor; Quaternion _targetAnchorRotation; bool _enableCollision = true; bool _enableAutoAnchor = false; public: /// /// The target actor for the joint. It has to be IPhysicsActor type (eg. RigidBody or CharacterController). /// API_FIELD(Attributes="EditorOrder(0), DefaultValue(null), EditorDisplay(\"Joint\")") ScriptingObjectReference Target; /// /// Gets the break force. Determines the maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation. /// API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(float.MaxValue), EditorDisplay(\"Joint\")") FORCE_INLINE float GetBreakForce() const { return _breakForce; } /// /// Sets the break force. Determines the maximum force the joint can apply before breaking. Broken joints no longer participate in physics simulation. /// API_PROPERTY() void SetBreakForce(float value); /// /// Gets the break torque. Determines the maximum torque the joint can apply before breaking. Broken joints no longer participate in physics simulation. /// API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(float.MaxValue), EditorDisplay(\"Joint\")") FORCE_INLINE float GetBreakTorque() const { return _breakTorque; } /// /// Sets the break torque. Determines the maximum torque the joint can apply before breaking. Broken joints no longer participate in physics simulation. /// API_PROPERTY() void SetBreakTorque(float value); /// /// Determines whether collision between the two bodies managed by the joint are enabled. /// API_PROPERTY(Attributes="EditorOrder(30), DefaultValue(true), EditorDisplay(\"Joint\")") FORCE_INLINE bool GetEnableCollision() const { return _enableCollision; } /// /// Determines whether collision between the two bodies managed by the joint are enabled. /// API_PROPERTY() void SetEnableCollision(bool value); /// /// Determines whether use automatic target anchor position and rotation based on the joint world-space frame (computed when creating joint). /// API_PROPERTY(Attributes="EditorOrder(39), DefaultValue(false), EditorDisplay(\"Joint\")") bool GetEnableAutoAnchor() const; /// /// Determines whether use automatic target anchor position and rotation based on the joint world-space frame (computed when creating joint). /// API_PROPERTY() void SetEnableAutoAnchor(bool value); /// /// Gets the target anchor. /// /// /// This is the relative pose which locates the joint frame relative to the target actor. /// API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorDisplay(\"Joint\"), VisibleIf(nameof(EnableAutoAnchor), true)") FORCE_INLINE Vector3 GetTargetAnchor() const { return _targetAnchor; } /// /// Sets the target anchor. /// /// /// This is the relative pose which locates the joint frame relative to the target actor. /// API_PROPERTY() void SetTargetAnchor(const Vector3& value); /// /// Gets the target anchor rotation. /// /// /// This is the relative pose rotation which locates the joint frame relative to the target actor. /// API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(typeof(Quaternion), \"0,0,0,1\"), EditorDisplay(\"Joint\"), VisibleIf(nameof(EnableAutoAnchor), true)") FORCE_INLINE Quaternion GetTargetAnchorRotation() const { return _targetAnchorRotation; } /// /// Sets the target anchor rotation. /// /// /// This is the relative pose rotation which locates the joint frame relative to the target actor. /// API_PROPERTY() void SetTargetAnchorRotation(const Quaternion& value); public: /// /// Gets the native physics backend object. /// void* GetPhysicsImpl() const; /// /// Sets the location of the joint by automatically computing local position and target anchor to place a joint at the given location (world-space). /// /// Use this utility to automatically place joint at the given location after setting up joint parent and target. /// The joint location to set (world-space). API_FUNCTION() void SetJointLocation(const Vector3& location); /// /// Sets the orientation of the joint by automatically computing local orientation and target anchor orientation to orient a joint at the given rotation (world-space). /// /// Use this utility to automatically rotate joint at the given location after setting up joint parent and target. /// The joint orientation to set (world-space). API_FUNCTION() void SetJointOrientation(const Quaternion& orientation); /// /// Gets the current force applied by the solver to maintain all constraints. /// /// The result linear force. /// The result angular force. API_FUNCTION() void GetCurrentForce(API_PARAM(Out) Vector3& linear, API_PARAM(Out) Vector3& angular) const; /// /// Creates native join object. /// void Create(); /// /// Occurs when a joint gets broken during simulation. /// API_EVENT() Action JointBreak; /// /// Called by the physics system when joint gets broken. /// virtual void OnJointBreak(); protected: Vector3 GetTargetPosition() const; Quaternion GetTargetOrientation() const; virtual void* CreateJoint(const struct PhysicsJointDesc& desc) = 0; #if USE_EDITOR virtual void DrawPhysicsDebug(RenderView& view); #endif private: void Delete(); void SetActors(); void OnTargetChanged(); public: // [Actor] #if USE_EDITOR void OnDebugDrawSelected() override; #endif void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; protected: // [Actor] void BeginPlay(SceneBeginData* data) override; void EndPlay() override; #if USE_EDITOR void OnEnable() override; void OnDisable() override; #endif void OnActiveInTreeChanged() override; void OnParentChanged() override; void OnTransformChanged() override; };