// Copyright (c) 2012-2020 Wojciech Figat. All rights reserved. #pragma once #include "PhysicsActor.h" #include "Engine/Physics/Collisions.h" class PhysicsColliderActor; /// /// Physics simulation driven object. /// /// API_CLASS() class FLAXENGINE_API RigidBody : public PhysicsActor { DECLARE_SCENE_OBJECT(RigidBody); private: PxRigidDynamic* _actor; Vector3 _cachedScale; float _mass; float _linearDamping; float _angularDamping; float _maxAngularVelocity; float _massScale; Vector3 _centerOfMassOffset; RigidbodyConstraints _constraints; int32 _enableSimulation : 1; int32 _isKinematic : 1; int32 _useCCD : 1; int32 _enableGravity : 1; int32 _startAwake : 1; int32 _updateMassWhenScaleChanges : 1; int32 _overrideMass : 1; public: /// /// Enables kinematic mode for the rigidbody. /// /// /// Kinematic rigidbodies are special dynamic actors that are not influenced by forces(such as gravity), and have no momentum. /// They are considered to have infinite mass and can push regular dynamic actors out of the way. /// Kinematics will not collide with static or other kinematic objects. /// /// Kinematic rigidbodies are great for moving platforms or characters, where direct motion control is desired. /// /// /// Kinematic rigidbodies are incompatible with CCD. /// /// /// The value. API_PROPERTY(Attributes="EditorOrder(10), DefaultValue(false), EditorDisplay(\"Rigid Body\")") FORCE_INLINE bool GetIsKinematic() const { return _isKinematic != 0; } /// /// Enables kinematic mode for the rigidbody. /// /// /// Kinematic rigidbodies are special dynamic actors that are not influenced by forces(such as gravity), and have no momentum. /// They are considered to have infinite mass and can push regular dynamic actors out of the way. /// Kinematics will not collide with static or other kinematic objects. /// /// Kinematic rigidbodies are great for moving platforms or characters, where direct motion control is desired. /// /// /// Kinematic rigidbodies are incompatible with CCD. /// /// /// The value. API_PROPERTY() void SetIsKinematic(const bool value); /// /// Gets the 'drag' force added to reduce linear movement. /// /// /// Linear damping can be used to slow down an object. The higher the drag the more the object slows down. /// /// The value. API_PROPERTY(Attributes="EditorOrder(60), DefaultValue(0.01f), Limit(0), EditorDisplay(\"Rigid Body\")") FORCE_INLINE float GetLinearDamping() const { return _linearDamping; } /// /// Sets the 'drag' force added to reduce linear movement. /// /// /// Linear damping can be used to slow down an object. The higher the drag the more the object slows down. /// /// The value. API_PROPERTY() void SetLinearDamping(float value); /// /// Gets the 'drag' force added to reduce angular movement. /// /// /// Angular damping can be used to slow down the rotation of an object. The higher the drag the more the rotation slows down. /// /// The value. API_PROPERTY(Attributes="EditorOrder(70), DefaultValue(0.05f), Limit(0), EditorDisplay(\"Rigid Body\")") FORCE_INLINE float GetAngularDamping() const { return _angularDamping; } /// /// Sets the 'drag' force added to reduce angular movement. /// /// /// Angular damping can be used to slow down the rotation of an object. The higher the drag the more the rotation slows down. /// /// The value. API_PROPERTY() void SetAngularDamping(float value); /// /// If true simulation and collisions detection will be enabled for the rigidbody. /// /// The value. API_PROPERTY(Attributes="EditorOrder(20), DefaultValue(true), EditorDisplay(\"Rigid Body\")") FORCE_INLINE bool GetEnableSimulation() const { return _enableSimulation != 0; } /// /// If true simulation and collisions detection will be enabled for the rigidbody. /// /// The value. API_PROPERTY() void SetEnableSimulation(bool value); /// /// If true Continuous Collision Detection (CCD) will be used for this component. /// /// The value. API_PROPERTY(Attributes="EditorOrder(30), DefaultValue(false), EditorDisplay(\"Rigid Body\", \"Use CCD\")") FORCE_INLINE bool GetUseCCD() const { return _useCCD != 0; } /// /// If true Continuous Collision Detection (CCD) will be used for this component. /// /// The value. API_PROPERTY() void SetUseCCD(const bool value); /// /// If object should have the force of gravity applied. /// /// The value. API_PROPERTY(Attributes="EditorOrder(40), DefaultValue(true), EditorDisplay(\"Rigid Body\")") FORCE_INLINE bool GetEnableGravity() const { return _enableGravity != 0; } /// /// If object should have the force of gravity applied. /// /// The value. API_PROPERTY() void SetEnableGravity(bool value); /// /// If object should start awake, or if it should initially be sleeping. /// /// The value. API_PROPERTY(Attributes="EditorOrder(50), DefaultValue(true), EditorDisplay(\"Rigid Body\")") FORCE_INLINE bool GetStartAwake() const { return _startAwake != 0; } /// /// If object should start awake, or if it should initially be sleeping. /// /// The value. API_PROPERTY() void SetStartAwake(bool value); /// /// If true, it will update mass when actor scale changes. /// /// The value. API_PROPERTY(Attributes="EditorOrder(130), DefaultValue(false), EditorDisplay(\"Rigid Body\")") FORCE_INLINE bool GetUpdateMassWhenScaleChanges() const { return _updateMassWhenScaleChanges != 0; } /// /// If true, it will update mass when actor scale changes. /// /// The value. /// Gets the maximum angular velocity that a simulated object can achieve. /// /// /// The angular velocity of rigidbodies is clamped to MaxAngularVelocity to avoid numerical instability with fast rotating bodies. /// Because this may prevent intentional fast rotations on objects such as wheels, you can override this value per rigidbody. /// /// The value. API_PROPERTY(Attributes="EditorOrder(90), DefaultValue(7.0f), Limit(0), EditorDisplay(\"Rigid Body\")") FORCE_INLINE float GetMaxAngularVelocity() const { return _maxAngularVelocity; } /// /// Sets the maximum angular velocity that a simulated object can achieve. /// /// /// The angular velocity of rigidbodies is clamped to MaxAngularVelocity to avoid numerical instability with fast rotating bodies. /// Because this may prevent intentional fast rotations on objects such as wheels, you can override this value per rigidbody. /// /// The value. API_PROPERTY() void SetMaxAngularVelocity(float value); /// /// Override the auto computed mass. /// /// The value. API_PROPERTY(Attributes="HideInEditor") FORCE_INLINE bool GetOverrideMass() const { return _overrideMass != 0; } /// /// Override the auto computed mass. /// /// The value. API_PROPERTY() void SetOverrideMass(bool value); /// /// Gets the mass value measured in kilograms (use override value only if EnableOverrideMass is enabled). /// /// The value. API_PROPERTY(Attributes="EditorOrder(110), Limit(0), EditorDisplay(\"Rigid Body\")") FORCE_INLINE float GetMass() const { return _mass; } /// /// Sets the mass value measured in kilograms (use override value only if EnableOverrideMass is enabled). /// /// /// If set auto enables mass override. /// /// The value. API_PROPERTY() void SetMass(float value); /// /// Gets the per-instance scaling of the mass. /// /// The value. API_PROPERTY(Attributes="EditorOrder(120), DefaultValue(1.0f), Limit(0.001f, 100.0f), EditorDisplay(\"Rigid Body\")") FORCE_INLINE float GetMassScale() const { return _massScale; } /// /// Sets the per-instance scaling of the mass. /// /// The value. API_PROPERTY() void SetMassScale(float value); /// /// Gets the user specified offset for the center of mass of this object, from the calculated location. /// /// The value. API_PROPERTY(Attributes="EditorOrder(140), DefaultValue(typeof(Vector3), \"0,0,0\"), EditorDisplay(\"Rigid Body\", \"Center Of Mass Offset\")") FORCE_INLINE Vector3 GetCenterOfMassOffset() const { return _centerOfMassOffset; } /// /// Sets the user specified offset for the center of mass of this object, from the calculated location. /// /// The value. API_PROPERTY() void SetCenterOfMassOffset(const Vector3& value); /// /// Gets the object movement constraint flags that define degrees of freedom are allowed for the simulation of object. /// /// The value. API_PROPERTY(Attributes="EditorOrder(150), DefaultValue(RigidbodyConstraints.None), EditorDisplay(\"Rigid Body\")") FORCE_INLINE RigidbodyConstraints GetConstraints() const { return _constraints; } /// /// Sets the object movement constraint flags that define degrees of freedom are allowed for the simulation of object. /// /// The value. API_PROPERTY() void SetConstraints(const RigidbodyConstraints value); public: /// /// Gets the linear velocity of the rigidbody. /// /// /// It's used mostly to get the current velocity. Manual modifications may result in unrealistic behaviour. /// /// The value. API_PROPERTY(Attributes="HideInEditor") Vector3 GetLinearVelocity() const; /// /// Sets the linear velocity of the rigidbody. /// /// /// It's used mostly to get the current velocity. Manual modifications may result in unrealistic behaviour. /// /// The value. API_PROPERTY() void SetLinearVelocity(const Vector3& value) const; /// /// Gets the angular velocity of the rigidbody measured in radians per second. /// /// /// It's used mostly to get the current angular velocity. Manual modifications may result in unrealistic behaviour. /// /// The value. API_PROPERTY(Attributes="HideInEditor") Vector3 GetAngularVelocity() const; /// /// Sets the angular velocity of the rigidbody measured in radians per second. /// /// /// It's used mostly to get the current angular velocity. Manual modifications may result in unrealistic behaviour. /// /// The value. API_PROPERTY() void SetAngularVelocity(const Vector3& value) const; /// /// Gets the maximum depenetration velocity when rigidbody moving out of penetrating state. /// /// /// This value controls how much velocity the solver can introduce to correct for penetrations in contacts. /// Using this property can smooth objects moving out of colliding state and prevent unstable motion. /// /// The value API_PROPERTY(Attributes="HideInEditor") float GetMaxDepenetrationVelocity() const; /// /// Sets the maximum depenetration velocity when rigidbody moving out of penetrating state. /// /// /// This value controls how much velocity the solver can introduce to correct for penetrations in contacts. /// Using this property can smooth objects moving out of colliding state and prevent unstable motion. /// /// The value. API_PROPERTY() void SetMaxDepenetrationVelocity(const float value) const; /// /// Gets the mass-normalized kinetic energy threshold below which an actor may go to sleep. /// /// /// Actors whose kinetic energy divided by their mass is below this threshold will be candidates for sleeping. /// /// The value API_PROPERTY(Attributes="HideInEditor") float GetSleepThreshold() const; /// /// Sets the mass-normalized kinetic energy threshold below which an actor may go to sleep. /// /// /// Actors whose kinetic energy divided by their mass is below this threshold will be candidates for sleeping. /// /// The value. API_PROPERTY() void SetSleepThreshold(const float value) const; /// /// Gets the center of the mass in the local space. /// /// The value. API_PROPERTY() Vector3 GetCenterOfMass() const; /// /// Determines whether this rigidbody is sleeping. /// /// true if this rigidbody is sleeping; otherwise, false. API_PROPERTY() bool IsSleeping() const; public: /// /// Forces a rigidbody to sleep (for at least one frame). /// API_FUNCTION() void Sleep() const; /// /// Forces a rigidbody to wake up. /// API_FUNCTION() void WakeUp() const; /// /// Updates the actor's mass (auto calculated mass from density and inertia tensor or overriden value). /// API_FUNCTION() void UpdateMass(); /// /// Gets the native PhysX rigid actor object. /// /// The PhysX dynamic rigid actor. FORCE_INLINE PxRigidDynamic* GetPhysXRigidActor() const { return _actor; } /// /// Applies a force (or impulse) defined in the world space to the rigidbody at its center of mass. /// /// /// This will not induce a torque /// /// ForceMode determines if the force is to be conventional or impulsive. /// /// /// Each actor has an acceleration and a velocity change accumulator which are directly modified using the modes ForceMode::Acceleration /// and ForceMode::VelocityChange respectively. The modes ForceMode::Force and ForceMode::Impulse also modify these same /// accumulators and are just short hand for multiplying the vector parameter by inverse mass and then using ForceMode::Acceleration and /// ForceMode::VelocityChange respectively. /// /// /// The force/impulse to apply defined in the world space. /// The mode to use when applying the force/impulse. API_FUNCTION() void AddForce(const Vector3& force, ForceMode mode = ForceMode::Force) const; /// /// Applies a force (or impulse) defined in the local space of the rigidbody (relative to its coordinate system) at its center of mass. /// /// /// This will not induce a torque /// /// ForceMode determines if the force is to be conventional or impulsive. /// /// /// Each actor has an acceleration and a velocity change accumulator which are directly modified using the modes ForceMode::Acceleration /// and ForceMode::VelocityChange respectively. The modes ForceMode::Force and ForceMode::Impulse also modify these same /// accumulators and are just short hand for multiplying the vector parameter by inverse mass and then using ForceMode::Acceleration and /// ForceMode::VelocityChange respectively. /// /// /// The force/impulse to apply defined in the local space. /// The mode to use when applying the force/impulse. API_FUNCTION() void AddRelativeForce(const Vector3& force, ForceMode mode = ForceMode::Force) const; /// /// Applies an impulsive torque defined in the world space to the rigidbody. /// /// /// ForceMode determines if the force is to be conventional or impulsive. /// /// Each actor has an angular acceleration and an angular velocity change accumulator which are directly modified using the modes /// ForceMode::Acceleration and ForceMode::VelocityChange respectively.The modes ForceMode::Force and ForceMode::Impulse /// also modify these same accumulators and are just short hand for multiplying the vector parameter by inverse inertia and then /// using ForceMode::Acceleration and ForceMode::VelocityChange respectively. /// /// /// The torque to apply defined in the world space. /// The mode to use when applying the force/impulse. API_FUNCTION() void AddTorque(const Vector3& torque, ForceMode mode = ForceMode::Force) const; /// /// Applies an impulsive torque defined in the local space of the rigidbody (relative to its coordinate system). /// /// /// ForceMode determines if the force is to be conventional or impulsive. /// /// Each actor has an angular acceleration and an angular velocity change accumulator which are directly modified using the modes /// ForceMode::Acceleration and ForceMode::VelocityChange respectively.The modes ForceMode::Force and ForceMode::Impulse /// also modify these same accumulators and are just short hand for multiplying the vector parameter by inverse inertia and then /// using ForceMode::Acceleration and ForceMode::VelocityChange respectively. /// /// /// The torque to apply defined in the local space. /// The mode to use when applying the force/impulse. API_FUNCTION() void AddRelativeTorque(const Vector3& torque, ForceMode mode = ForceMode::Force) const; /// /// Sets the solver iteration counts for the rigidbody. /// /// /// The solver iteration count determines how accurately joints and contacts are resolved. /// If you are having trouble with jointed bodies oscillating and behaving erratically, /// then setting a higher position iteration count may improve their stability. /// /// If intersecting bodies are being depenetrated too violently, increase the number of velocity /// iterations. More velocity iterations will drive the relative exit velocity of the intersecting /// objects closer to the correct value given the restitution. /// /// /// Default: 4 position iterations, 1 velocity iteration. /// /// /// The minimum number of position iterations the solver should perform for this body. /// The minimum number of velocity iterations the solver should perform for this body. API_FUNCTION() void SetSolverIterationCounts(int32 minPositionIters, int32 minVelocityIters) const; /// /// Gets a point on one of the colliders attached to the attached that is closest to a given location. Can be used to find a hit location or position to apply explosion force or any other special effects. /// /// The position to find the closest point to it. /// The result point on the rigidbody shape that is closest to the specified location. API_FUNCTION() void ClosestPoint(const Vector3& position, API_PARAM(Out) Vector3& result) const; public: /// /// Occurs when a collision start gets registered for this rigidbody (it collides with something). /// API_EVENT() Delegate CollisionEnter; /// /// Occurs when a collision end gets registered for this rigidbody (it ends colliding with something). /// API_EVENT() Delegate CollisionExit; /// /// Occurs when this rigidbody trigger touching start gets registered for this collider (the other collider enters it and triggers the event). /// API_EVENT() Delegate TriggerEnter; /// /// Occurs when this rigidbody trigger touching end gets registered for this collider (the other collider enters it and triggers the event). /// API_EVENT() Delegate TriggerExit; public: void OnCollisionEnter(const Collision& c); void OnCollisionExit(const Collision& c); void OnTriggerEnter(PhysicsColliderActor* c); void OnTriggerExit(PhysicsColliderActor* c); protected: /// /// Creates the physics actor. /// void CreateActor(); /// /// Updates the rigidbody scale dependent properties like mass (may be modified when actor transformation changes). /// void UpdateScale(); public: // [PhysicsActor] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; PxActor* GetPhysXActor() override; PxRigidActor* GetRigidActor() override; protected: // [PhysicsActor] void BeginPlay(SceneBeginData* data) override; void EndPlay() override; void OnActiveInTreeChanged() override; void OnTransformChanged() override; };