11#include " CharacterController.hpp"
2+ #include " ../../Logging/Exception.hpp"
23#include < characterkinematic/PxControllerManager.h>
34#include < characterkinematic/PxController.h>
45#include < characterkinematic/PxCapsuleController.h>
56#include < PxPhysics.h>
67#include < PxScene.h>
8+ #include < PxRigidDynamic.h>
9+ #include < PxMaterial.h>
10+ #include < geometry/PxGeometryQuery.h>
711
812using namespace Engine3DRadSpace ;
913using namespace Engine3DRadSpace ::Math;
@@ -26,9 +30,15 @@ CharacterController::CharacterController(
2630 desc.setToDefault ();
2731 desc.height = height;
2832 desc.radius = radius;
29- desc.slopeLimit = 0 .707f ; // 45 deg
33+ desc.slopeLimit = std::cos (_maxSlopeAngle);
34+ desc.material = nvPhysics->createMaterial (0 .5f , 0 .5f , 0 .0f );
35+ _material = PxUPtr<physx::PxMaterial>(desc.material );
3036
3137 auto controller = nvControllerManager->createController (desc);
38+ if (controller == nullptr )
39+ {
40+ throw Logging::Exception (" CharacterController creation failed!" );
41+ }
3242 _controller.reset (static_cast <physx::PxCapsuleController*>(controller));
3343
3444 auto scene = static_cast <physx::PxScene*>(physics->GetScene ());
@@ -96,7 +106,7 @@ void CharacterController::Move(const Math::Vector3& displacement)
96106
97107 _verticalVelocity += Gravity.Get () * dt;
98108
99- if (IsGrounded () && _verticalVelocity. Y < = 0 .0f )
109+ if (IsGrounded () && Vector3::Dot ( _verticalVelocity, _gravity) > = 0 .0f )
100110 _verticalVelocity = Vector3::Zero ();
101111
102112 physx::PxVec3 motion =
@@ -105,18 +115,22 @@ void CharacterController::Move(const Math::Vector3& displacement)
105115 _controller->move (
106116 motion,
107117 0 .001f ,
108- _physics-> dt () ,
118+ dt ,
109119 physx::PxControllerFilters (),
110120 nullptr
111121 );
112122}
113123
114124void CharacterController::Jump (float height)
115125{
116- if (!IsGrounded ()) return ;
126+ if (!IsGrounded () || height <= 0 . 0f ) return ;
117127
118128 float g = _gravity.Length ();
119- _verticalVelocity = Vector3 (0 , std::sqrt (2 .0f * g * height), 0 );
129+ if (g == 0 .0f ) return ;
130+
131+ // Conservation of energy: (1/2)m(v^2) = mgh -> v = sqrt(2gh)
132+ float speed = std::sqrt (2 .0f * g * height);
133+ _verticalVelocity = Vector3::Normalize (-_gravity) * speed;
120134}
121135
122136bool CharacterController::IsGrounded ()
@@ -126,6 +140,11 @@ bool CharacterController::IsGrounded()
126140 physx::PxControllerState state;
127141 _controller->getState (state);
128142
143+ if ((state.collisionFlags & physx::PxControllerCollisionFlag::eCOLLISION_UP) != 0 )
144+ {
145+ _verticalVelocity = Vector3::Zero ();
146+ }
147+
129148 return (state.collisionFlags & physx::PxControllerCollisionFlag::eCOLLISION_DOWN) != 0 ;
130149 }
131150
@@ -139,12 +158,51 @@ float CharacterController::_getMass()
139158
140159void CharacterController::_setMass (float mass)
141160{
142- // Do nothing, character controller doesn't have mass
161+ ( void ) mass;
143162}
144163
145164std::optional<float > CharacterController::Intersects (const Math::Ray& r)
146165{
147- return std::nullopt ;
166+ if (_controller == nullptr ) return std::nullopt ;
167+
168+ physx::PxVec3 origin (r.Origin .X , r.Origin .Y , r.Origin .Z );
169+ physx::PxVec3 dir (r.Direction .X , r.Direction .Y , r.Direction .Z );
170+
171+ if (dir.normalize () == 0 .0f ) return std::nullopt ;
172+
173+ auto numShapes = _controller->getActor ()->getNbShapes ();
174+ if (numShapes == 0 ) return std::nullopt ;
175+
176+ std::vector<physx::PxShape*> shapes (numShapes);
177+ auto rigidbody = _controller->getActor ();
178+ rigidbody->getShapes (shapes.data (), numShapes);
179+
180+ float closestDist = PX_MAX_F32 ;
181+ bool hasHit = false ;
182+
183+ for (auto * shape : shapes)
184+ {
185+ physx::PxTransform pose = rigidbody->getGlobalPose () * shape->getLocalPose ();
186+ physx::PxRaycastHit hit;
187+
188+ physx::PxU32 hitCount = physx::PxGeometryQuery::raycast (
189+ origin, dir,
190+ shape->getGeometry (),
191+ pose,
192+ PX_MAX_F32 ,
193+ physx::PxHitFlag::eDEFAULT,
194+ 1 ,
195+ &hit
196+ );
197+
198+ if (hitCount > 0 && hit.distance < closestDist)
199+ {
200+ closestDist = hit.distance ;
201+ hasHit = true ;
202+ }
203+ }
204+
205+ return hasHit ? std::optional<float >(closestDist) : std::nullopt ;
148206}
149207
150208void CharacterController::UpdateTransform ()
@@ -159,4 +217,12 @@ void CharacterController::UpdateTransform(const Math::Vector3& position, const M
159217{
160218 if (!_controller) return ;
161219 _controller->setPosition (physx::PxExtendedVec3 (position.X , position.Y , position.Z ));
220+
221+ Vector3 up = Vector3::Transform (Vector3::Up (), rotation);
222+ _controller->setUpDirection (physx::PxVec3 (up.X , up.Y , up.Z ));
223+ }
224+
225+ Math::Vector3 CharacterController::GetPosition () const noexcept
226+ {
227+ return _position;
162228}
0 commit comments