The Pyramid Engine's Physics System provides realistic physics simulation for games and interactive applications. The system is designed to be modular, high-performance, and easy to integrate with the game world.
Note: The Physics System is currently in development. This documentation represents the planned API and architecture.
- Rigid Body Dynamics: 3D rigid body simulation with realistic physics
- Collision Detection: Efficient collision detection with multiple primitive types
- Collision Response: Realistic collision response and physics integration
- Constraints and Joints: Springs, hinges, sliders, and custom constraints
- Force System: Gravity, friction, drag, and custom force applications
- Particle System: Large-scale particle simulation for effects
- Soft Body Physics: Cloth, fluid, and deformable object simulation
- Character Controller: Specialized controller for character movement
- Trigger Volumes: Non-physical volumes for game logic triggers
- Raycasting: High-performance ray queries for gameplay mechanics
- Multi-Threading: Parallel physics simulation for performance
The main physics simulation world:
class PhysicsWorld {
public:
PhysicsWorld();
~PhysicsWorld();
// World management
bool Initialize(const PhysicsConfig& config);
void Shutdown();
void Step(float deltaTime);
// Rigid body management
RigidBodyID CreateRigidBody(const RigidBodyDesc& desc);
void DestroyRigidBody(RigidBodyID bodyId);
RigidBody* GetRigidBody(RigidBodyID bodyId);
// Collision shape management
CollisionShapeID CreateBoxShape(const Math::Vec3& halfExtents);
CollisionShapeID CreateSphereShape(float radius);
CollisionShapeID CreateCapsuleShape(float radius, float height);
CollisionShapeID CreateMeshShape(const Mesh& mesh);
void DestroyCollisionShape(CollisionShapeID shapeId);
// World properties
void SetGravity(const Math::Vec3& gravity);
Math::Vec3 GetGravity() const;
// Queries
bool Raycast(const Math::Vec3& origin, const Math::Vec3& direction,
float maxDistance, RaycastHit& hit);
std::vector<RigidBodyID> QuerySphere(const Math::Vec3& center, float radius);
std::vector<RigidBodyID> QueryBox(const Math::Vec3& center, const Math::Vec3& halfExtents);
// Force application
void ApplyForce(RigidBodyID bodyId, const Math::Vec3& force);
void ApplyForceAtPosition(RigidBodyID bodyId, const Math::Vec3& force, const Math::Vec3& position);
void ApplyTorque(RigidBodyID bodyId, const Math::Vec3& torque);
void ApplyImpulse(RigidBodyID bodyId, const Math::Vec3& impulse);
// Constraints and joints
ConstraintID CreateConstraint(const ConstraintDesc& desc);
void DestroyConstraint(ConstraintID constraintId);
// Collision callbacks
void SetCollisionCallback(CollisionCallback callback);
void SetTriggerCallback(TriggerCallback callback);
private:
std::unique_ptr<PhysicsWorldImpl> m_impl;
};Individual physics rigid body:
class RigidBody {
public:
// Transform
void SetPosition(const Math::Vec3& position);
Math::Vec3 GetPosition() const;
void SetRotation(const Math::Quat& rotation);
Math::Quat GetRotation() const;
void SetTransform(const Math::Vec3& position, const Math::Quat& rotation);
// Physics properties
void SetMass(float mass);
float GetMass() const;
void SetInertia(const Math::Vec3& inertia);
Math::Vec3 GetInertia() const;
// Motion
void SetLinearVelocity(const Math::Vec3& velocity);
Math::Vec3 GetLinearVelocity() const;
void SetAngularVelocity(const Math::Vec3& velocity);
Math::Vec3 GetAngularVelocity() const;
// Material properties
void SetFriction(float friction);
float GetFriction() const;
void SetRestitution(float restitution);
float GetRestitution() const;
void SetDrag(float linearDrag, float angularDrag);
// State control
void SetKinematic(bool kinematic);
bool IsKinematic() const;
void SetActive(bool active);
bool IsActive() const;
void SetSleeping(bool sleeping);
bool IsSleeping() const;
// Force application
void ApplyForce(const Math::Vec3& force);
void ApplyForceAtPosition(const Math::Vec3& force, const Math::Vec3& position);
void ApplyTorque(const Math::Vec3& torque);
void ApplyImpulse(const Math::Vec3& impulse);
void ApplyImpulseAtPosition(const Math::Vec3& impulse, const Math::Vec3& position);
// Collision shape
void SetCollisionShape(CollisionShapeID shapeId);
CollisionShapeID GetCollisionShape() const;
// User data
void SetUserData(void* userData);
void* GetUserData() const;
private:
RigidBodyID m_bodyId;
PhysicsWorld* m_world;
};Various collision shape types:
// Base collision shape
class CollisionShape {
public:
virtual ~CollisionShape() = default;
virtual CollisionShapeType GetType() const = 0;
virtual Math::Vec3 CalculateLocalInertia(float mass) const = 0;
};
// Box collision shape
class BoxShape : public CollisionShape {
public:
BoxShape(const Math::Vec3& halfExtents);
CollisionShapeType GetType() const override { return CollisionShapeType::Box; }
Math::Vec3 CalculateLocalInertia(float mass) const override;
Math::Vec3 GetHalfExtents() const { return m_halfExtents; }
private:
Math::Vec3 m_halfExtents;
};
// Sphere collision shape
class SphereShape : public CollisionShape {
public:
SphereShape(float radius);
CollisionShapeType GetType() const override { return CollisionShapeType::Sphere; }
Math::Vec3 CalculateLocalInertia(float mass) const override;
float GetRadius() const { return m_radius; }
private:
float m_radius;
};
// Capsule collision shape
class CapsuleShape : public CollisionShape {
public:
CapsuleShape(float radius, float height);
CollisionShapeType GetType() const override { return CollisionShapeType::Capsule; }
Math::Vec3 CalculateLocalInertia(float mass) const override;
float GetRadius() const { return m_radius; }
float GetHeight() const { return m_height; }
private:
float m_radius;
float m_height;
};
// Mesh collision shape
class MeshShape : public CollisionShape {
public:
MeshShape(const std::vector<Math::Vec3>& vertices, const std::vector<u32>& indices);
CollisionShapeType GetType() const override { return CollisionShapeType::Mesh; }
Math::Vec3 CalculateLocalInertia(float mass) const override;
private:
std::vector<Math::Vec3> m_vertices;
std::vector<u32> m_indices;
};// Base constraint class
class Constraint {
public:
virtual ~Constraint() = default;
virtual ConstraintType GetType() const = 0;
void SetBodyA(RigidBodyID bodyId) { m_bodyA = bodyId; }
void SetBodyB(RigidBodyID bodyId) { m_bodyB = bodyId; }
protected:
RigidBodyID m_bodyA = InvalidRigidBodyID;
RigidBodyID m_bodyB = InvalidRigidBodyID;
};
// Point-to-point constraint
class PointConstraint : public Constraint {
public:
PointConstraint(const Math::Vec3& anchorA, const Math::Vec3& anchorB);
ConstraintType GetType() const override { return ConstraintType::Point; }
void SetAnchorA(const Math::Vec3& anchor) { m_anchorA = anchor; }
void SetAnchorB(const Math::Vec3& anchor) { m_anchorB = anchor; }
private:
Math::Vec3 m_anchorA;
Math::Vec3 m_anchorB;
};
// Hinge constraint
class HingeConstraint : public Constraint {
public:
HingeConstraint(const Math::Vec3& pivotA, const Math::Vec3& pivotB,
const Math::Vec3& axisA, const Math::Vec3& axisB);
ConstraintType GetType() const override { return ConstraintType::Hinge; }
void SetLimits(float lowerLimit, float upperLimit);
void SetMotor(float targetVelocity, float maxMotorImpulse);
private:
Math::Vec3 m_pivotA, m_pivotB;
Math::Vec3 m_axisA, m_axisB;
float m_lowerLimit = -Math::Pi;
float m_upperLimit = Math::Pi;
};
// Spring constraint
class SpringConstraint : public Constraint {
public:
SpringConstraint(float restLength, float stiffness, float damping);
ConstraintType GetType() const override { return ConstraintType::Spring; }
void SetStiffness(float stiffness) { m_stiffness = stiffness; }
void SetDamping(float damping) { m_damping = damping; }
void SetRestLength(float length) { m_restLength = length; }
private:
float m_restLength;
float m_stiffness;
float m_damping;
};struct PhysicsConfig {
// Simulation settings
Math::Vec3 gravity = Math::Vec3(0.0f, -9.81f, 0.0f);
float timeStep = 1.0f / 60.0f; // 60 FPS
u32 maxSubSteps = 10;
u32 velocityIterations = 6;
u32 positionIterations = 2;
// World settings
Math::Vec3 worldMin = Math::Vec3(-1000.0f);
Math::Vec3 worldMax = Math::Vec3(1000.0f);
u32 maxRigidBodies = 10000;
u32 maxConstraints = 5000;
// Performance settings
bool enableMultiThreading = true;
u32 threadCount = 0; // 0 = auto-detect
bool enableContinuousCollisionDetection = true;
bool enableSleeping = true;
float sleepThreshold = 0.5f;
// Collision settings
u32 collisionMargin = 0.01f;
bool enableContactCache = true;
float contactBreakingThreshold = 0.02f;
};#include <Pyramid/Physics/PhysicsWorld.hpp>
// Initialize physics world
PhysicsConfig config;
config.gravity = Math::Vec3(0.0f, -9.81f, 0.0f);
config.enableMultiThreading = true;
PhysicsWorld physicsWorld;
if (!physicsWorld.Initialize(config)) {
PYRAMID_LOG_ERROR("Failed to initialize physics world");
return false;
}
// Create ground plane
RigidBodyDesc groundDesc;
groundDesc.type = RigidBodyType::Static;
groundDesc.position = Math::Vec3(0.0f, -1.0f, 0.0f);
auto groundShapeId = physicsWorld.CreateBoxShape(Math::Vec3(50.0f, 1.0f, 50.0f));
groundDesc.collisionShape = groundShapeId;
auto groundBodyId = physicsWorld.CreateRigidBody(groundDesc);
// Create falling box
RigidBodyDesc boxDesc;
boxDesc.type = RigidBodyType::Dynamic;
boxDesc.position = Math::Vec3(0.0f, 10.0f, 0.0f);
boxDesc.mass = 1.0f;
auto boxShapeId = physicsWorld.CreateBoxShape(Math::Vec3(0.5f, 0.5f, 0.5f));
boxDesc.collisionShape = boxShapeId;
auto boxBodyId = physicsWorld.CreateRigidBody(boxDesc);
auto* boxBody = physicsWorld.GetRigidBody(boxBodyId);
// Simulation loop
while (running) {
float deltaTime = GetDeltaTime();
// Step physics simulation
physicsWorld.Step(deltaTime);
// Get updated transform for rendering
Math::Vec3 position = boxBody->GetPosition();
Math::Quat rotation = boxBody->GetRotation();
// Update render transform
UpdateRenderObject(boxBodyId, position, rotation);
}class PhysicsCharacterController {
public:
bool Initialize(PhysicsWorld* world, const Math::Vec3& position) {
m_world = world;
// Create character capsule
auto capsuleShape = world->CreateCapsuleShape(0.4f, 1.8f);
RigidBodyDesc desc;
desc.type = RigidBodyType::Dynamic;
desc.position = position;
desc.mass = 70.0f; // 70kg character
desc.collisionShape = capsuleShape;
desc.lockRotation = true; // Prevent character from falling over
m_bodyId = world->CreateRigidBody(desc);
m_body = world->GetRigidBody(m_bodyId);
return m_body != nullptr;
}
void Move(const Math::Vec3& moveDirection, float speed, float deltaTime) {
if (!m_body) return;
// Apply movement force
Math::Vec3 force = moveDirection * speed * m_body->GetMass();
m_body->ApplyForce(force);
// Limit horizontal velocity to prevent infinite acceleration
Math::Vec3 velocity = m_body->GetLinearVelocity();
Math::Vec3 horizontalVel(velocity.x, 0.0f, velocity.z);
if (horizontalVel.Length() > speed) {
horizontalVel = horizontalVel.Normalized() * speed;
m_body->SetLinearVelocity(Math::Vec3(horizontalVel.x, velocity.y, horizontalVel.z));
}
}
void Jump(float jumpForce) {
if (!m_body || !IsGrounded()) return;
// Apply upward impulse
m_body->ApplyImpulse(Math::Vec3(0.0f, jumpForce, 0.0f));
}
bool IsGrounded() {
if (!m_world || !m_body) return false;
// Raycast downward to check for ground
Math::Vec3 position = m_body->GetPosition();
Math::Vec3 rayStart = position;
Math::Vec3 rayDirection = Math::Vec3(0.0f, -1.0f, 0.0f);
float rayDistance = 1.1f; // Slightly more than half character height
RaycastHit hit;
return m_world->Raycast(rayStart, rayDirection, rayDistance, hit);
}
Math::Vec3 GetPosition() const {
return m_body ? m_body->GetPosition() : Math::Vec3::Zero;
}
private:
PhysicsWorld* m_world = nullptr;
RigidBodyID m_bodyId = InvalidRigidBodyID;
RigidBody* m_body = nullptr;
};class PhysicsVehicle {
public:
bool Initialize(PhysicsWorld* world, const Math::Vec3& position) {
m_world = world;
// Create vehicle chassis
auto chassisShape = world->CreateBoxShape(Math::Vec3(2.0f, 0.5f, 4.0f));
RigidBodyDesc chassisDesc;
chassisDesc.type = RigidBodyType::Dynamic;
chassisDesc.position = position;
chassisDesc.mass = 1500.0f; // 1.5 ton vehicle
chassisDesc.collisionShape = chassisShape;
m_chassisId = world->CreateRigidBody(chassisDesc);
m_chassis = world->GetRigidBody(m_chassisId);
// Create wheels
CreateWheels();
return m_chassis != nullptr;
}
void SetThrottle(float throttle) {
m_throttle = Math::Clamp(throttle, -1.0f, 1.0f);
}
void SetSteering(float steering) {
m_steering = Math::Clamp(steering, -1.0f, 1.0f);
}
void Update(float deltaTime) {
if (!m_chassis) return;
// Apply engine force
Math::Vec3 forward = m_chassis->GetRotation() * Math::Vec3::Forward;
float engineForce = m_throttle * m_maxEngineForce;
m_chassis->ApplyForce(forward * engineForce);
// Apply steering torque
Math::Vec3 up = Math::Vec3::Up;
float steeringTorque = m_steering * m_maxSteeringTorque;
m_chassis->ApplyTorque(up * steeringTorque);
// Apply drag
Math::Vec3 velocity = m_chassis->GetLinearVelocity();
Math::Vec3 dragForce = -velocity * velocity.Length() * m_dragCoefficient;
m_chassis->ApplyForce(dragForce);
}
private:
void CreateWheels() {
// Wheel creation and constraints would be implemented here
// This would involve creating wheel rigid bodies and connecting them
// to the chassis with appropriate constraints
}
PhysicsWorld* m_world = nullptr;
RigidBodyID m_chassisId = InvalidRigidBodyID;
RigidBody* m_chassis = nullptr;
std::vector<RigidBodyID> m_wheelIds;
std::vector<ConstraintID> m_wheelConstraints;
float m_throttle = 0.0f;
float m_steering = 0.0f;
float m_maxEngineForce = 5000.0f;
float m_maxSteeringTorque = 1000.0f;
float m_dragCoefficient = 0.3f;
};class CollisionManager {
public:
void Initialize(PhysicsWorld* world) {
m_world = world;
// Set collision callbacks
world->SetCollisionCallback([this](const CollisionInfo& info) {
OnCollision(info);
});
world->SetTriggerCallback([this](const TriggerInfo& info) {
OnTrigger(info);
});
}
private:
void OnCollision(const CollisionInfo& info) {
// Get user data to identify game objects
void* userDataA = info.bodyA->GetUserData();
void* userDataB = info.bodyB->GetUserData();
GameObject* objA = static_cast<GameObject*>(userDataA);
GameObject* objB = static_cast<GameObject*>(userDataB);
if (objA && objB) {
// Handle collision between game objects
HandleCollision(objA, objB, info);
}
}
void OnTrigger(const TriggerInfo& info) {
void* userData = info.triggerBody->GetUserData();
void* otherData = info.otherBody->GetUserData();
TriggerVolume* trigger = static_cast<TriggerVolume*>(userData);
GameObject* other = static_cast<GameObject*>(otherData);
if (trigger && other) {
if (info.entering) {
trigger->OnEnter(other);
} else {
trigger->OnExit(other);
}
}
}
void HandleCollision(GameObject* objA, GameObject* objB, const CollisionInfo& info) {
// Example collision handling
if (objA->GetType() == GameObjectType::Player && objB->GetType() == GameObjectType::Enemy) {
// Player hit enemy
Player* player = static_cast<Player*>(objA);
Enemy* enemy = static_cast<Enemy*>(objB);
player->TakeDamage(enemy->GetContactDamage());
// Play collision sound
AudioManager::PlaySound("collision_sound.wav", info.contactPoint);
// Create particle effect
ParticleManager::CreateEffect("hit_sparks", info.contactPoint);
}
}
PhysicsWorld* m_world = nullptr;
};Current Status: Planning and Architecture Phase
- ✅ Architecture design
- ✅ API specification
- ✅ Integration planning with existing systems
- 🔄 Core physics engine research (Bullet Physics vs custom implementation)
- 🔄 Collision detection system design
- 🔄 Rigid body dynamics implementation
- ⏳ Collision shape implementations
- ⏳ Constraint and joint system
- ⏳ Character controller
- ⏳ Vehicle physics
- ⏳ Soft body physics
- ⏳ Multi-threading optimization
- ⏳ Performance profiling and optimization
- Spatial Partitioning: Octree or AABB tree for efficient collision culling
- Continuous Collision Detection: Prevent fast-moving objects from tunneling
- Contact Caching: Reuse collision information between frames
- Iterative Solvers: Configurable iteration counts for quality vs performance
- Island Solving: Solve disconnected object groups independently
- Sleeping: Disable simulation for stationary objects
- Object Pooling: Reuse physics objects to minimize allocations
- SOA Layout: Structure-of-Arrays for cache-friendly data access
- Memory Mapping: Efficient memory layout for SIMD operations
- Core Game Class - Main game loop integration
- Math Library - Vector and matrix operations
- Scene Management - Spatial organization
- Performance Profiling - Physics performance monitoring
- Fluid Simulation: Water and gas dynamics
- Destruction Physics: Breakable objects and fracturing
- Cloth Simulation: Realistic fabric and rope physics
- Physics Scripting: Lua/C# scripting for complex physics behaviors
- VR Physics: Specialized physics for virtual reality applications