@codexo/exojs-physics 0.13.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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/dist/esm/Aabb.d.ts +14 -0
  4. package/dist/esm/Aabb.js +12 -0
  5. package/dist/esm/Aabb.js.map +1 -0
  6. package/dist/esm/Collider.d.ts +77 -0
  7. package/dist/esm/Collider.js +138 -0
  8. package/dist/esm/Collider.js.map +1 -0
  9. package/dist/esm/ContactGraph.d.ts +34 -0
  10. package/dist/esm/ContactGraph.js +157 -0
  11. package/dist/esm/ContactGraph.js.map +1 -0
  12. package/dist/esm/PhysicsBody.d.ts +103 -0
  13. package/dist/esm/PhysicsBody.js +186 -0
  14. package/dist/esm/PhysicsBody.js.map +1 -0
  15. package/dist/esm/PhysicsWorld.d.ts +126 -0
  16. package/dist/esm/PhysicsWorld.js +253 -0
  17. package/dist/esm/PhysicsWorld.js.map +1 -0
  18. package/dist/esm/TimeStepper.d.ts +39 -0
  19. package/dist/esm/TimeStepper.js +70 -0
  20. package/dist/esm/TimeStepper.js.map +1 -0
  21. package/dist/esm/backend/NativePhysicsBackend.d.ts +19 -0
  22. package/dist/esm/backend/NativePhysicsBackend.js +31 -0
  23. package/dist/esm/backend/NativePhysicsBackend.js.map +1 -0
  24. package/dist/esm/backend/PhysicsBackend.d.ts +23 -0
  25. package/dist/esm/binding/BindingRegistry.d.ts +21 -0
  26. package/dist/esm/binding/BindingRegistry.js +40 -0
  27. package/dist/esm/binding/BindingRegistry.js.map +1 -0
  28. package/dist/esm/binding/PhysicsBinding.d.ts +27 -0
  29. package/dist/esm/binding/PhysicsBinding.js +24 -0
  30. package/dist/esm/binding/PhysicsBinding.js.map +1 -0
  31. package/dist/esm/broadphase/BroadPhase.d.ts +22 -0
  32. package/dist/esm/broadphase/SweepAndPrune.d.ts +14 -0
  33. package/dist/esm/broadphase/SweepAndPrune.js +48 -0
  34. package/dist/esm/broadphase/SweepAndPrune.js.map +1 -0
  35. package/dist/esm/broadphase/index.d.ts +2 -0
  36. package/dist/esm/collision/CollisionProxy.d.ts +14 -0
  37. package/dist/esm/collision/Manifold.d.ts +33 -0
  38. package/dist/esm/collision/Manifold.js +28 -0
  39. package/dist/esm/collision/Manifold.js.map +1 -0
  40. package/dist/esm/collision/index.d.ts +3 -0
  41. package/dist/esm/collision/narrowphase.d.ts +14 -0
  42. package/dist/esm/collision/narrowphase.js +377 -0
  43. package/dist/esm/collision/narrowphase.js.map +1 -0
  44. package/dist/esm/debug/PhysicsDebugDraw.d.ts +46 -0
  45. package/dist/esm/debug/PhysicsDebugDraw.js +171 -0
  46. package/dist/esm/debug/PhysicsDebugDraw.js.map +1 -0
  47. package/dist/esm/debug/index.d.ts +1 -0
  48. package/dist/esm/debug/index.js +2 -0
  49. package/dist/esm/debug/index.js.map +1 -0
  50. package/dist/esm/events.d.ts +35 -0
  51. package/dist/esm/index.d.ts +1 -0
  52. package/dist/esm/index.js +12 -0
  53. package/dist/esm/index.js.map +1 -0
  54. package/dist/esm/math.d.ts +32 -0
  55. package/dist/esm/math.js +48 -0
  56. package/dist/esm/math.js.map +1 -0
  57. package/dist/esm/physicsBuildInfo.d.ts +15 -0
  58. package/dist/esm/physicsBuildInfo.js +8 -0
  59. package/dist/esm/physicsBuildInfo.js.map +1 -0
  60. package/dist/esm/public.d.ts +21 -0
  61. package/dist/esm/query/QueryEngine.d.ts +51 -0
  62. package/dist/esm/query/QueryEngine.js +246 -0
  63. package/dist/esm/query/QueryEngine.js.map +1 -0
  64. package/dist/esm/shapes/BoxShape.d.ts +11 -0
  65. package/dist/esm/shapes/BoxShape.js +29 -0
  66. package/dist/esm/shapes/BoxShape.js.map +1 -0
  67. package/dist/esm/shapes/CircleShape.d.ts +16 -0
  68. package/dist/esm/shapes/CircleShape.js +30 -0
  69. package/dist/esm/shapes/CircleShape.js.map +1 -0
  70. package/dist/esm/shapes/PolygonShape.d.ts +26 -0
  71. package/dist/esm/shapes/PolygonShape.js +156 -0
  72. package/dist/esm/shapes/PolygonShape.js.map +1 -0
  73. package/dist/esm/shapes/Shape.d.ts +26 -0
  74. package/dist/esm/shapes/Shape.js +16 -0
  75. package/dist/esm/shapes/Shape.js.map +1 -0
  76. package/dist/esm/shapes/index.d.ts +4 -0
  77. package/dist/esm/types.d.ts +39 -0
  78. package/dist/esm/types.js +28 -0
  79. package/dist/esm/types.js.map +1 -0
  80. package/package.json +51 -0
