/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #pragma once #include <AzFramework/Physics/Character.h> #include <AzFramework/Physics/Collision.h> #include <PhysX/UserDataTypes.h> #include <PxPhysicsAPI.h> namespace PhysXCharacters { static const float epsilon = 1e-3f; enum class SlopeBehaviour { PreventClimbing, ForceSliding }; /// Allows PhysX specific character controller properties that are not included in the generic configuration. class CharacterControllerConfiguration : public Physics::CharacterConfiguration { public: AZ_CLASS_ALLOCATOR(CharacterControllerConfiguration, AZ::SystemAllocator, 0); AZ_RTTI(CharacterControllerConfiguration, "{23A8DFD6-7DA4-4CB3-BBD3-7FB58DEE6F9D}", Physics::CharacterConfiguration); static void Reflect(AZ::ReflectContext* context); CharacterControllerConfiguration() = default; CharacterControllerConfiguration(const CharacterControllerConfiguration&) = default; virtual ~CharacterControllerConfiguration() = default; SlopeBehaviour m_slopeBehaviour = SlopeBehaviour::PreventClimbing; ///< Behaviour on surfaces above maximum slope. float m_contactOffset = 0.1f; ///< Extra distance outside the controller used to give smoother contact resolution. float m_scaleCoefficient = 0.8f; ///< Scalar coefficient used to scale the controller, usually slightly smaller than 1. }; class CharacterController : public Physics::Character , public physx::PxControllerFilterCallback , public physx::PxQueryFilterCallback { friend class CharacterControllerComponent; public: AZ_CLASS_ALLOCATOR(CharacterController, AZ::SystemAllocator, 0); AZ_TYPE_INFO_LEGACY(CharacterController, "{A75A7D19-BC21-4F7E-A3D9-05031D2DFC94}", Physics::Character); static void Reflect(AZ::ReflectContext* context); CharacterController() = default; explicit CharacterController(physx::PxController* pxController); ~CharacterController(); void SetFilterDataAndShape(const Physics::CharacterConfiguration& characterConfig); void SetUserData(const Physics::CharacterConfiguration& characterConfig); void SetActorName(const AZStd::string& name = "Character Controller"); void SetMinimumMovementDistance(float distance); void CreateShadowBody(const Physics::CharacterConfiguration& configuration, Physics::World&); void SetTag(const AZStd::string& tag); // Physics::Character AZ::Vector3 GetBasePosition() const override; void SetBasePosition(const AZ::Vector3& position) override; AZ::Vector3 GetCenterPosition() const override; float GetStepHeight() const override; void SetStepHeight(float stepHeight) override; AZ::Vector3 GetUpDirection() const override; void SetUpDirection(const AZ::Vector3& upDirection) override; float GetSlopeLimitDegrees() const override; void SetSlopeLimitDegrees(float slopeLimitDegrees) override; AZ::Vector3 GetVelocity() const override; Physics::CollisionLayer GetCollisionLayer() const override; Physics::CollisionGroup GetCollisionGroup() const override; void SetCollisionLayer(const Physics::CollisionLayer& layer) override; void SetCollisionGroup(const Physics::CollisionGroup& group) override; AZ::Crc32 GetColliderTag() const override; AZ::Vector3 TryRelativeMove(const AZ::Vector3& deltaPosition, float deltaTime) override; void SetRotation(const AZ::Quaternion& rotation) override; void CheckSupport(const AZ::Vector3& direction, float distance, const Physics::CharacterSupportInfo& supportInfo) override; void AttachShape(AZStd::shared_ptr<Physics::Shape> shape) override; // Physics::WorldBody AZ::EntityId GetEntityId() const override; Physics::World* GetWorld() const override; AZ::Transform GetTransform() const override; void SetTransform(const AZ::Transform& transform) override; AZ::Vector3 GetPosition() const override; AZ::Quaternion GetOrientation() const override; AZ::Aabb GetAabb() const override; Physics::RayCastHit RayCast(const Physics::RayCastRequest& request) override; AZ::Crc32 GetNativeType() const override; void* GetNativePointer() const override; void AddToWorld(Physics::World&) override; void RemoveFromWorld(Physics::World&) override; // physx::PxControllerFilterCallback bool filter(const physx::PxController& controllerA, const physx::PxController& controllerB) override; // physx::PxQueryFilterCallback physx::PxQueryHitType::Enum preFilter(const physx::PxFilterData& filterData, const physx::PxShape* shape, const physx::PxRigidActor* actor, physx::PxHitFlags& queryFlags) override; physx::PxQueryHitType::Enum postFilter(const physx::PxFilterData& filterData, const physx::PxQueryHit& hit) override; // CharacterController specific void Resize(float height); float GetHeight() const; void SetHeight(float height); float GetRadius() const; void SetRadius(float radius); float GetHalfSideExtent() const; void SetHalfSideExtent(float halfSideExtent); float GetHalfForwardExtent() const; void SetHalfForwardExtent(float halfForwardExtent); private: /// Update the velocity based on the outcome of the controller's movement in the simulation. This can differ /// from the desired velocity, for example if the character is stuck in a corner its observed velocity may be /// zero in spite of having a non-zero desired velocity. void UpdateObservedVelocity(const AZ::Vector3& observedVelocity); void UpdatePxControllerFilters(Physics::CollisionLayer collisionLayer, Physics::CollisionGroup collisionGroup); physx::PxController* m_pxController = nullptr; ///< The underlying PhysX controller. float m_minimumMovementDistance = 0.0f; ///< To avoid jittering, the controller will not attempt to move distances below this. AZ::Vector3 m_observedVelocity = AZ::Vector3::CreateZero(); ///< Velocity observed in the simulation, may not match desired. PhysX::ActorData m_actorUserData; ///< Used to populate the user data on the PxActor associated with the controller. physx::PxFilterData m_filterData; ///< Controls filtering for collisions with other objects and scene queries. physx::PxControllerFilters m_pxControllerFilters; ///< Controls which objects the controller interacts with when moving. AZStd::shared_ptr<Physics::Material> m_material; ///< The generic physics API material for the controller. AZStd::shared_ptr<Physics::Shape> m_shape; ///< The generic physics API shape associated with the controller. AZStd::unique_ptr<Physics::RigidBody> m_shadowBody; ///< A kinematic-synchronised rigid body used to store additional colliders. AZStd::string m_name = "Character Controller"; ///< Name to set on the PhysX actor associated with the controller. AZ::Crc32 m_colliderTag; ///< Tag used to identify the collider associated with the controller. }; } // namespace PhysXCharacters