You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/PhysX/Code/Source/RigidBodyComponent.h

189 lines
7.9 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <PxPhysicsAPI.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/TransformBus.h>
#include <AzFramework/Physics/RigidBodyBus.h>
#include <AzFramework/Physics/Components/SimulatedBodyComponentBus.h>
#include <AzFramework/Physics/Common/PhysicsEvents.h>
#include <AzFramework/Physics/Configuration/RigidBodyConfiguration.h>
#include <AzFramework/Physics/SimulatedBodies/RigidBody.h>
#include <AzFramework/Entity/SliceGameEntityOwnershipServiceBus.h>
namespace AzPhysics
{
struct SimulatedBody;
}
namespace PhysX
{
class TransformForwardTimeInterpolator;
/// Component used to register an entity as a dynamic rigid body in the PhysX simulation.
class RigidBodyComponent
: public AZ::Component
, public Physics::RigidBodyRequestBus::Handler
, public AzPhysics::SimulatedBodyComponentRequestsBus::Handler
, public AZ::TickBus::Handler
, public AzFramework::SliceGameEntityOwnershipServiceNotificationBus::Handler
, protected AZ::TransformNotificationBus::MultiHandler
{
public:
AZ_COMPONENT(RigidBodyComponent, "{D4E52A70-BDE1-4819-BD3C-93AB3F4F3BE3}");
static void Reflect(AZ::ReflectContext* context);
RigidBodyComponent();
explicit RigidBodyComponent(const AzPhysics::RigidBodyConfiguration& config, AzPhysics::SceneHandle sceneHandle);
~RigidBodyComponent() override = default;
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("PhysXRigidBodyService", 0x1d4c64a8));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("PhysXRigidBodyService", 0x1d4c64a8));
incompatible.push_back(AZ_CRC("PhysicsService", 0xa7350d22));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("PhysXColliderService", 0x4ff43f7c));
}
// RigidBodyRequests + WorldBodyRequests
void EnablePhysics() override;
void DisablePhysics() override;
bool IsPhysicsEnabled() const override;
AzPhysics::SceneQueryHit RayCast(const AzPhysics::RayCastRequest& request) override;
AZ::Aabb GetAabb() const override;
// RigidBodyRequests
AZ::Vector3 GetCenterOfMassWorld() const override;
virtual AZ::Vector3 GetCenterOfMassLocal() const override;
AZ::Matrix3x3 GetInverseInertiaWorld() const override;
AZ::Matrix3x3 GetInverseInertiaLocal() const override;
float GetMass() const override;
float GetInverseMass() const override;
void SetMass(float mass) override;
void SetCenterOfMassOffset(const AZ::Vector3& comOffset) override;
AZ::Vector3 GetLinearVelocity() const override;
void SetLinearVelocity(const AZ::Vector3& velocity) override;
AZ::Vector3 GetAngularVelocity() const override;
void SetAngularVelocity(const AZ::Vector3& angularVelocity) override;
AZ::Vector3 GetLinearVelocityAtWorldPoint(const AZ::Vector3& worldPoint) const override;
void ApplyLinearImpulse(const AZ::Vector3& impulse) override;
void ApplyLinearImpulseAtWorldPoint(const AZ::Vector3& impulse, const AZ::Vector3& worldPoint) override;
void ApplyAngularImpulse(const AZ::Vector3& angularImpulse) override;
float GetLinearDamping() const override;
void SetLinearDamping(float damping) override;
float GetAngularDamping() const override;
void SetAngularDamping(float damping) override;
bool IsAwake() const override;
void ForceAsleep() override;
void ForceAwake() override;
bool IsKinematic() const override;
void SetKinematic(bool kinematic) override;
void SetKinematicTarget(const AZ::Transform& targetPosition) override;
bool IsGravityEnabled() const override;
void SetGravityEnabled(bool enabled) override;
void SetSimulationEnabled(bool enabled) override;
float GetSleepThreshold() const override;
void SetSleepThreshold(float threshold) override;
AzPhysics::RigidBody* GetRigidBody() override;
// AzPhysics::SimulatedBodyComponentRequestsBus::Handler overrides ...
AzPhysics::SimulatedBody* GetSimulatedBody() override;
AzPhysics::SimulatedBodyHandle GetSimulatedBodyHandle() const override;
// SliceGameEntityOwnershipServiceNotificationBus
void OnSliceInstantiated(const AZ::Data::AssetId&, const AZ::SliceComponent::SliceInstanceAddress&,
const AzFramework::SliceInstantiationTicket&) override;
void OnSliceInstantiationFailed(const AZ::Data::AssetId&, const AzFramework::SliceInstantiationTicket&) override;
AzPhysics::RigidBodyConfiguration& GetConfiguration()
{
return m_configuration;
}
protected:
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
int GetTickOrder() override;
// TransformNotificationBus
void OnTransformChanged(const AZ::Transform& local, const AZ::Transform& world) override;
private:
void SetupConfiguration();
void CreatePhysics();
void InitPhysicsTickHandler();
void PostPhysicsTick(float fixedDeltaTime);
const AzPhysics::RigidBody* GetRigidBodyConst() const;
std::unique_ptr<TransformForwardTimeInterpolator> m_interpolator;
AzPhysics::RigidBodyConfiguration m_configuration;
AzPhysics::SimulatedBodyHandle m_rigidBodyHandle = AzPhysics::InvalidSimulatedBodyHandle;
AzPhysics::SceneHandle m_attachedSceneHandle = AzPhysics::InvalidSceneHandle;
bool m_staticTransformAtActivation = false; ///< Whether the transform was static when the component last activated.
bool m_isLastMovementFromKinematicSource = false; ///< True when the source of the movement comes from SetKinematicTarget as opposed to coming from a Transform change
bool m_rigidBodyTransformNeedsUpdateOnPhysReEnable = false; ///< True if rigid body transform needs to be synced to the entity's when physics is re-enabled
AzPhysics::SceneEvents::OnSceneSimulationFinishHandler m_sceneFinishSimHandler;
};
class TransformForwardTimeInterpolator
{
public:
AZ_RTTI(TransformForwardTimeInterpolator, "{2517631D-9CF3-4F9C-921C-03FB44DE377C}");
AZ_CLASS_ALLOCATOR(TransformForwardTimeInterpolator, AZ::SystemAllocator, 0);
virtual ~TransformForwardTimeInterpolator() = default;
void Reset(const AZ::Vector3& position, const AZ::Quaternion& rotation);
void SetTarget(const AZ::Vector3& position, const AZ::Quaternion& rotation, float fixedDeltaTime);
void GetInterpolated(AZ::Vector3& position, AZ::Quaternion& rotation, float realDeltaTime);
private:
static const AZ::u32 FloatToIntegralResolution = 1000u;
AZ::u32 FloatToIntegralTime(float deltaTime) { return static_cast<AZ::u32>(deltaTime * FloatToIntegralResolution) + m_integralTime; }
AZ::LinearlyInterpolatedSample<AZ::Vector3> m_targetTranslation;
AZ::LinearlyInterpolatedSample<AZ::Quaternion> m_targetRotation;
float m_currentRealTime = 0.0f;
float m_currentFixedTime = 0.0f;
AZ::u32 m_integralTime = 0;
};
} // namespace PhysX