@phalanx-engine/physics 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +437 -0
- package/dist/PhysicsWorld.d.ts +35 -0
- package/dist/PhysicsWorld.d.ts.map +1 -0
- package/dist/PhysicsWorld.js +112 -0
- package/dist/PhysicsWorldConfig.d.ts +21 -0
- package/dist/PhysicsWorldConfig.d.ts.map +1 -0
- package/dist/PhysicsWorldConfig.js +1 -0
- package/dist/collision/CollisionManifold.d.ts +9 -0
- package/dist/collision/CollisionManifold.d.ts.map +1 -0
- package/dist/collision/CollisionManifold.js +1 -0
- package/dist/collision/NarrowPhase.d.ts +8 -0
- package/dist/collision/NarrowPhase.d.ts.map +1 -0
- package/dist/collision/NarrowPhase.js +112 -0
- package/dist/collision/SpatialHashGrid.d.ts +19 -0
- package/dist/collision/SpatialHashGrid.d.ts.map +1 -0
- package/dist/collision/SpatialHashGrid.js +125 -0
- package/dist/collision/index.d.ts +4 -0
- package/dist/collision/index.d.ts.map +1 -0
- package/dist/collision/index.js +2 -0
- package/dist/components/InterpolationComponent.d.ts +15 -0
- package/dist/components/InterpolationComponent.d.ts.map +1 -0
- package/dist/components/InterpolationComponent.js +32 -0
- package/dist/components/PhysicsBodyComponent.d.ts +53 -0
- package/dist/components/PhysicsBodyComponent.d.ts.map +1 -0
- package/dist/components/PhysicsBodyComponent.js +157 -0
- package/dist/components/TransformComponent.d.ts +32 -0
- package/dist/components/TransformComponent.d.ts.map +1 -0
- package/dist/components/TransformComponent.js +75 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +3 -0
- package/dist/events.d.ts +7 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +6 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/systems/CollisionSystem.d.ts +20 -0
- package/dist/systems/CollisionSystem.d.ts.map +1 -0
- package/dist/systems/CollisionSystem.js +150 -0
- package/dist/systems/InterpolationSystem.d.ts +28 -0
- package/dist/systems/InterpolationSystem.d.ts.map +1 -0
- package/dist/systems/InterpolationSystem.js +104 -0
- package/dist/systems/PhysicsSystem.d.ts +41 -0
- package/dist/systems/PhysicsSystem.d.ts.map +1 -0
- package/dist/systems/PhysicsSystem.js +316 -0
- package/dist/systems/index.d.ts +5 -0
- package/dist/systems/index.d.ts.map +1 -0
- package/dist/systems/index.js +3 -0
- package/dist/tick/AutonomousPhysicsTickProvider.d.ts +18 -0
- package/dist/tick/AutonomousPhysicsTickProvider.d.ts.map +1 -0
- package/dist/tick/AutonomousPhysicsTickProvider.js +39 -0
- package/dist/tick/ExternalPhysicsTickProvider.d.ts +8 -0
- package/dist/tick/ExternalPhysicsTickProvider.d.ts.map +1 -0
- package/dist/tick/ExternalPhysicsTickProvider.js +6 -0
- package/dist/tick/IPhysicsTickProvider.d.ts +5 -0
- package/dist/tick/IPhysicsTickProvider.d.ts.map +1 -0
- package/dist/tick/IPhysicsTickProvider.js +1 -0
- package/dist/tick/index.d.ts +5 -0
- package/dist/tick/index.d.ts.map +1 -0
- package/dist/tick/index.js +2 -0
- package/dist/types.d.ts +37 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# Phalanx Physics
|
|
2
|
+
|
|
3
|
+
A deterministic, fixed-point physics engine for the [Phalanx Engine](../README.md). Designed for lockstep multiplayer games where every client must produce identical simulation results.
|
|
4
|
+
|
|
5
|
+
> Sibling packages: [phalanx-ecs](../phalanx-ecs/README.md) (ECS core), [phalanx-math](../phalanx-math/README.md) (fixed-point math), [phalanx-server](../phalanx-server/README.md), [phalanx-client](../phalanx-client/README.md).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Deterministic by Design**: All math uses `FP.*` fixed-point operations — no floating-point non-determinism
|
|
10
|
+
- **SoA Storage**: Physics body data stored in contiguous typed arrays (`BigInt64Array` for fixed-point, `Uint8Array` for flags) via phalanx-ecs `SoAComponent`
|
|
11
|
+
- **Spatial Hash Grid**: O(n) broad-phase collision detection with configurable cell size
|
|
12
|
+
- **Narrow Phase**: Circle vs Circle, Circle vs AABB, and AABB vs AABB collision tests
|
|
13
|
+
- **Impulse Resolution**: Mass-weighted velocity impulse + positional separation for overlap correction
|
|
14
|
+
- **Sub-stepping**: Configurable physics sub-steps per tick for higher fidelity at the same tick rate
|
|
15
|
+
- **Collision Filtering**: Inject game-specific collision rules via callback — no coupling to game concepts
|
|
16
|
+
- **Tick Providers**: Pluggable `IPhysicsTickProvider` interface decouples tick scheduling from simulation logic — supports GameWorld-driven, autonomous (turn-based), and external (rAF) modes
|
|
17
|
+
- **Impulse API**: `applyImpulse()` sets body velocity for flick/strike mechanics; `isSettled()` queries whether all bodies are at rest
|
|
18
|
+
- **Bounds Exit Mode**: Optional `ejectOnBoundsExit` mode marks out-of-bounds bodies as ignored and emits `BOUNDS_EXIT` events instead of clamping
|
|
19
|
+
- **Event-Driven**: Collision, trigger enter, trigger exit, and bounds exit events emitted via phalanx-ecs `EventBus`
|
|
20
|
+
- **Built-in Transform & Interpolation**: `TransformComponent` (SoA fixed-point spatial state), `InterpolationComponent`, and `InterpolationSystem` for tick-to-frame render smoothing
|
|
21
|
+
- **PhysicsWorld Facade**: One-liner setup — wraps PhysicsSystem + InterpolationSystem, exposes event subscriptions, spatial queries, and interpolated transforms
|
|
22
|
+
|
|
23
|
+
## Core Components
|
|
24
|
+
|
|
25
|
+
### PhysicsWorld (Recommended Entry Point)
|
|
26
|
+
- **PhysicsWorld**: High-level facade — creates PhysicsSystem and InterpolationSystem, wires collision pipeline, exposes event subscriptions, spatial queries, and `getInterpolatedTransform()`
|
|
27
|
+
|
|
28
|
+
### Transform & Interpolation
|
|
29
|
+
- **TransformComponent**: SoA-backed fixed-point position and rotation (`TransformSoASchema`, `TRANSFORM_COMPONENT_TYPE`)
|
|
30
|
+
- **InterpolationComponent**: Tick-to-tick transform samples for render smoothing
|
|
31
|
+
- **InterpolationSystem**: Snapshots/captures transform state each tick and interpolates each frame (implements `IBeforeTick`, `IAfterTick`, `IBeforeFrame`)
|
|
32
|
+
|
|
33
|
+
### Physics Body
|
|
34
|
+
- **PhysicsBodyComponent**: SoA-backed component with velocity, radius, mass, restitution, friction, isStatic, and ignorePhysics fields
|
|
35
|
+
- **PhysicsSoASchema**: Schema definition for the SoA storage layout
|
|
36
|
+
|
|
37
|
+
### Collision Detection
|
|
38
|
+
- **SpatialHashGrid**: Broad-phase spatial partitioning with `queryPairs()` and `queryRadius()`
|
|
39
|
+
- **NarrowPhase**: Static methods for precise collision geometry tests
|
|
40
|
+
|
|
41
|
+
### Systems
|
|
42
|
+
- **PhysicsSystem**: Velocity integration with sub-stepping, world bounds handling, broad/narrow/resolve collision pipeline, `step()` / `applyImpulse()` / `isSettled()` / `setCollisionFilter()` API. Created and owned by `PhysicsWorld`; retrieve it via `physicsWorld.getSystems().physicsSystem` to register with `GameWorld`.
|
|
43
|
+
- **InterpolationSystem**: Tick/frame lifecycle hooks for transform interpolation. Register as a **frame system** via `physicsWorld.getSystems().interpolationSystem`.
|
|
44
|
+
|
|
45
|
+
### Tick Providers
|
|
46
|
+
- **IPhysicsTickProvider**: Interface for custom tick scheduling strategies
|
|
47
|
+
- **AutonomousPhysicsTickProvider**: Runs physics loop via `setImmediate` (Node.js) or `setTimeout(0)` (browser) until settled or `maxSteps` reached — ideal for turn-based games
|
|
48
|
+
- **ExternalPhysicsTickProvider**: Delegates tick control to the caller (e.g. BabylonJS `onBeforeRenderObservable` or unit tests)
|
|
49
|
+
|
|
50
|
+
### Events
|
|
51
|
+
- **PhysicsEvents.COLLISION**: Emitted when two bodies collide
|
|
52
|
+
- **PhysicsEvents.TRIGGER_ENTER**: Emitted when a trigger overlap starts
|
|
53
|
+
- **PhysicsEvents.TRIGGER_EXIT**: Emitted when a trigger overlap ends
|
|
54
|
+
- **PhysicsEvents.BOUNDS_EXIT**: Emitted when a body exits `worldBounds` and `ejectOnBoundsExit` is `true`
|
|
55
|
+
|
|
56
|
+
## Installation
|
|
57
|
+
|
|
58
|
+
> ⚠️ **Not on npm yet** — clone the monorepo and install via pnpm.
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/phaeton-forge/phalanx-engine.git
|
|
62
|
+
cd phalanx-engine
|
|
63
|
+
pnpm install
|
|
64
|
+
pnpm --filter @phalanx-engine/physics build
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Peer dependencies: `@phalanx-engine/ecs` ^0.1.0, `@phalanx-engine/math` ^0.1.0
|
|
68
|
+
|
|
69
|
+
## Imports
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import {
|
|
73
|
+
// Facade & config
|
|
74
|
+
PhysicsWorld,
|
|
75
|
+
type PhysicsWorldConfig,
|
|
76
|
+
|
|
77
|
+
// Components
|
|
78
|
+
PhysicsBodyComponent,
|
|
79
|
+
PhysicsSoASchema,
|
|
80
|
+
PHYSICS_BODY_COMPONENT_TYPE,
|
|
81
|
+
TransformComponent,
|
|
82
|
+
TransformSoASchema,
|
|
83
|
+
TRANSFORM_COMPONENT_TYPE,
|
|
84
|
+
InterpolationComponent,
|
|
85
|
+
INTERPOLATION_COMPONENT_TYPE,
|
|
86
|
+
type PhysicsBodyConfig,
|
|
87
|
+
|
|
88
|
+
// Collision primitives
|
|
89
|
+
SpatialHashGrid,
|
|
90
|
+
NarrowPhase,
|
|
91
|
+
type CollisionManifold,
|
|
92
|
+
|
|
93
|
+
// Systems
|
|
94
|
+
PhysicsSystem,
|
|
95
|
+
InterpolationSystem,
|
|
96
|
+
type InterpolatedTransformSample,
|
|
97
|
+
|
|
98
|
+
// Events & event types
|
|
99
|
+
PhysicsEvents,
|
|
100
|
+
type CollisionEvent,
|
|
101
|
+
type BoundsExitEvent,
|
|
102
|
+
|
|
103
|
+
// Tick providers
|
|
104
|
+
type IPhysicsTickProvider,
|
|
105
|
+
AutonomousPhysicsTickProvider,
|
|
106
|
+
type AutonomousProviderOptions,
|
|
107
|
+
ExternalPhysicsTickProvider,
|
|
108
|
+
|
|
109
|
+
// Misc types
|
|
110
|
+
type CollisionFilter,
|
|
111
|
+
type PhysicsConfig,
|
|
112
|
+
} from '@phalanx-engine/physics';
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Quick Start
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { GameWorld, GameSystem, createComponentTypeRegistry } from '@phalanx-engine/ecs';
|
|
119
|
+
import {
|
|
120
|
+
PhysicsWorld,
|
|
121
|
+
PhysicsBodyComponent,
|
|
122
|
+
TransformComponent,
|
|
123
|
+
InterpolationComponent,
|
|
124
|
+
PHYSICS_BODY_COMPONENT_TYPE,
|
|
125
|
+
TRANSFORM_COMPONENT_TYPE,
|
|
126
|
+
INTERPOLATION_COMPONENT_TYPE,
|
|
127
|
+
} from '@phalanx-engine/physics';
|
|
128
|
+
import { FP, FPVector3 } from '@phalanx-engine/math';
|
|
129
|
+
|
|
130
|
+
// Register canonical component type symbols from phalanx-physics
|
|
131
|
+
export const ComponentType = createComponentTypeRegistry({
|
|
132
|
+
Transform: 'Transform',
|
|
133
|
+
Interpolation: 'Interpolation',
|
|
134
|
+
PhysicsBody: 'PhysicsBody',
|
|
135
|
+
});
|
|
136
|
+
(ComponentType as Record<string, symbol>).Transform = TRANSFORM_COMPONENT_TYPE;
|
|
137
|
+
(ComponentType as Record<string, symbol>).Interpolation = INTERPOLATION_COMPONENT_TYPE;
|
|
138
|
+
(ComponentType as Record<string, symbol>).PhysicsBody = PHYSICS_BODY_COMPONENT_TYPE;
|
|
139
|
+
|
|
140
|
+
// Minimal placeholder systems — replace with your real ones.
|
|
141
|
+
class MovementSystem extends GameSystem {
|
|
142
|
+
public override processTick(_tick: number): void { /* set velocities here */ }
|
|
143
|
+
}
|
|
144
|
+
class RenderSystem extends GameSystem {
|
|
145
|
+
public override update(_dt: number): void {
|
|
146
|
+
const sample = this.physics?.getInterpolatedTransform(entityId);
|
|
147
|
+
if (sample) mesh.position.set(sample.position.x, sample.position.y, sample.position.z);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const movementSystem = new MovementSystem();
|
|
151
|
+
const renderSystem = new RenderSystem();
|
|
152
|
+
|
|
153
|
+
// 1. Create GameWorld and the physics facade
|
|
154
|
+
const world = new GameWorld({ componentTypes: Object.values(ComponentType) });
|
|
155
|
+
|
|
156
|
+
const physicsWorld = new PhysicsWorld({
|
|
157
|
+
gridCellSize: FP.FromFloat(8),
|
|
158
|
+
subSteps: 3,
|
|
159
|
+
tickRate: 20,
|
|
160
|
+
maxVelocity: FP.FromFloat(15),
|
|
161
|
+
pushStrength: FP.FromFloat(15),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// 2. Wire physics into SystemContext so systems can access it
|
|
165
|
+
world.context.physics = physicsWorld;
|
|
166
|
+
|
|
167
|
+
// 3. Register systems with GameWorld (order matters)
|
|
168
|
+
const { physicsSystem, interpolationSystem } = physicsWorld.getSystems();
|
|
169
|
+
world.registerSystems(
|
|
170
|
+
[movementSystem, physicsSystem], // tick systems
|
|
171
|
+
[interpolationSystem, renderSystem], // frame systems — InterpolationSystem runs before render
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
world.start();
|
|
175
|
+
|
|
176
|
+
// 4. Add transform, interpolation, and physics body to entities
|
|
177
|
+
declare const entity: { id: number; addComponent(c: unknown): void };
|
|
178
|
+
const fpPosition = FPVector3.FromFloat(0, 0, 0);
|
|
179
|
+
entity.addComponent(new TransformComponent(entity.id, fpPosition));
|
|
180
|
+
entity.addComponent(new InterpolationComponent(fpPosition));
|
|
181
|
+
entity.addComponent(new PhysicsBodyComponent(entity.id, { radius: FP.FromFloat(1.0) }));
|
|
182
|
+
world.entityManager.addEntity(entity as any);
|
|
183
|
+
|
|
184
|
+
// 5. Subscribe to collision events (must be called after world.start())
|
|
185
|
+
physicsWorld.onCollision((event) => {
|
|
186
|
+
console.log(`Collision: ${event.entityA} ↔ ${event.entityB}`);
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
> **Note:** `PhysicsSystem` reads and writes the built-in `TransformSoASchema` store directly — no `setTransformStore()` or consumer-defined transform schema is required. Register `Transform`, `Interpolation`, and `PhysicsBody` component types using the canonical symbols exported from phalanx-physics.
|
|
191
|
+
|
|
192
|
+
## Turn-Based Physics (Tick Providers)
|
|
193
|
+
|
|
194
|
+
For turn-based games like Chapayev checkers, use a tick provider to decouple simulation from the server tick loop:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import {
|
|
198
|
+
PhysicsWorld,
|
|
199
|
+
AutonomousPhysicsTickProvider,
|
|
200
|
+
} from '@phalanx-engine/physics';
|
|
201
|
+
import { FP } from '@phalanx-engine/math';
|
|
202
|
+
|
|
203
|
+
// Game defines what "settled" means and what happens when it occurs
|
|
204
|
+
let physicsWorld: PhysicsWorld;
|
|
205
|
+
|
|
206
|
+
const provider = new AutonomousPhysicsTickProvider({
|
|
207
|
+
isSettled: () => physicsWorld.isSettled(),
|
|
208
|
+
onSettled: () => {
|
|
209
|
+
// Game-level logic: turn is over
|
|
210
|
+
sendTurnEnd(getCheckerPositions());
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
physicsWorld = new PhysicsWorld({
|
|
215
|
+
tickRate: 60,
|
|
216
|
+
subSteps: 3,
|
|
217
|
+
ejectOnBoundsExit: true,
|
|
218
|
+
worldBounds: {
|
|
219
|
+
minX: FP.FromFloat(-8), maxX: FP.FromFloat(8),
|
|
220
|
+
minZ: FP.FromFloat(-8), maxZ: FP.FromFloat(8),
|
|
221
|
+
},
|
|
222
|
+
tickProvider: provider,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// Player flicks a checker
|
|
226
|
+
function onFlick(entityId: number, dirX: number, dirZ: number, power: number) {
|
|
227
|
+
const speed = power * 12;
|
|
228
|
+
physicsWorld.applyImpulse(
|
|
229
|
+
entityId,
|
|
230
|
+
FP.FromFloat(dirX * speed),
|
|
231
|
+
FP.FromFloat(dirZ * speed),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Checker exits the board
|
|
236
|
+
physicsWorld.onBoundsExit(({ entityId }) => {
|
|
237
|
+
removeChecker(entityId);
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Tick Provider Options
|
|
242
|
+
|
|
243
|
+
| Provider | Use Case |
|
|
244
|
+
|---|---|
|
|
245
|
+
| *(none / default)* | GameWorld `processTick()` drives simulation — real-time games |
|
|
246
|
+
| `AutonomousPhysicsTickProvider` | Runs until settled or `maxSteps` — turn-based physics |
|
|
247
|
+
| `ExternalPhysicsTickProvider` | Caller invokes `tick()` manually — BabylonJS rAF, unit tests |
|
|
248
|
+
|
|
249
|
+
## API Reference
|
|
250
|
+
|
|
251
|
+
### `PhysicsWorld`
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
class PhysicsWorld {
|
|
255
|
+
constructor(config?: PhysicsWorldConfig);
|
|
256
|
+
|
|
257
|
+
// System wiring
|
|
258
|
+
getSystems(): { physicsSystem: PhysicsSystem; interpolationSystem: InterpolationSystem };
|
|
259
|
+
setCollisionFilter(filter: (entityA: number, entityB: number) => boolean): void;
|
|
260
|
+
|
|
261
|
+
// Event subscriptions (must be called after GameWorld.start())
|
|
262
|
+
onCollision(callback: (event: CollisionEvent) => void): () => void;
|
|
263
|
+
onBoundsExit(callback: (event: BoundsExitEvent) => void): () => void;
|
|
264
|
+
|
|
265
|
+
// Planned — not yet emitted by PhysicsSystem.
|
|
266
|
+
onTriggerEnter(callback: (event: CollisionEvent) => void): () => void;
|
|
267
|
+
onTriggerExit(callback: (event: CollisionEvent) => void): () => void;
|
|
268
|
+
|
|
269
|
+
// Impulse / settle queries
|
|
270
|
+
applyImpulse(entityId: number, vx: FixedPoint, vz: FixedPoint): void;
|
|
271
|
+
isSettled(threshold?: FixedPoint): boolean;
|
|
272
|
+
|
|
273
|
+
// Spatial / transform queries
|
|
274
|
+
readonly spatialGrid: SpatialHashGrid;
|
|
275
|
+
getEntityPosition(entityId: number): { x: FixedPoint; z: FixedPoint } | undefined;
|
|
276
|
+
getInterpolatedTransform(entityId: number): InterpolatedTransformSample | undefined;
|
|
277
|
+
|
|
278
|
+
// Cleanup
|
|
279
|
+
dispose(): void;
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- **`getSystems()`** — Returns both `physicsSystem` (register as tick system) and `interpolationSystem` (register as frame system).
|
|
284
|
+
- **`getEntityPosition(entityId)`** — Fixed-point position for gameplay queries (e.g. ability targeting).
|
|
285
|
+
- **`getInterpolatedTransform(entityId)`** — Interpolated float position/rotation for rendering, populated after `InterpolationSystem` runs.
|
|
286
|
+
|
|
287
|
+
- **`applyImpulse(entityId, vx, vz)`** — Set body velocity (replaces, does not accumulate). Re-enables previously ejected bodies.
|
|
288
|
+
- **`isSettled(threshold?)`** — Pure query: `true` when all non-static, non-ignored bodies are below velocity threshold (default from config, falling back to `FP.FromFloat(0.01)`).
|
|
289
|
+
- **`onBoundsExit(callback)`** — Subscribe to `BOUNDS_EXIT` events (requires `ejectOnBoundsExit: true`).
|
|
290
|
+
- **`setCollisionFilter(filter)`** — Inject a per-pair predicate. Return `false` to skip collision resolution for that pair.
|
|
291
|
+
|
|
292
|
+
### `PhysicsWorldConfig`
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
interface PhysicsWorldConfig {
|
|
296
|
+
gridCellSize?: FixedPoint; // default FP.FromFloat(4)
|
|
297
|
+
subSteps?: number; // default 3
|
|
298
|
+
tickRate?: number; // default 20 — used to compute tickDt
|
|
299
|
+
worldBounds?: { minX: FixedPoint; minZ: FixedPoint; maxX: FixedPoint; maxZ: FixedPoint };
|
|
300
|
+
defaultRestitution?: FixedPoint;
|
|
301
|
+
defaultFriction?: FixedPoint; // default FP.FromFloat(0.92)
|
|
302
|
+
maxVelocity?: FixedPoint; // default FP.FromFloat(15)
|
|
303
|
+
pushStrength?: FixedPoint; // default FP.FromFloat(15)
|
|
304
|
+
tickProvider?: IPhysicsTickProvider;
|
|
305
|
+
ejectOnBoundsExit?: boolean; // default false
|
|
306
|
+
settleThreshold?: FixedPoint; // default FP.FromFloat(0.01)
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### `TransformComponent`
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
class TransformComponent extends SoAComponent<typeof TransformSoASchema.definition> {
|
|
314
|
+
static readonly soaSchema: typeof TransformSoASchema;
|
|
315
|
+
readonly type: symbol; // TRANSFORM_COMPONENT_TYPE
|
|
316
|
+
|
|
317
|
+
constructor(entityId: number, initialPosition?: FPVector3, initialRotation?: FPVector3);
|
|
318
|
+
|
|
319
|
+
fpPosition: FPVector3; // get/set — authoritative fixed-point position
|
|
320
|
+
fpRotation: FPVector3; // get/set — authoritative fixed-point rotation (radians)
|
|
321
|
+
fpRotationY: FixedPoint; // get/set — convenience for Y-axis rotation
|
|
322
|
+
}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`TransformSoASchema` fields: `fpPositionX/Y/Z`, `fpRotationX/Y/Z` (all `i64`).
|
|
326
|
+
|
|
327
|
+
### `InterpolationComponent`
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
class InterpolationComponent implements IComponent {
|
|
331
|
+
readonly type: symbol; // INTERPOLATION_COMPONENT_TYPE
|
|
332
|
+
|
|
333
|
+
constructor(initialPosition?: FPVector3, initialRotation?: FPVector3);
|
|
334
|
+
|
|
335
|
+
snapshot(): void; // copy current → previous (called by InterpolationSystem before tick)
|
|
336
|
+
capture(fpPosition: FPVector3, fpRotation: FPVector3): void; // capture authoritative state after tick
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Attach alongside `TransformComponent` on any entity that needs render interpolation.
|
|
341
|
+
|
|
342
|
+
### `PhysicsBodyComponent`
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
class PhysicsBodyComponent extends SoAComponent<typeof PhysicsSoASchema.definition> {
|
|
346
|
+
static readonly soaSchema: typeof PhysicsSoASchema;
|
|
347
|
+
readonly type: symbol; // PHYSICS_BODY_COMPONENT_TYPE
|
|
348
|
+
|
|
349
|
+
constructor(entityId: number, config: PhysicsBodyConfig);
|
|
350
|
+
|
|
351
|
+
// Velocity
|
|
352
|
+
velocity: FPVector3; // get/set (returns cached object)
|
|
353
|
+
setVelocity(x: FixedPoint, y: FixedPoint, z: FixedPoint): void;
|
|
354
|
+
addVelocity(velocity: FPVector3): void;
|
|
355
|
+
stopVelocity(): void;
|
|
356
|
+
|
|
357
|
+
// Read-only attributes
|
|
358
|
+
readonly radius: FixedPoint;
|
|
359
|
+
readonly radiusFloat: number;
|
|
360
|
+
readonly mass: FixedPoint;
|
|
361
|
+
readonly restitution: FixedPoint;
|
|
362
|
+
readonly friction: FixedPoint;
|
|
363
|
+
readonly isStatic: boolean;
|
|
364
|
+
ignorePhysics: boolean; // get/set
|
|
365
|
+
|
|
366
|
+
// Spatial-grid bookkeeping
|
|
367
|
+
lastX: number;
|
|
368
|
+
lastZ: number;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
interface PhysicsBodyConfig {
|
|
372
|
+
radius: FixedPoint;
|
|
373
|
+
mass?: FixedPoint; // default FP._1
|
|
374
|
+
isStatic?: boolean; // default false
|
|
375
|
+
restitution?: FixedPoint; // default FP.FromFloat(0.5)
|
|
376
|
+
friction?: FixedPoint; // default FP._0
|
|
377
|
+
}
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
For hot-path access, prefer the SoA store directly:
|
|
381
|
+
|
|
382
|
+
```typescript
|
|
383
|
+
const store = entityManager.getOrCreateSoAStore(PhysicsSoASchema);
|
|
384
|
+
const idx = store.indexOf(entityId);
|
|
385
|
+
store.arrays.velocityX[idx] = FP.ToRaw(newVx);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Collision primitives
|
|
389
|
+
|
|
390
|
+
- **`SpatialHashGrid`** — broad-phase O(n) neighbor pairing. Methods: `clear()`, `insert(...)`, `queryPairs()`, `queryRadius(...)`. Access via `physicsWorld.spatialGrid` for ad-hoc range queries.
|
|
391
|
+
- **`NarrowPhase`** — static methods for circle/AABB intersection tests. Returns `CollisionManifold | null`.
|
|
392
|
+
- **`CollisionManifold`** — `{ entityA, entityB, normalX, normalZ, penetration }`.
|
|
393
|
+
|
|
394
|
+
### Tick providers
|
|
395
|
+
|
|
396
|
+
```typescript
|
|
397
|
+
interface IPhysicsTickProvider {
|
|
398
|
+
/** Start the provider; it calls `onStep` whenever physics should advance one step. */
|
|
399
|
+
start(onStep: () => void): void;
|
|
400
|
+
/** Stop the provider and release any timers/handles. */
|
|
401
|
+
stop(): void;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
interface AutonomousProviderOptions {
|
|
405
|
+
/** Called every step to decide whether to stop (defined by the game). */
|
|
406
|
+
isSettled: () => boolean;
|
|
407
|
+
/** Called once when simulation settles or `maxSteps` is reached. */
|
|
408
|
+
onSettled: () => void;
|
|
409
|
+
/** Max simulation steps before forcing a stop. Default: 10000. */
|
|
410
|
+
maxSteps?: number;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
class AutonomousPhysicsTickProvider implements IPhysicsTickProvider {
|
|
414
|
+
constructor(options: AutonomousProviderOptions);
|
|
415
|
+
// Schedules `onStep` via setImmediate (Node) or setTimeout(0) (browser)
|
|
416
|
+
// until isSettled() returns true or maxSteps is reached.
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
class ExternalPhysicsTickProvider implements IPhysicsTickProvider {
|
|
420
|
+
/** Manually advance one physics step from your render loop / test harness. */
|
|
421
|
+
tick(): void;
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Events
|
|
426
|
+
|
|
427
|
+
```typescript
|
|
428
|
+
const PhysicsEvents = {
|
|
429
|
+
COLLISION: 'physics:collision',
|
|
430
|
+
TRIGGER_ENTER: 'physics:trigger:enter',
|
|
431
|
+
TRIGGER_EXIT: 'physics:trigger:exit',
|
|
432
|
+
BOUNDS_EXIT: 'physics:bounds:exit',
|
|
433
|
+
} as const;
|
|
434
|
+
|
|
435
|
+
interface CollisionEvent { entityA: number; entityB: number; manifold: CollisionManifold; }
|
|
436
|
+
interface BoundsExitEvent { entityId: number; }
|
|
437
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { PhysicsSystem } from './systems/PhysicsSystem';
|
|
2
|
+
import { InterpolationSystem } from './systems/InterpolationSystem';
|
|
3
|
+
import type { InterpolatedTransformSample } from './systems/InterpolationSystem';
|
|
4
|
+
import { SpatialHashGrid } from './collision/SpatialHashGrid';
|
|
5
|
+
import type { PhysicsWorldConfig } from './PhysicsWorldConfig';
|
|
6
|
+
import type { FixedPoint } from '@phalanx-engine/math';
|
|
7
|
+
import type { CollisionEvent, BoundsExitEvent } from './types';
|
|
8
|
+
export declare class PhysicsWorld {
|
|
9
|
+
private readonly physicsSystem;
|
|
10
|
+
private readonly interpolationSystem;
|
|
11
|
+
private eventBusRef;
|
|
12
|
+
private readonly unsubscribers;
|
|
13
|
+
private readonly settleThreshold;
|
|
14
|
+
constructor(config?: PhysicsWorldConfig);
|
|
15
|
+
getSystems(): {
|
|
16
|
+
physicsSystem: PhysicsSystem;
|
|
17
|
+
interpolationSystem: InterpolationSystem;
|
|
18
|
+
};
|
|
19
|
+
setCollisionFilter(filter: (entityA: number, entityB: number) => boolean): void;
|
|
20
|
+
onCollision(callback: (event: CollisionEvent) => void): () => void;
|
|
21
|
+
onTriggerEnter(callback: (event: CollisionEvent) => void): () => void;
|
|
22
|
+
onTriggerExit(callback: (event: CollisionEvent) => void): () => void;
|
|
23
|
+
applyImpulse(entityId: number, vx: FixedPoint, vz: FixedPoint): void;
|
|
24
|
+
isSettled(threshold?: FixedPoint): boolean;
|
|
25
|
+
onBoundsExit(callback: (event: BoundsExitEvent) => void): () => void;
|
|
26
|
+
get spatialGrid(): SpatialHashGrid;
|
|
27
|
+
getEntityPosition(entityId: number): {
|
|
28
|
+
x: FixedPoint;
|
|
29
|
+
z: FixedPoint;
|
|
30
|
+
} | undefined;
|
|
31
|
+
getInterpolatedTransform(entityId: number): InterpolatedTransformSample | undefined;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
private getEventBus;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=PhysicsWorld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicsWorld.d.ts","sourceRoot":"","sources":["../src/PhysicsWorld.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,cAAc,EAAiB,eAAe,EAAE,MAAM,SAAS,CAAC;AAS9E,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAsB;IACpD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAyB;gBAE7C,MAAM,CAAC,EAAE,kBAAkB;IAgChC,UAAU,IAAI;QACnB,aAAa,EAAE,aAAa,CAAC;QAC7B,mBAAmB,EAAE,mBAAmB,CAAC;KAC1C;IAWM,kBAAkB,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,GAAG,IAAI;IAS/E,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI;IAalE,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI;IAarE,aAAa,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GAAG,MAAM,IAAI;IAWpE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,GAAG,IAAI;IAQpE,SAAS,CAAC,SAAS,CAAC,EAAE,UAAU,GAAG,OAAO;IAK1C,YAAY,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,GAAG,MAAM,IAAI;IAS3E,IAAW,WAAW,IAAI,eAAe,CAExC;IAKM,iBAAiB,CACtB,QAAQ,EAAE,MAAM,GACf;QAAE,CAAC,EAAE,UAAU,CAAC;QAAC,CAAC,EAAE,UAAU,CAAA;KAAE,GAAG,SAAS;IAQxC,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,2BAA2B,GAAG,SAAS;IAKnF,OAAO,IAAI,IAAI;IAOtB,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { FP } from '@phalanx-engine/math';
|
|
2
|
+
import { PhysicsSystem } from './systems/PhysicsSystem';
|
|
3
|
+
import { InterpolationSystem } from './systems/InterpolationSystem';
|
|
4
|
+
import { PhysicsEvents } from './events';
|
|
5
|
+
export class PhysicsWorld {
|
|
6
|
+
physicsSystem;
|
|
7
|
+
interpolationSystem;
|
|
8
|
+
eventBusRef = null;
|
|
9
|
+
unsubscribers = [];
|
|
10
|
+
settleThreshold;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
const tickRate = config?.tickRate ?? 20;
|
|
13
|
+
const subSteps = config?.subSteps ?? 3;
|
|
14
|
+
const tickDt = FP.FromFloat(1 / tickRate);
|
|
15
|
+
const gridCellSize = config?.gridCellSize ?? FP.FromFloat(4);
|
|
16
|
+
const maxVelocity = config?.maxVelocity ?? FP.FromFloat(15.0);
|
|
17
|
+
const pushStrength = config?.pushStrength ?? FP.FromFloat(15.0);
|
|
18
|
+
const defaultFriction = config?.defaultFriction ?? FP.FromFloat(0.92);
|
|
19
|
+
const physicsConfig = {
|
|
20
|
+
tickDt,
|
|
21
|
+
subSteps,
|
|
22
|
+
maxVelocity,
|
|
23
|
+
defaultFriction,
|
|
24
|
+
pushStrength,
|
|
25
|
+
gridCellSize,
|
|
26
|
+
worldBounds: config?.worldBounds,
|
|
27
|
+
ejectOnBoundsExit: config?.ejectOnBoundsExit,
|
|
28
|
+
};
|
|
29
|
+
this.physicsSystem = new PhysicsSystem(physicsConfig);
|
|
30
|
+
this.interpolationSystem = new InterpolationSystem();
|
|
31
|
+
this.settleThreshold = config?.settleThreshold;
|
|
32
|
+
if (config?.tickProvider) {
|
|
33
|
+
this.physicsSystem.setTickProvider(config.tickProvider);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getSystems() {
|
|
37
|
+
return {
|
|
38
|
+
physicsSystem: this.physicsSystem,
|
|
39
|
+
interpolationSystem: this.interpolationSystem,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
setCollisionFilter(filter) {
|
|
43
|
+
this.physicsSystem.setCollisionFilter(filter);
|
|
44
|
+
}
|
|
45
|
+
onCollision(callback) {
|
|
46
|
+
const eb = this.getEventBus();
|
|
47
|
+
if (!eb) {
|
|
48
|
+
throw new Error('PhysicsWorld: Cannot subscribe before systems are initialized');
|
|
49
|
+
}
|
|
50
|
+
const unsub = eb.on(PhysicsEvents.COLLISION, callback);
|
|
51
|
+
this.unsubscribers.push(unsub);
|
|
52
|
+
return unsub;
|
|
53
|
+
}
|
|
54
|
+
onTriggerEnter(callback) {
|
|
55
|
+
const eb = this.getEventBus();
|
|
56
|
+
if (!eb) {
|
|
57
|
+
throw new Error('PhysicsWorld: Cannot subscribe before systems are initialized');
|
|
58
|
+
}
|
|
59
|
+
const unsub = eb.on(PhysicsEvents.TRIGGER_ENTER, callback);
|
|
60
|
+
this.unsubscribers.push(unsub);
|
|
61
|
+
return unsub;
|
|
62
|
+
}
|
|
63
|
+
onTriggerExit(callback) {
|
|
64
|
+
const eb = this.getEventBus();
|
|
65
|
+
if (!eb) {
|
|
66
|
+
throw new Error('PhysicsWorld: Cannot subscribe before systems are initialized');
|
|
67
|
+
}
|
|
68
|
+
const unsub = eb.on(PhysicsEvents.TRIGGER_EXIT, callback);
|
|
69
|
+
this.unsubscribers.push(unsub);
|
|
70
|
+
return unsub;
|
|
71
|
+
}
|
|
72
|
+
applyImpulse(entityId, vx, vz) {
|
|
73
|
+
this.physicsSystem.applyImpulse(entityId, vx, vz);
|
|
74
|
+
}
|
|
75
|
+
isSettled(threshold) {
|
|
76
|
+
return this.physicsSystem.isSettled(threshold ?? this.settleThreshold);
|
|
77
|
+
}
|
|
78
|
+
onBoundsExit(callback) {
|
|
79
|
+
const eb = this.getEventBus();
|
|
80
|
+
if (!eb)
|
|
81
|
+
throw new Error('PhysicsWorld: Cannot subscribe before systems are initialized');
|
|
82
|
+
const unsub = eb.on(PhysicsEvents.BOUNDS_EXIT, callback);
|
|
83
|
+
this.unsubscribers.push(unsub);
|
|
84
|
+
return unsub;
|
|
85
|
+
}
|
|
86
|
+
get spatialGrid() {
|
|
87
|
+
return this.physicsSystem.getSpatialGrid();
|
|
88
|
+
}
|
|
89
|
+
getEntityPosition(entityId) {
|
|
90
|
+
return this.physicsSystem.getEntityPosition(entityId);
|
|
91
|
+
}
|
|
92
|
+
getInterpolatedTransform(entityId) {
|
|
93
|
+
return this.interpolationSystem.getInterpolatedTransform(entityId);
|
|
94
|
+
}
|
|
95
|
+
dispose() {
|
|
96
|
+
for (const unsub of this.unsubscribers) {
|
|
97
|
+
unsub();
|
|
98
|
+
}
|
|
99
|
+
this.unsubscribers.length = 0;
|
|
100
|
+
}
|
|
101
|
+
getEventBus() {
|
|
102
|
+
if (this.eventBusRef)
|
|
103
|
+
return this.eventBusRef;
|
|
104
|
+
try {
|
|
105
|
+
this.eventBusRef = this.physicsSystem.getEventBus() ?? null;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
return this.eventBusRef;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { FixedPoint } from '@phalanx-engine/math';
|
|
2
|
+
import type { IPhysicsTickProvider } from './tick/IPhysicsTickProvider';
|
|
3
|
+
export interface PhysicsWorldConfig {
|
|
4
|
+
gridCellSize?: FixedPoint;
|
|
5
|
+
subSteps?: number;
|
|
6
|
+
tickRate?: number;
|
|
7
|
+
worldBounds?: {
|
|
8
|
+
minX: FixedPoint;
|
|
9
|
+
minZ: FixedPoint;
|
|
10
|
+
maxX: FixedPoint;
|
|
11
|
+
maxZ: FixedPoint;
|
|
12
|
+
};
|
|
13
|
+
defaultRestitution?: FixedPoint;
|
|
14
|
+
defaultFriction?: FixedPoint;
|
|
15
|
+
maxVelocity?: FixedPoint;
|
|
16
|
+
pushStrength?: FixedPoint;
|
|
17
|
+
tickProvider?: IPhysicsTickProvider;
|
|
18
|
+
ejectOnBoundsExit?: boolean;
|
|
19
|
+
settleThreshold?: FixedPoint;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=PhysicsWorldConfig.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PhysicsWorldConfig.d.ts","sourceRoot":"","sources":["../src/PhysicsWorldConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAKxE,MAAM,WAAW,kBAAkB;IAEjC,YAAY,CAAC,EAAE,UAAU,CAAC;IAE1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;QACjB,IAAI,EAAE,UAAU,CAAC;KAClB,CAAC;IAEF,kBAAkB,CAAC,EAAE,UAAU,CAAC;IAEhC,eAAe,CAAC,EAAE,UAAU,CAAC;IAE7B,WAAW,CAAC,EAAE,UAAU,CAAC;IAEzB,YAAY,CAAC,EAAE,UAAU,CAAC;IAQ1B,YAAY,CAAC,EAAE,oBAAoB,CAAC;IAMpC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAO5B,eAAe,CAAC,EAAE,UAAU,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollisionManifold.d.ts","sourceRoot":"","sources":["../../src/collision/CollisionManifold.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAKvD,MAAM,WAAW,iBAAiB;IAEhC,OAAO,EAAE,MAAM,CAAC;IAEhB,OAAO,EAAE,MAAM,CAAC;IAEhB,OAAO,EAAE,UAAU,CAAC;IAEpB,OAAO,EAAE,UAAU,CAAC;IAEpB,WAAW,EAAE,UAAU,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type FixedPoint } from '@phalanx-engine/math';
|
|
2
|
+
import type { CollisionManifold } from './CollisionManifold';
|
|
3
|
+
export declare class NarrowPhase {
|
|
4
|
+
static circleVsCircle(posAX: FixedPoint, posAZ: FixedPoint, radiusA: FixedPoint, posBX: FixedPoint, posBZ: FixedPoint, radiusB: FixedPoint, entityA: number, entityB: number): CollisionManifold | null;
|
|
5
|
+
static circleVsAABB(circlePosX: FixedPoint, circlePosZ: FixedPoint, circleRadius: FixedPoint, aabbMinX: FixedPoint, aabbMinZ: FixedPoint, aabbMaxX: FixedPoint, aabbMaxZ: FixedPoint, entityCircle: number, entityAABB: number): CollisionManifold | null;
|
|
6
|
+
static aabbVsAABB(aMinX: FixedPoint, aMinZ: FixedPoint, aMaxX: FixedPoint, aMaxZ: FixedPoint, bMinX: FixedPoint, bMinZ: FixedPoint, bMaxX: FixedPoint, bMaxZ: FixedPoint, entityA: number, entityB: number): CollisionManifold | null;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=NarrowPhase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NarrowPhase.d.ts","sourceRoot":"","sources":["../../src/collision/NarrowPhase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAW7D,qBAAa,WAAW;IAKtB,MAAM,CAAC,cAAc,CACnB,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EACzD,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,EACzD,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAC/B,iBAAiB,GAAG,IAAI;IAwC3B,MAAM,CAAC,YAAY,CACjB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EACxE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAC1C,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAC1C,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GACvC,iBAAiB,GAAG,IAAI;IAsE3B,MAAM,CAAC,UAAU,CACf,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAC1E,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAC1E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAC/B,iBAAiB,GAAG,IAAI;CAuC5B"}
|