@@ -0,0 +1,35 @@
1
+ import type { Collider } from './Collider';
2
+ import type { PhysicsBody } from './PhysicsBody';
3
+ /** A single contact point on a {@link CollisionEvent}. World space. */
4
+ export interface ContactPoint {
5
+ readonly x: number;
6
+ readonly y: number;
7
+ /** Penetration depth in px (≥ 0). */
8
+ readonly penetration: number;
9
+ }
10
+ /**
11
+ * Immutable per-dispatch snapshot describing a solid (non-sensor) contact.
12
+ * Frozen: it is safe to read during the callback and to copy fields out, but it
13
+ * is never reused or mutated, so the classic "stored a pooled event" bug cannot
14
+ * occur. `normal` points from collider/body **A toward B**.
15
+ */
16
+ export interface CollisionEvent {
17
+ readonly bodyA: PhysicsBody;
18
+ readonly bodyB: PhysicsBody;
19
+ readonly colliderA: Collider;
20
+ readonly colliderB: Collider;
21
+ readonly normal: Readonly<{
22
+ x: number;
23
+ y: number;
24
+ }>;
25
+ readonly points: readonly ContactPoint[];
26
+ }
27
+ /**
28
+ * Immutable per-dispatch snapshot for a sensor overlap. `sensor` is the
29
+ * sensor-flagged collider; `other` is the collider that entered/left it. When
30
+ * both colliders are sensors, the lower-id collider is reported as `sensor`.
31
+ */
32
+ export interface SensorEvent {
33
+ readonly sensor: Collider;
34
+ readonly other: Collider;
35
+ }
@@ -0,0 +1 @@
1
+ export * from './public';
@@ -0,0 +1,12 @@
1
+ export { PhysicsBinding } from './binding/PhysicsBinding.js';
2
+ export { Collider } from './Collider.js';
3
+ export { PhysicsBody } from './PhysicsBody.js';
4
+ export { physicsBuildInfo } from './physicsBuildInfo.js';
5
+ export { PhysicsWorld } from './PhysicsWorld.js';
6
+ export { BoxShape } from './shapes/BoxShape.js';
7
+ export { CircleShape } from './shapes/CircleShape.js';
8
+ export { PolygonShape } from './shapes/PolygonShape.js';
9
+ export { Shape } from './shapes/Shape.js';
10
+ export { TimeStepper } from './TimeStepper.js';
11
+ export { defaultFilter, shouldCollide } from './types.js';
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -0,0 +1,32 @@
1
+ /** A mutable two-component output sink used to avoid per-call allocation. */
2
+ export interface Mutable2D {
3
+ x: number;
4
+ y: number;
5
+ }
6
+ /** A rigid 2D transform: translation plus the precomputed sin/cos of `angle`. */
7
+ export interface Transform {
8
+ x: number;
9
+ y: number;
10
+ /** Rotation in radians. */
11
+ angle: number;
12
+ sin: number;
13
+ cos: number;
14
+ }
15
+ /** Create a transform from a position and angle (radians). */
16
+ export declare const createTransform: (x?: number, y?: number, angle?: number) => Transform;
17
+ /** Set a transform in place, refreshing sin/cos only when the angle changes. */
18
+ export declare const setTransform: (transform: Transform, x: number, y: number, angle: number) => Transform;
19
+ /** Rotate and translate a local point by `transform`, writing into `out`. */
20
+ export declare const applyTransform: (transform: Transform, x: number, y: number, out: Mutable2D) => Mutable2D;
21
+ /** Rotate a local direction by `transform` (no translation), writing into `out`. */
22
+ export declare const applyRotation: (transform: Transform, x: number, y: number, out: Mutable2D) => Mutable2D;
23
+ /** Map a world point into `transform`'s local frame, writing into `out`. */
24
+ export declare const applyInverseTransform: (transform: Transform, x: number, y: number, out: Mutable2D) => Mutable2D;
25
+ /** Map a world direction into `transform`'s local frame, writing into `out`. */
26
+ export declare const applyInverseRotation: (transform: Transform, x: number, y: number, out: Mutable2D) => Mutable2D;
27
+ /**
28
+ * Compose `world = body ∘ local` into `out`. The local transform is expressed
29
+ * in the body frame (a collider's offset + local rotation); the result is the
30
+ * collider's world transform.
31
+ */
32
+ export declare const composeTransforms: (body: Transform, local: Transform, out: Transform) => Transform;
@@ -0,0 +1,48 @@
1
+ // Internal rigid-transform and angle helpers. Physics stores rotations as a
2
+ // precomputed `sin`/`cos` pair so the hot collision paths never call the
3
+ // trigonometric functions per vertex. `Mutable2D` is a tiny `{ x, y }` sink to
4
+ // keep the rotate/transform helpers allocation-free at their call sites.
5
+ /** Create a transform from a position and angle (radians). */
6
+ const createTransform = (x = 0, y = 0, angle = 0) => ({
7
+ x,
8
+ y,
9
+ angle,
10
+ sin: Math.sin(angle),
11
+ cos: Math.cos(angle),
12
+ });
13
+ /** Set a transform in place, refreshing sin/cos only when the angle changes. */
14
+ const setTransform = (transform, x, y, angle) => {
15
+ transform.x = x;
16
+ transform.y = y;
17
+ if (transform.angle !== angle) {
18
+ transform.angle = angle;
19
+ transform.sin = Math.sin(angle);
20
+ transform.cos = Math.cos(angle);
21
+ }
22
+ return transform;
23
+ };
24
+ /** Rotate and translate a local point by `transform`, writing into `out`. */
25
+ const applyTransform = (transform, x, y, out) => {
26
+ out.x = transform.cos * x - transform.sin * y + transform.x;
27
+ out.y = transform.sin * x + transform.cos * y + transform.y;
28
+ return out;
29
+ };
30
+ /** Rotate a local direction by `transform` (no translation), writing into `out`. */
31
+ const applyRotation = (transform, x, y, out) => {
32
+ out.x = transform.cos * x - transform.sin * y;
33
+ out.y = transform.sin * x + transform.cos * y;
34
+ return out;
35
+ };
36
+ /**
37
+ * Compose `world = body ∘ local` into `out`. The local transform is expressed
38
+ * in the body frame (a collider's offset + local rotation); the result is the
39
+ * collider's world transform.
40
+ */
41
+ const composeTransforms = (body, local, out) => {
42
+ const x = body.cos * local.x - body.sin * local.y + body.x;
43
+ const y = body.sin * local.x + body.cos * local.y + body.y;
44
+ return setTransform(out, x, y, body.angle + local.angle);
45
+ };
46
+
47
+ export { applyRotation, applyTransform, composeTransforms, createTransform, setTransform };
48
+ //# sourceMappingURL=math.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"math.js","sources":["../../../src/math.ts"],"sourcesContent":[null],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AAkBA;AACO,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,MAAiB;IACtE,CAAC;IACD,CAAC;IACD,KAAK;AACL,IAAA,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACpB,IAAA,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;AACrB,CAAA;AAED;AACO,MAAM,YAAY,GAAG,CAAC,SAAoB,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,KAAe;AACnG,IAAA,SAAS,CAAC,CAAC,GAAG,CAAC;AACf,IAAA,SAAS,CAAC,CAAC,GAAG,CAAC;AAEf,IAAA,IAAI,SAAS,CAAC,KAAK,KAAK,KAAK,EAAE;AAC7B,QAAA,SAAS,CAAC,KAAK,GAAG,KAAK;QACvB,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;QAC/B,SAAS,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;IACjC;AAEA,IAAA,OAAO,SAAS;AAClB;AAEA;AACO,MAAM,cAAc,GAAG,CAAC,SAAoB,EAAE,CAAS,EAAE,CAAS,EAAE,GAAc,KAAe;AACtG,IAAA,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;AAC3D,IAAA,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;AAE3D,IAAA,OAAO,GAAG;AACZ;AAEA;AACO,MAAM,aAAa,GAAG,CAAC,SAAoB,EAAE,CAAS,EAAE,CAAS,EAAE,GAAc,KAAe;AACrG,IAAA,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC;AAC7C,IAAA,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC;AAE7C,IAAA,OAAO,GAAG;AACZ;AAqBA;;;;AAIG;AACI,MAAM,iBAAiB,GAAG,CAAC,IAAe,EAAE,KAAgB,EAAE,GAAc,KAAe;IAChG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC1D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAE1D,IAAA,OAAO,YAAY,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;AAC1D;;;;"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Immutable compile-time build metadata for `@codexo/exojs-physics`.
3
+ *
4
+ * `development` mirrors the `__DEV__` compile-time constant and is statically
5
+ * replaced before tree shaking. `version` is the exact `package.json` version
6
+ * of the Physics package at build time. `revision` is the short source-control
7
+ * revision (appended with `-dirty` when uncommitted changes are present) or
8
+ * `"unknown"` when no revision information is available.
9
+ */
10
+ export interface PhysicsBuildInfo {
11
+ readonly version: string;
12
+ readonly revision: string;
13
+ readonly development: boolean;
14
+ }
15
+ export declare const physicsBuildInfo: PhysicsBuildInfo;
@@ -0,0 +1,8 @@
1
+ const physicsBuildInfo = Object.freeze({
2
+ version: "0.13.0",
3
+ revision: "ad2faf3",
4
+ development: false,
5
+ });
6
+
7
+ export { physicsBuildInfo };
8
+ //# sourceMappingURL=physicsBuildInfo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"physicsBuildInfo.js","sources":["../../../src/physicsBuildInfo.ts"],"sourcesContent":[null],"names":[],"mappings":"AAeO,MAAM,gBAAgB,GAAqB,MAAM,CAAC,MAAM,CAAC;AAC9D,IAAA,OAAO,EAAE,QAAW;AACpB,IAAA,QAAQ,EAAE,SAAY;AACtB,IAAA,WAAW,EAAE,KAAO;AACrB,CAAA;;;;"}
@@ -0,0 +1,21 @@
1
+ export type { Aabb } from './Aabb';
2
+ export type { BindingOptions } from './binding/PhysicsBinding';
3
+ export { PhysicsBinding } from './binding/PhysicsBinding';
4
+ export type { ColliderOptions } from './Collider';
5
+ export { Collider } from './Collider';
6
+ export type { CollisionEvent, ContactPoint, SensorEvent } from './events';
7
+ export type { BodyOptions } from './PhysicsBody';
8
+ export { PhysicsBody } from './PhysicsBody';
9
+ export { type PhysicsBuildInfo, physicsBuildInfo } from './physicsBuildInfo';
10
+ export type { PhysicsWorldOptions, StaticColliderOptions } from './PhysicsWorld';
11
+ export { PhysicsWorld } from './PhysicsWorld';
12
+ export type { QueryFilter, RayHit } from './query/QueryEngine';
13
+ export { BoxShape } from './shapes/BoxShape';
14
+ export { CircleShape } from './shapes/CircleShape';
15
+ export { PolygonShape } from './shapes/PolygonShape';
16
+ export type { ShapeType } from './shapes/Shape';
17
+ export { Shape } from './shapes/Shape';
18
+ export type { TimeStepperOptions } from './TimeStepper';
19
+ export { TimeStepper } from './TimeStepper';
20
+ export type { BodyType, CollisionFilter, VectorLike } from './types';
21
+ export { defaultFilter, shouldCollide } from './types';
@@ -0,0 +1,51 @@
1
+ import type { Aabb } from '../Aabb';
2
+ import type { Collider } from '../Collider';
3
+ import type { PhysicsBody } from '../PhysicsBody';
4
+ import type { Shape } from '../shapes/Shape';
5
+ import type { VectorLike } from '../types';
6
+ /** A category/mask/group filter applied to a query. Omitting it matches everything. */
7
+ export type QueryFilter = Partial<{
8
+ category: number;
9
+ mask: number;
10
+ group: number;
11
+ }>;
12
+ /** A single ray-cast intersection. */
13
+ export interface RayHit {
14
+ collider: Collider;
15
+ body: PhysicsBody;
16
+ /** World-space hit position. */
17
+ point: {
18
+ x: number;
19
+ y: number;
20
+ };
21
+ /** Surface normal at the hit (unit, pointing back toward the ray origin). */
22
+ normal: {
23
+ x: number;
24
+ y: number;
25
+ };
26
+ /** Distance from the origin along the (normalised) ray direction. */
27
+ distance: number;
28
+ }
29
+ /**
30
+ * Spatial queries over the world's live collider set. The engine holds a
31
+ * reference to the world's collider array (kept world-synchronised on every
32
+ * body move), so queries always see current placements. Array-returning queries
33
+ * follow the three explicit allocation forms: fresh array, caller-owned `out`,
34
+ * or an allocation-free callback — never a hidden shared buffer.
35
+ */
36
+ export declare class QueryEngine {
37
+ private readonly _colliders;
38
+ constructor(colliders: readonly Collider[]);
39
+ /** Colliders containing `point`. Allocates a fresh array. */
40
+ queryPoint(point: VectorLike, filter?: QueryFilter): Collider[];
41
+ /** Colliders whose AABB overlaps `bounds`. Writes into `out` (cleared first) when given, else a fresh array. */
42
+ queryAabb(bounds: Aabb, filter?: QueryFilter, out?: Collider[]): Collider[];
43
+ /** Invoke `callback` for each collider whose AABB overlaps `bounds`. Allocation-free. */
44
+ forEachAabbHit(bounds: Aabb, filter: QueryFilter | undefined, callback: (collider: Collider) => void): void;
45
+ /** Nearest collider hit by the ray from `origin` along `direction`, or `null`. */
46
+ rayCast(origin: VectorLike, direction: VectorLike, filter?: QueryFilter, maxDistance?: number): RayHit | null;
47
+ /** All collider hits along the ray, sorted by distance. Writes into `out` (cleared first) when given. */
48
+ rayCastAll(origin: VectorLike, direction: VectorLike, filter?: QueryFilter, out?: RayHit[], maxDistance?: number): RayHit[];
49
+ /** Colliders overlapping `shape` placed at `position`/`angle`. Allocates a fresh array. */
50
+ overlapShape(shape: Shape, position: VectorLike, filter?: QueryFilter, angle?: number): Collider[];
51
+ }
@@ -0,0 +1,246 @@
1
+ import { aabbOverlap, aabbContainsPoint } from '../Aabb.js';
2
+ import { testOverlap } from '../collision/narrowphase.js';
3
+ import { applyTransform, applyRotation, createTransform } from '../math.js';
4
+ import { resolveFilter, shouldCollide } from '../types.js';
5
+
6
+ /**
7
+ * Spatial queries over the world's live collider set. The engine holds a
8
+ * reference to the world's collider array (kept world-synchronised on every
9
+ * body move), so queries always see current placements. Array-returning queries
10
+ * follow the three explicit allocation forms: fresh array, caller-owned `out`,
11
+ * or an allocation-free callback — never a hidden shared buffer.
12
+ */
13
+ class QueryEngine {
14
+ _colliders;
15
+ constructor(colliders) {
16
+ this._colliders = colliders;
17
+ }
18
+ /** Colliders containing `point`. Allocates a fresh array. */
19
+ queryPoint(point, filter) {
20
+ const out = [];
21
+ const resolved = filter ? resolveFilter(filter) : null;
22
+ for (const collider of this._colliders) {
23
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
24
+ continue;
25
+ }
26
+ if (pointInCollider(collider, point.x, point.y)) {
27
+ out.push(collider);
28
+ }
29
+ }
30
+ return out;
31
+ }
32
+ /** Colliders whose AABB overlaps `bounds`. Writes into `out` (cleared first) when given, else a fresh array. */
33
+ queryAabb(bounds, filter, out) {
34
+ const result = out ?? [];
35
+ result.length = 0;
36
+ const resolved = filter ? resolveFilter(filter) : null;
37
+ for (const collider of this._colliders) {
38
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
39
+ continue;
40
+ }
41
+ if (aabbOverlap(collider.aabb, bounds)) {
42
+ result.push(collider);
43
+ }
44
+ }
45
+ return result;
46
+ }
47
+ /** Invoke `callback` for each collider whose AABB overlaps `bounds`. Allocation-free. */
48
+ forEachAabbHit(bounds, filter, callback) {
49
+ const resolved = filter ? resolveFilter(filter) : null;
50
+ for (const collider of this._colliders) {
51
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
52
+ continue;
53
+ }
54
+ if (aabbOverlap(collider.aabb, bounds)) {
55
+ callback(collider);
56
+ }
57
+ }
58
+ }
59
+ /** Nearest collider hit by the ray from `origin` along `direction`, or `null`. */
60
+ rayCast(origin, direction, filter, maxDistance = Infinity) {
61
+ const length = Math.hypot(direction.x, direction.y);
62
+ if (length < 1e-9) {
63
+ throw new RangeError('QueryEngine.rayCast: direction must be non-zero.');
64
+ }
65
+ const dx = direction.x / length;
66
+ const dy = direction.y / length;
67
+ const resolved = filter ? resolveFilter(filter) : null;
68
+ let best = null;
69
+ for (const collider of this._colliders) {
70
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
71
+ continue;
72
+ }
73
+ const hit = rayCastCollider(collider, origin.x, origin.y, dx, dy, best ? best.distance : maxDistance);
74
+ if (hit && (best === null || hit.distance < best.distance)) {
75
+ best = hit;
76
+ }
77
+ }
78
+ return best;
79
+ }
80
+ /** All collider hits along the ray, sorted by distance. Writes into `out` (cleared first) when given. */
81
+ rayCastAll(origin, direction, filter, out, maxDistance = Infinity) {
82
+ const length = Math.hypot(direction.x, direction.y);
83
+ if (length < 1e-9) {
84
+ throw new RangeError('QueryEngine.rayCastAll: direction must be non-zero.');
85
+ }
86
+ const dx = direction.x / length;
87
+ const dy = direction.y / length;
88
+ const resolved = filter ? resolveFilter(filter) : null;
89
+ const result = out ?? [];
90
+ result.length = 0;
91
+ for (const collider of this._colliders) {
92
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
93
+ continue;
94
+ }
95
+ const hit = rayCastCollider(collider, origin.x, origin.y, dx, dy, maxDistance);
96
+ if (hit) {
97
+ result.push(hit);
98
+ }
99
+ }
100
+ result.sort((a, b) => a.distance - b.distance);
101
+ return result;
102
+ }
103
+ /** Colliders overlapping `shape` placed at `position`/`angle`. Allocates a fresh array. */
104
+ overlapShape(shape, position, filter, angle = 0) {
105
+ const proxy = makeProxy(shape, position.x, position.y, angle);
106
+ const out = [];
107
+ const resolved = filter ? resolveFilter(filter) : null;
108
+ for (const collider of this._colliders) {
109
+ if (resolved && !shouldCollide(resolved, collider.filter)) {
110
+ continue;
111
+ }
112
+ if (testOverlap(proxy, collider)) {
113
+ out.push(collider);
114
+ }
115
+ }
116
+ return out;
117
+ }
118
+ }
119
+ /** `true` when world point `(px, py)` lies inside `collider`'s shape. */
120
+ const pointInCollider = (collider, px, py) => {
121
+ if (!aabbContainsPoint(collider.aabb, px, py)) {
122
+ return false;
123
+ }
124
+ if (collider.shape.type === 'circle') {
125
+ const c = collider.worldCenter;
126
+ const r = collider.shape.radius;
127
+ const dx = px - c.x;
128
+ const dy = py - c.y;
129
+ return dx * dx + dy * dy <= r * r;
130
+ }
131
+ const verts = collider.worldVertices;
132
+ const normals = collider.worldNormals;
133
+ const count = collider.shape.count;
134
+ for (let i = 0; i < count; i++) {
135
+ if (normals[i * 2] * (px - verts[i * 2]) + normals[i * 2 + 1] * (py - verts[i * 2 + 1]) > 0) {
136
+ return false;
137
+ }
138
+ }
139
+ return true;
140
+ };
141
+ /** Cast the (normalised) ray against one collider, returning the entry hit or `null`. */
142
+ const rayCastCollider = (collider, ox, oy, dx, dy, maxDistance) => {
143
+ if (collider.shape.type === 'circle') {
144
+ return rayCastCircle(collider, ox, oy, dx, dy, maxDistance);
145
+ }
146
+ return rayCastPolygon(collider, ox, oy, dx, dy, maxDistance);
147
+ };
148
+ const rayCastCircle = (collider, ox, oy, dx, dy, maxDistance) => {
149
+ const c = collider.worldCenter;
150
+ const r = collider.shape.radius;
151
+ const mx = ox - c.x;
152
+ const my = oy - c.y;
153
+ const b = mx * dx + my * dy;
154
+ const cc = mx * mx + my * my - r * r;
155
+ // Origin outside and pointing away.
156
+ if (cc > 0 && b > 0) {
157
+ return null;
158
+ }
159
+ const disc = b * b - cc;
160
+ if (disc < 0) {
161
+ return null;
162
+ }
163
+ let t = -b - Math.sqrt(disc);
164
+ if (t < 0) {
165
+ t = 0;
166
+ }
167
+ if (t > maxDistance) {
168
+ return null;
169
+ }
170
+ const px = ox + dx * t;
171
+ const py = oy + dy * t;
172
+ const nx = (px - c.x) / r;
173
+ const ny = (py - c.y) / r;
174
+ return { collider, body: collider.body, point: { x: px, y: py }, normal: { x: nx, y: ny }, distance: t };
175
+ };
176
+ const rayCastPolygon = (collider, ox, oy, dx, dy, maxDistance) => {
177
+ const verts = collider.worldVertices;
178
+ const normals = collider.worldNormals;
179
+ const count = collider.shape.count;
180
+ let tmin = 0;
181
+ let tmax = maxDistance;
182
+ let enterNx = 0;
183
+ let enterNy = 0;
184
+ let entered = false;
185
+ for (let i = 0; i < count; i++) {
186
+ const nx = normals[i * 2];
187
+ const ny = normals[i * 2 + 1];
188
+ const numerator = nx * (verts[i * 2] - ox) + ny * (verts[i * 2 + 1] - oy);
189
+ const denominator = nx * dx + ny * dy;
190
+ if (denominator === 0) {
191
+ // Parallel to this face: if the origin is outside it, the ray misses.
192
+ if (numerator < 0) {
193
+ return null;
194
+ }
195
+ continue;
196
+ }
197
+ const t = numerator / denominator;
198
+ if (denominator < 0) {
199
+ // Entering this half-plane.
200
+ if (t > tmin) {
201
+ tmin = t;
202
+ enterNx = nx;
203
+ enterNy = ny;
204
+ entered = true;
205
+ }
206
+ }
207
+ else if (t < tmax) {
208
+ // Leaving this half-plane.
209
+ tmax = t;
210
+ }
211
+ if (tmin > tmax) {
212
+ return null;
213
+ }
214
+ }
215
+ if (!entered || tmin < 0 || tmin > maxDistance) {
216
+ return null;
217
+ }
218
+ return {
219
+ collider,
220
+ body: collider.body,
221
+ point: { x: ox + dx * tmin, y: oy + dy * tmin },
222
+ normal: { x: enterNx, y: enterNy },
223
+ distance: tmin,
224
+ };
225
+ };
226
+ /** Build a throwaway collision proxy for a shape placed at `(x, y)` with `angle`. */
227
+ const makeProxy = (shape, x, y, angle) => {
228
+ if (shape.type === 'circle') {
229
+ return { shape, worldCenter: { x, y }, worldVertices: [], worldNormals: [] };
230
+ }
231
+ const polygon = shape;
232
+ const transform = createTransform(x, y, angle);
233
+ const worldVertices = [];
234
+ const worldNormals = [];
235
+ const out = { x: 0, y: 0 };
236
+ for (let i = 0; i < polygon.count; i++) {
237
+ applyTransform(transform, polygon.vertices[i * 2], polygon.vertices[i * 2 + 1], out);
238
+ worldVertices.push(out.x, out.y);
239
+ applyRotation(transform, polygon.normals[i * 2], polygon.normals[i * 2 + 1], out);
240
+ worldNormals.push(out.x, out.y);
241
+ }
242
+ return { shape, worldCenter: { x, y }, worldVertices, worldNormals };
243
+ };
244
+
245
+ export { QueryEngine };
246
+ //# sourceMappingURL=QueryEngine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QueryEngine.js","sources":["../../../../src/query/QueryEngine.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { PolygonShape } from './PolygonShape';
2
+ /**
3
+ * Axis-aligned box of `width × height` centred on the collider's local origin —
4
+ * a convenience over {@link PolygonShape}. The result is a regular polygon, so
5
+ * it participates in the polygon narrow phase like any other convex shape.
6
+ */
7
+ export declare class BoxShape extends PolygonShape {
8
+ readonly width: number;
9
+ readonly height: number;
10
+ constructor(width: number, height: number);
11
+ }
@@ -0,0 +1,29 @@
1
+ import { PolygonShape } from './PolygonShape.js';
2
+
3
+ /**
4
+ * Axis-aligned box of `width × height` centred on the collider's local origin —
5
+ * a convenience over {@link PolygonShape}. The result is a regular polygon, so
6
+ * it participates in the polygon narrow phase like any other convex shape.
7
+ */
8
+ class BoxShape extends PolygonShape {
9
+ width;
10
+ height;
11
+ constructor(width, height) {
12
+ if (!Number.isFinite(width) || width <= 0 || !Number.isFinite(height) || height <= 0) {
13
+ throw new RangeError(`BoxShape: width and height must be positive finite numbers, received ${width} × ${height}.`);
14
+ }
15
+ const hw = width / 2;
16
+ const hh = height / 2;
17
+ super([
18
+ { x: -hw, y: -hh },
19
+ { x: hw, y: -hh },
20
+ { x: hw, y: hh },
21
+ { x: -hw, y: hh },
22
+ ]);
23
+ this.width = width;
24
+ this.height = height;
25
+ }
26
+ }
27
+
28
+ export { BoxShape };
29
+ //# sourceMappingURL=BoxShape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BoxShape.js","sources":["../../../../src/shapes/BoxShape.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;;;;AAIG;AACG,MAAO,QAAS,SAAQ,YAAY,CAAA;AACxB,IAAA,KAAK;AACL,IAAA,MAAM;IAEtB,WAAA,CAAmB,KAAa,EAAE,MAAc,EAAA;QAC9C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE;YACpF,MAAM,IAAI,UAAU,CAAC,CAAA,qEAAA,EAAwE,KAAK,CAAA,GAAA,EAAM,MAAM,CAAA,CAAA,CAAG,CAAC;QACpH;AAEA,QAAA,MAAM,EAAE,GAAG,KAAK,GAAG,CAAC;AACpB,QAAA,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC;AAErB,QAAA,KAAK,CAAC;YACJ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;YAClB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE;AACjB,YAAA,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;YAChB,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE;AAClB,SAAA,CAAC;AAEF,QAAA,IAAI,CAAC,KAAK,GAAG,KAAK;AAClB,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;IACtB;AACD;;;;"}
@@ -0,0 +1,16 @@
1
+ import type { ShapeType } from './Shape';
2
+ import { Shape } from './Shape';
3
+ /**
4
+ * A circle of the given `radius` centred on the collider's local origin.
5
+ * The cheapest shape for both broad- and narrow-phase.
6
+ */
7
+ export declare class CircleShape extends Shape {
8
+ readonly type: ShapeType;
9
+ readonly radius: number;
10
+ readonly boundingRadius: number;
11
+ readonly area: number;
12
+ readonly centroidX = 0;
13
+ readonly centroidY = 0;
14
+ readonly unitInertia: number;
15
+ constructor(radius: number);
16
+ }
@@ -0,0 +1,30 @@
1
+ import { Shape } from './Shape.js';
2
+
3
+ /**
4
+ * A circle of the given `radius` centred on the collider's local origin.
5
+ * The cheapest shape for both broad- and narrow-phase.
6
+ */
7
+ class CircleShape extends Shape {
8
+ type = 'circle';
9
+ radius;
10
+ boundingRadius;
11
+ area;
12
+ centroidX = 0;
13
+ centroidY = 0;
14
+ unitInertia;
15
+ constructor(radius) {
16
+ super();
17
+ if (!Number.isFinite(radius) || radius <= 0) {
18
+ throw new RangeError(`CircleShape: radius must be a positive finite number, received ${radius}.`);
19
+ }
20
+ this.radius = radius;
21
+ this.boundingRadius = radius;
22
+ this.area = Math.PI * radius * radius;
23
+ // Second moment of area of a disc about its centre: ∫ r² dA = (π/2) R⁴.
24
+ this.unitInertia = 0.5 * this.area * radius * radius;
25
+ Object.freeze(this);
26
+ }
27
+ }
28
+
29
+ export { CircleShape };
30
+ //# sourceMappingURL=CircleShape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CircleShape.js","sources":["../../../../src/shapes/CircleShape.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAGA;;;AAGG;AACG,MAAO,WAAY,SAAQ,KAAK,CAAA;IACpB,IAAI,GAAc,QAAQ;AAC1B,IAAA,MAAM;AACN,IAAA,cAAc;AACd,IAAA,IAAI;IACJ,SAAS,GAAG,CAAC;IACb,SAAS,GAAG,CAAC;AACb,IAAA,WAAW;AAE3B,IAAA,WAAA,CAAmB,MAAc,EAAA;AAC/B,QAAA,KAAK,EAAE;AAEP,QAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE;AAC3C,YAAA,MAAM,IAAI,UAAU,CAAC,kEAAkE,MAAM,CAAA,CAAA,CAAG,CAAC;QACnG;AAEA,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,cAAc,GAAG,MAAM;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,GAAG,MAAM;;AAErC,QAAA,IAAI,CAAC,WAAW,GAAG,GAAG,GAAG,IAAI,CAAC,IAAI,GAAG,MAAM,GAAG,MAAM;AAEpD,QAAA,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;IACrB;AACD;;;;"}
@@ -0,0 +1,26 @@
1
+ import type { VectorLike } from '../types';
2
+ import type { ShapeType } from './Shape';
3
+ import { Shape } from './Shape';
4
+ /**
5
+ * A convex polygon defined by ≥3 local-space vertices. Input vertices may be
6
+ * given in either winding; they are canonicalised to counter-clockwise and the
7
+ * outward edge normals are precomputed. Construction throws on any non-convex,
8
+ * degenerate, or under-specified input — there is no silent repair.
9
+ *
10
+ * Vertices and normals are exposed as flat `[x0, y0, x1, y1, …]` arrays to keep
11
+ * the narrow phase allocation-free; both are frozen.
12
+ */
13
+ export declare class PolygonShape extends Shape {
14
+ readonly type: ShapeType;
15
+ /** Local-space vertices, CCW, flattened. */
16
+ readonly vertices: readonly number[];
17
+ /** Outward unit edge normals (edge `i` spans vertex `i → i+1`), flattened. */
18
+ readonly normals: readonly number[];
19
+ readonly count: number;
20
+ readonly boundingRadius: number;
21
+ readonly area: number;
22
+ readonly centroidX: number;
23
+ readonly centroidY: number;
24
+ readonly unitInertia: number;
25
+ constructor(vertices: readonly VectorLike[]);
26
+ }