|
SleakEngine 1.0.0
C++23 multi-backend game engine
|
This page describes the rigid-body physics simulation and the broadphase spatial structure in SleakEngine.
| Type | Role |
|---|---|
| Sleak::Physics::PhysicsWorld | Owns the collider list and the broadphase tree; stepped once per frame. |
| Sleak::Physics::DynamicAABBTree | Self-balancing AABB tree used as the broadphase and for queries. |
| Sleak::ColliderComponent | Attaches a shape to a GameObject and registers it with the world. |
| Sleak::RigidbodyComponent | Velocity, gravity, mass, and collision-normal bookkeeping. |
| Sleak::Physics::ColliderShape | std::variant over AABB, BoundingSphere, BoundingCapsule, TriangleMesh. |
| Sleak::Physics::CollisionManifold | Narrow-phase result: contact point, normal, penetration. |
| Sleak::Physics::RayHit / SweepResult | Query results from Raycast and SphereSweep. |
One Step call integrates, refits the tree, then resolves every overlapping pair inline. There is no separate solver iteration and no contact cache.
Sleak::Physics::PhysicsWorld (include/public/Physics/PhysicsWorld.hpp) is stepped once per frame from SceneBase::Update(deltaTime), using the variable frame delta time. It is not on the engine's fixed-timestep path; SceneBase::FixedUpdate exists and is driven by a real accumulator in Application::Run() (see Rendering Pipeline), but PhysicsWorld does not use it.
PhysicsWorld::Step integrates gravity and linear velocity into position for BodyType::Dynamic bodies, with grounded-state tracking and a terminal velocity clamp. There is no angular velocity and no damping anywhere in the physics code.
There is no collision enter/stay/exit callback system. Collision response is resolved inline: PhysicsWorld::FindPairsAndResolve calls RigidbodyComponent::ResolveCollision(normal, penetration) directly on overlapping pairs. ColliderComponent::IsTrigger() skips physical resolution between two triggers, but nothing fires an event when that happens. PhysicsWorld::Raycast(origin, direction, maxDist, layerMask) returns a RayHit struct; it is implemented as a small-radius sphere sweep, not by exposing a raycast callback.
PhysicsWorld is a small, general-purpose system; in SleakCraft it is used narrowly to track the player camera's grounded/collision state. World collision against voxel geometry is handled by a separate system, VoxelQueries::ResolveVoxelCollision, and does not go through PhysicsWorld at all.
Sleak::Physics::DynamicAABBTree (include/public/Physics/DynamicAABBTree.hpp) is a genuinely self-balancing tree: Balance(nodeId) computes a height-difference balance factor and performs AVL-style rotations with AABB and height refit after every insert or remove. Proxy AABBs are fattened by a fixed margin (FAT_AABB_MARGIN = 0.1f) via AABB::Fatten(), and MoveProxy extends the fat box toward the direction of travel, skipping re-insertion when the new AABB is still contained in the old one.
Both callbacks receive a proxy id (int), not a collider pointer, and return bool to continue or stop traversal.
The tree is not used for frustum culling; the culling system has no reference to it and is a separate CPU software-occlusion system. DynamicAABBTree usage is confined to include/public/Physics/ and src/Physics/.
Sleak::RigidbodyComponent (include/public/Physics/RigidbodyComponent.hpp) holds a BodyType (Static, Kinematic, Dynamic), Vector3D m_velocity, Vector3D m_gravity (default (0, -9.81, 0)), bool m_useGravity, float m_mass (default 1.0), float m_terminalVelocity (default 50.0), and ground/wall collision-normal bookkeeping. There is no friction field, no restitution field, and no angular velocity field.
Sleak::ColliderComponent (include/public/Physics/ColliderComponent.hpp) is a concrete Component, not an abstract base with per-shape subclasses. It holds a Physics::ColliderShape, defined as std::variant<AABB, BoundingSphere, BoundingCapsule, TriangleMesh> (include/public/Physics/Colliders.hpp), selected through constructor overloads or a ColliderType enum. There are no BoxCollider, SphereCollider, or CapsuleCollider classes; the real shape types are Physics::AABB, Physics::BoundingSphere, Physics::BoundingCapsule (a genuine cylinder-plus-hemispherical-caps shape, suitable for character controllers), and Physics::TriangleMesh.
Physics::AABB is a distinct type from Sleak::Math::AABB (include/public/Math/AABB.hpp); the physics variant additionally carries Fatten(), GetSurfaceArea(), and Merge() for use as the broadphase and collision shape. The two also spell their accessors differently (Physics::AABB::GetCenter() against Math::AABB::Center()), so a mix-up shows up as a compile error rather than silently wrong math.
Beyond Step, PhysicsWorld answers four spatial queries against everything registered with RegisterCollider:
Every query takes a layer mask and tests it against each collider's own layer, so a query can ignore whole categories of geometry. The overlap queries return CollisionPair values carrying the full manifold, not just the collider pointer, so a caller can act on the contact normal without running the narrow phase again.
Colliders register themselves with the scene's world through ColliderComponent, so a query sees an object as soon as its collider component initializes and stops seeing it once the component is removed.
| Question | File |
|---|---|
| The step order and query implementations | src/Physics/PhysicsWorld.cpp |
| Tree insertion, removal, and AVL balancing | src/Physics/DynamicAABBTree.cpp |
| Shape definitions and the world-AABB helper | include/public/Physics/Colliders.hpp |
| Every shape-versus-shape test | include/public/Physics/CollisionDetection.hpp |
| How a collision changes velocity | src/Physics/RigidbodyComponent.cpp |
| Where the world gets stepped | src/Scene/SceneBase.cpp |