9#ifndef GLM_ENABLE_EXPERIMENTAL
10 #define GLM_ENABLE_EXPERIMENTAL 1
14#include <glm/gtc/matrix_transform.hpp>
15#include <glm/gtx/euler_angles.hpp>
16#include <glm/gtx/quaternion.hpp>
20#include <unordered_map>
25#include <components/GameComponents/CharacterComponent.hpp>
33 std::size_t operator()(
const JPH::BodyID&
id)
const {
34 return std::hash<uint32_t>{}(
id.GetIndexAndSequenceNumber());
42 unsigned int GetNumBroadPhaseLayers()
const override {
return 1; }
44 JPH::BroadPhaseLayer GetBroadPhaseLayer(JPH::ObjectLayer inLayer)
const override {
return JPH::BroadPhaseLayer(0); }
45#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
47 const char* GetBroadPhaseLayerName(JPH::BroadPhaseLayer inLayer)
const override {
return "Default"; }
55 bool ShouldCollide(JPH::ObjectLayer, JPH::BroadPhaseLayer)
const override {
return true; }
62 bool ShouldCollide(JPH::ObjectLayer, JPH::ObjectLayer)
const override {
return true; }
69 void OnBodyActivated(
const JPH::BodyID& inBodyID, JPH::uint64 inBodyUserData)
override {}
71 void OnBodyDeactivated(
const JPH::BodyID& inBodyID, JPH::uint64 inBodyUserData)
override {}
76 BOX, ROUNDED_BOX, SPHERE, CAPSULE, CYLINDER, CONVEX_HULL, MESH
81 STATIC, DYNAMIC, KINEMATIC, SENSOR
102 BodyType bodyType = BodyType::STATIC;
104 float friction = 0.5f;
106 uint8_t objectLayer = 0;
107 JPH::BodyID bodyId = JPH::BodyID(JPH::BodyID::cInvalidBodyID);
108 float linearDamping = 0.05f;
109 float angularDamping = 0.05f;
110 bool isSensor =
false;
111 bool allowSleeping =
true;
112 bool debugDraw =
true;
114 glm::vec3 boxHalfExtents = {0.5f, 0.5f, 0.5f};
115 float roundedRadius = 0.05f;
116 float sphereRadius = 0.5f;
117 float capsuleRadius = 0.5f;
118 float capsuleHeight = 1.0f;
119 float cylinderRadius = 0.5f;
120 float cylinderHeight = 1.0f;
121 std::vector<JPH::Vec3> convexPoints;
122 std::vector<glm::vec3> meshVertices;
123 std::vector<uint32_t> meshIndices;
131 bool updated =
false;
145 static PhysicsComponent Box(glm::vec3 halfExtents = {0.5f, 0.5f, 0.5f},
BodyType bodyType = BodyType::STATIC,
float mass = 1.0f,
float friction = 0.5f,
float bounce = 0.1f) {
147 pc.shape = ShapeType::BOX;
148 pc.boxHalfExtents = halfExtents;
150 pc.bodyType = bodyType;
151 pc.friction = friction;
163 static PhysicsComponent RoundedBox(glm::vec3 halfExtents,
float radius = 0.05f,
BodyType bodyType = BodyType::DYNAMIC,
float mass = 1.0f,
float friction = 0.5f,
float bounce = 0.1f) {
165 pc.shape = ShapeType::ROUNDED_BOX;
166 pc.boxHalfExtents = halfExtents;
167 pc.roundedRadius = radius;
169 pc.bodyType = bodyType;
170 pc.friction = friction;
183 pc.shape = ShapeType::SPHERE;
184 pc.sphereRadius = radius;
186 pc.bodyType = bodyType;
187 pc.friction = friction;
199 static PhysicsComponent Capsule(
float radius = 0.5f,
float height = 1.0f,
BodyType bodyType = BodyType::STATIC,
float mass = 1.0f,
float friction = 0.5f,
float bounce = 0.1f) {
201 pc.shape = ShapeType::CAPSULE;
202 pc.capsuleRadius = radius;
203 pc.capsuleHeight = height;
205 pc.bodyType = bodyType;
206 pc.friction = friction;
218 static PhysicsComponent Cylinder(
float radius = 0.5f,
float height = 1.0f,
BodyType bodyType = BodyType::STATIC,
float mass = 1.0f,
float friction = 0.5f,
float bounce = 0.1f) {
220 pc.shape = ShapeType::CYLINDER;
221 pc.cylinderRadius = radius;
222 pc.cylinderHeight = height;
224 pc.bodyType = bodyType;
225 pc.friction = friction;
238 pc.shape = ShapeType::CONVEX_HULL;
239 pc.convexPoints = points;
241 pc.bodyType = bodyType;
242 pc.friction = friction;
255 pc.shape = ShapeType::MESH;
256 pc.bodyType = bodyType;
258 pc.friction = friction;
260 if (!mesh.meshData.submeshes.empty()) {
261 pc.meshVertices.clear();
262 pc.meshIndices.clear();
264 size_t vertexOffset = 0;
266 for (
const auto& sm : mesh.meshData.submeshes) {
267 for (
const auto& v : sm.vertices) {
268 pc.meshVertices.push_back(v.position);
270 for (
auto idx : sm.indices) {
271 pc.meshIndices.push_back(
static_cast<uint32_t
>(idx + vertexOffset));
273 vertexOffset += sm.vertices.size();
282 onCollisionEnter = callback;
288 onCollisionStay = callback;
294 onCollisionExit = callback;
315 void drawDebug(
bool drawConstraints =
true,
bool drawWireframe =
true);
319 bool init(
size_t maxBodies = 1024);
326 void update(
float deltaTime);
334 m_physicsSystem->SetGravity(JPH::Vec3(gravity.x, gravity.y, gravity.z));
341 m_physicsSystem->GetBodyInterface().SetGravityFactor(bodyId, gravityFactor);
347 void SetFriction(JPH::BodyID bodyId,
float friction);
398 void AddTorque(JPH::BodyID bodyId,
const glm::vec3& torque);
403 void AddForce(JPH::BodyID bodyId,
const glm::vec3& force);
409 void AddForceAtPosition(JPH::BodyID bodyId,
const glm::vec3& force,
const glm::vec3& position);
414 void AddImpulse(JPH::BodyID bodyId,
const glm::vec3& impulse);
420 void AddImpulseAtPosition(JPH::BodyID bodyId,
const glm::vec3& impulse,
const glm::vec3& position);
460 bool raycast(
const glm::vec3& origin,
const glm::vec3& direction,
float maxDistance,
RaycastHit& hit);
497 int collisionSteps = 3;
498 bool enableSmoothing =
true;
500 JPH::TempAllocatorImpl* m_tempAllocator =
nullptr;
501 JPH::JobSystem* m_jobSystem =
nullptr;
502 JPH::PhysicsSystem* m_physicsSystem =
nullptr;
503 JPH::DebugRenderer* m_debugRenderer =
nullptr;
510 std::unique_ptr<MyActivationListener> m_activationListener;
511 std::unique_ptr<JPH::ContactListener> m_contactListener;
513 std::unordered_map<JPH::BodyID, vex::Entity, BodyIDHasher> m_bodyToEntity;
516 glm::vec3 prevPos = {0.0f, 0.0f, 0.0f};
517 glm::quat prevRot = {1.0f, 0.0f, 0.0f, 0.0f};
518 glm::vec3 currPos = {0.0f, 0.0f, 0.0f};
519 glm::quat currRot = {1.0f, 0.0f, 0.0f, 0.0f};
520 glm::vec3 lastVisualPos = {0.0f, 0.0f, 0.0f};
521 glm::quat lastVisualRot = {1.0f, 0.0f, 0.0f, 0.0f};
522 bool desynced =
false;
524 std::unordered_map<JPH::BodyID, InterpCache, BodyIDHasher> m_interpCache;
526 float m_fixedDt = 1.0f / 60.0f;
527 float m_accumulator = 0.0f;
532 static JPH::Quat EulerToQuat(
const glm::vec3& eulerDeg);
536 static glm::vec3 QuatToEuler(
const JPH::Quat& q);
561 void WeldVertices(
const std::vector<glm::vec3>& inVerts,
const std::vector<uint32_t>& inIndices,
562 JPH::VertexList& outVerts, JPH::IndexedTriangleList& outTris);
565 class MyContactListener :
public JPH::ContactListener {
567 MyContactListener(
PhysicsSystem& system) : m_system(system) {}
570 JPH::ValidateResult OnContactValidate(
const JPH::Body& inBody1,
const JPH::Body& inBody2, JPH::RVec3Arg inBaseOffset,
const JPH::CollideShapeResult& inCollisionResult)
override {
571 return JPH::ValidateResult::AcceptAllContactsForThisBodyPair;
579 void OnContactAdded(
const JPH::Body& inBody1,
const JPH::Body& inBody2,
const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings)
override;
585 void OnContactPersisted(
const JPH::Body& inBody1,
const JPH::Body& inBody2,
const JPH::ContactManifold& inManifold, JPH::ContactSettings& ioSettings)
override;
588 void OnContactRemoved(
const JPH::SubShapeIDPair& inSubShapePair)
override;
595 class DebugDrawFilter :
public JPH::BodyDrawFilter {
599 virtual bool ShouldDraw(
const JPH::Body& body)
const override {
600 auto& pc = m_system.getPhysicsComponentByBodyId(body.GetID());
Contains basic components like transform, camera, name components..
Main header for the Entity Component System (ECS) framework.
This file exist only because of coliding macros.
Implementation of JPH::BroadPhaseLayerInterface for the default layer.
Implementation of JPH::BodyActivationListener for the default layer.
Implementation of JPH::ObjectLayerPairFilter for the default layer.
Implementation of JPH::ObjectVsBroadPhaseLayerFilter for the default layer.
Class representing a physics system.
int GetCollisionSteps()
Allows for getting collision steps (collision accuracy).
void setEnableSmoothing(bool enable)
Allows for enabling/disabling smoothing.
void SetLinearVelocity(JPH::BodyID bodyId, const glm::vec3 &velocity)
Allows for updating linear velocity.
void SyncBodies()
Scans registry for PhysicsComponents without bodies and creates them.
void SetBodyActive(JPH::BodyID bodyId, bool active)
Allows for setting body active state.
void AddForceAtPosition(JPH::BodyID bodyId, const glm::vec3 &force, const glm::vec3 &position)
Applies force at the given position of the body, it is reset next physics tick.
void SetFriction(JPH::BodyID bodyId, float friction)
Allows for updating friction.
PhysicsSystem(vex::Registry ®istry)
Constructor, initializes physics system.
float GetFriction(JPH::BodyID bodyId)
Allows for getting friction.
void AddLinearVelocity(JPH::BodyID bodyId, const glm::vec3 &velocity)
Allows for adding to linear velocity.
void setDebugRenderer(JPH::DebugRenderer *renderer)
Sets the debug renderer for the physics system.
bool raycast(const glm::vec3 &origin, const glm::vec3 &direction, float maxDistance, RaycastHit &hit)
Performs a raycast in the physics world.
void WeldVertices(const std::vector< glm::vec3 > &inVerts, const std::vector< uint32_t > &inIndices, JPH::VertexList &outVerts, JPH::IndexedTriangleList &outTris)
Helper to weld vertices based on position ONLY (ignoring UVs/Normals which split render meshes).
void update(float deltaTime)
Updates physics, it is technically fixed time but needs delta to track if required time already passe...
void SetGravityVector(const glm::vec3 &gravity)
Allows for updating gravity.
void AddForce(JPH::BodyID bodyId, const glm::vec3 &force)
Applies force at the mass center of the body, it is reset next physics tick.
void AddAngularImpulse(JPH::BodyID bodyId, const glm::vec3 &impulse)
Applies angular impulse at the mass center of the body, it is reset next physics tick.
void AddTorque(JPH::BodyID bodyId, const glm::vec3 &torque)
Applies torque to the body, it is reset next physics tick.
void AddAngularVelocity(JPH::BodyID bodyId, const glm::vec3 &velocity)
Allows for adding to angular velocity.
void AddImpulse(JPH::BodyID bodyId, const glm::vec3 &impulse)
Applies impulse at the mass center of the body, it is reset next physics tick.
void shutdown()
clears all physics objects
void SetAngularVelocity(JPH::BodyID bodyId, const glm::vec3 &velocity)
Allows for setting angular velocity.
glm::vec3 GetPhysicsPosition(JPH::BodyID bodyId)
Retrieves the physics position of a body.
glm::vec3 GetLinearVelocity(JPH::BodyID bodyId)
Allows for getting linear velocity.
std::optional< JPH::BodyID > CreateBodyForEntity(vex::Entity e, vex::Registry &r, PhysicsComponent &pc)
Allows to recreate physics body at runtime.
std::optional< JPH::BodyID > RecreateBodyForEntity(vex::Entity e, PhysicsComponent &pc)
Allows to recreate physics body at runtime.
bool init(size_t maxBodies=1024)
Initializes jolts physics system.
void AddImpulseAtPosition(JPH::BodyID bodyId, const glm::vec3 &impulse, const glm::vec3 &position)
Applies impulse at the given position of the body, it is reset next physics tick.
void drawDebug(bool drawConstraints=true, bool drawWireframe=true)
Draws debug information for the physics system.
void DestroyBodyForEntity(PhysicsComponent &pc)
Destroys a physics body.
void SetBounciness(JPH::BodyID bodyId, float bounciness)
Allows for updating bounciness.
glm::vec3 GetAngularVelocity(JPH::BodyID bodyId)
Allows for getting angular velocity.
void setCollisionSteps(int steps)
Allows for setting collision steps (collision accuracy).
bool GetBodyActive(JPH::BodyID bodyId)
Allows for getting body active state.
glm::vec3 GetVelocityAtPosition(JPH::BodyID bodyId, const glm::vec3 &point)
Gets the velocity of a specific point on the body (in World Space).
~PhysicsSystem()
Destructor, simply calls shutdown().
void SetGravityFactor(JPH::BodyID bodyId, float gravityFactor)
Allows for updating gravity factor per object.
glm::quat GetPhysicsRotation(JPH::BodyID bodyId)
Retrieves the physics rotation of a body.
float GetBounciness(JPH::BodyID bodyId)
Allows for getting bounciness.
Central registry for managing entities and their components in the ECS system.
uint32_t Entity
Type alias representing a unique entity identifier in the ECS system.
BodyType
Enumeration of available body types for physics components.
ShapeType
Enumeration of available shape types for physics components.
Character component for player or NPC characters.
Structure representing a collision hit.
Struct containing raw meshData, mesh id, texture paths and material properties. It just template and ...
Structure representing a physics component.
void addCollisionExitBinding(std::function< void(vex::Entity, vex::Entity)> callback)
Binds a callback for collision exit events.
static PhysicsComponent Mesh(MeshComponent &mesh, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a mesh-shaped physics component.
static PhysicsComponent Cylinder(float radius=0.5f, float height=1.0f, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a cylinder-shaped physics component.
PhysicsComponent()=default
— Constructors —
static PhysicsComponent Box(glm::vec3 halfExtents={0.5f, 0.5f, 0.5f}, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a box-shaped physics component.
void addCollisionStayBinding(std::function< void(vex::Entity, vex::Entity, const CollisionHit &)> callback)
Binds a callback for collision stay events.
void addCollisionEnterBinding(std::function< void(vex::Entity, vex::Entity, const CollisionHit &)> callback)
Binds a callback for collision enter events.
static PhysicsComponent ConvexHull(std::vector< JPH::Vec3 > points, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a convex hull-shaped physics component.
static PhysicsComponent Sphere(float radius=0.5f, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a sphere-shaped physics component.
static PhysicsComponent Capsule(float radius=0.5f, float height=1.0f, BodyType bodyType=BodyType::STATIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a capsule-shaped physics component.
static PhysicsComponent RoundedBox(glm::vec3 halfExtents, float radius=0.05f, BodyType bodyType=BodyType::DYNAMIC, float mass=1.0f, float friction=0.5f, float bounce=0.1f)
Creates a rounded box.
Structure representing a raycast hit.