Add claude docs
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user