Add claude docs

This commit is contained in:
2026-06-16 10:15:59 -05:00
parent 8131bcd4d4
commit ed5c60ac30
32 changed files with 3781 additions and 13 deletions
+127
View File
@@ -0,0 +1,127 @@
# Physics System
Source: `src/dusk/physics/`, entity component at
`src/dusk/entity/component/physics/entityphysics.h/.c`
## Overview
Dusk uses a lightweight, custom 3D physics simulation with no external
library dependency. It is integrated with the ECS: only entities that
have both a `COMPONENT_TYPE_PHYSICS` and a `COMPONENT_TYPE_POSITION`
component participate in the simulation.
## Shapes
```c
typedef enum {
PHYSICS_SHAPE_CUBE, // Axis-aligned bounding box (AABB)
PHYSICS_SHAPE_SPHERE,
PHYSICS_SHAPE_CAPSULE, // Y-axis aligned; radius + halfHeight
PHYSICS_SHAPE_PLANE, // Infinite plane; normal + distance
} physicshapetype_t;
```
All shape pairs are supported by the collision dispatch
(`physicsTestShapeVsShape`). See `physicstest.h` for the individual
test functions.
## Body types
```c
typedef enum {
PHYSICS_BODY_STATIC, // Never moves; immovable collision surface
PHYSICS_BODY_DYNAMIC, // Driven by gravity, velocity, collisions
PHYSICS_BODY_KINEMATIC, // Moved programmatically; collides but not
// driven by the simulation (e.g. player)
} physicsbodytype_t;
```
## World and gravity
```c
extern physicsworld_t PHYSICS_WORLD;
// PHYSICS_WORLD.gravity -- default {0, -9.81, 0}
```
The simulation step is driven by `physicsManagerUpdate()`, which is
called each fixed-timestep game loop tick. It skips dynamic-timestep
sub-steps (`DUSK_TIME_DYNAMIC`).
## Simulation phases (each step)
1. **Integrate dynamics** -- apply gravity scaled by `gravityScale`,
advance velocity, update position.
2. **Dynamic vs static/kinematic** -- resolve penetration and cancel
the normal velocity component.
3. **Dynamic vs dynamic** -- split penetration 50/50; exchange
relative normal velocity.
4. **Rebuild transforms** -- call `entityPositionRebuild()` for all
affected dynamic bodies.
`PHYSICS_GROUND_THRESHOLD = 0.707f` -- a collision normal with a Y
component above this value sets `onGround = true` on the dynamic body.
## Entity component (`entityphysics_t`)
```c
typedef struct {
physicsbodytype_t type;
physicsshape_t shape;
vec3 velocity;
float_t gravityScale; // default 1.0
bool_t onGround; // set by the solver each step
} entityphysics_t;
```
Default on init: DYNAMIC body, 0.5m half-extents AABB cube,
`gravityScale = 1.0f`.
### Component API
```c
entityphysics_t *entityPhysicsGet(entityid_t, componentid_t);
void entityPhysicsSetShape(entityid_t, componentid_t, physicsshape_t);
physicsshape_t entityPhysicsGetShape(entityid_t, componentid_t);
void entityPhysicsSetVelocity(entityid_t, componentid_t, vec3);
void entityPhysicsGetVelocity(entityid_t, componentid_t, vec3 dest);
void entityPhysicsApplyImpulse(entityid_t, componentid_t, vec3);
// No-op on STATIC bodies.
bool_t entityPhysicsIsOnGround(entityid_t, componentid_t);
void entityPhysicsSetBodyType(entityid_t, componentid_t, physicsbodytype_t);
physicsbodytype_t entityPhysicsGetBodyType(entityid_t, componentid_t);
```
## Collision detection primitives (`physicstest.h`)
Each function returns `true` if overlapping and writes the push-out
normal (pointing from B toward A) and penetration depth.
| Function | Shapes |
|----------|--------|
| `physicsTestAabbVsAabb` | CUBE vs CUBE |
| `physicsTestSphereVsSphere` | SPHERE vs SPHERE |
| `physicsTestSphereVsAabb` | SPHERE vs CUBE |
| `physicsTestSphereVsPlane` | SPHERE vs PLANE |
| `physicsTestAabbVsPlane` | CUBE vs PLANE |
| `physicsTestCapsuleVsSphere` | CAPSULE vs SPHERE |
| `physicsTestCapsuleVsAabb` | CAPSULE vs CUBE |
| `physicsTestCapsuleVsPlane` | CAPSULE vs PLANE |
| `physicsTestCapsuleVsCapsule` | CAPSULE vs CAPSULE |
| `physicsTestShapeVsShape` | Any pair via dispatch |
Capsules are always Y-axis aligned. Planes are infinite (not half-spaces).
## Limitations and known gaps
- No rotation simulation -- bodies do not rotate from collisions.
- No friction or damping model yet.
- No sleeping / deactivation for resting bodies.
- No broad-phase culling: the solver is O(n^2) per phase.
This is acceptable up to the ECS entity limit (64 entities) but must
be revisited if the entity count grows.
- Capsule vs plane uses the bottom/top hemisphere centers as a
degenerate approximation -- accurate for large planes but
not for thin surfaces.