@codexo/exojs 0.6.11 → 0.6.12

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/CHANGELOG.md CHANGED
@@ -4,6 +4,46 @@ All notable changes to ExoJS are documented in this file.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.6.12] - 2026-05-02
8
+
9
+ Adds swept (continuous) collision detection. Pure-math addition —
10
+ prevents fast-moving shapes from tunneling through stationary
11
+ colliders during a single frame's update.
12
+
13
+ ### Added
14
+
15
+ - **`sweepRectangle(moving, deltaX, deltaY, target)`** — swept AABB
16
+ vs AABB via the slab method. Returns `SweptHit | null` with time
17
+ of impact `t ∈ [0..1]`, contact position `(x, y)`, and surface
18
+ normal `(normalX, normalY)`. Handles already-overlapping case
19
+ (returns `t = 0` with deepest-penetration axis as normal).
20
+ - **`sweepCircleVsCircle(moving, deltaX, deltaY, target)`** —
21
+ closed-form quadratic solution.
22
+ - **`sweepCircleVsRectangle(moving, deltaX, deltaY, target)`** —
23
+ v1 uses the simple expanded-AABB fallback (rectangle expanded
24
+ by circle radius, treated as AABB swept against zero-sized
25
+ moving circle). Over-collides slightly at corners — true
26
+ Minkowski corner rounding is V2.
27
+ - **`sweepRectangleAgainst(moving, dx, dy, targets)`** /
28
+ **`sweepCircleAgainst(moving, dx, dy, targets)`** — earliest
29
+ hit against an array of static colliders. Broad-phase swept-AABB
30
+ early-out per target.
31
+ - **`substepSweep(fromX, fromY, deltaX, deltaY, maxStepSize)`** —
32
+ generator that yields `(x, y, t)` snapshots along a movement
33
+ vector at fixed intervals. Use this for arbitrary shape pairs
34
+ that lack a closed-form swept test: iterate, place shape at
35
+ each snapshot, run discrete intersection.
36
+ - **`SweptHit` interface** exported.
37
+
38
+ ### Notes
39
+
40
+ - Pure math only — no Scene / RenderNode / Physics integration. User
41
+ code calls these in their game's update step.
42
+ - v1 covers the common cases (AABB + Circle). Polygon-vs-anything
43
+ swept tests are V2 (use `substepSweep` as a fallback for now).
44
+ - Returns the hit; does NOT compute response. Sliding / bouncing /
45
+ velocity adjustment is the caller's responsibility.
46
+
7
47
  ## [0.6.11] - 2026-05-02
8
48
 
9
49
  Adds a fluent-builder Tween / Animation system. Pure addition — no
package/dist/esm/index.js CHANGED
@@ -58,6 +58,7 @@ export { Random } from './math/Random.js';
58
58
  export { Segment } from './math/Segment.js';
59
59
  export { Size } from './math/Size.js';
60
60
  export { PolarVector } from './math/PolarVector.js';
61
+ export { substepSweep, sweepCircleAgainst, sweepCircleVsCircle, sweepCircleVsRectangle, sweepRectangle, sweepRectangleAgainst } from './math/swept-collision.js';
61
62
  export { ColorAffector } from './particles/affectors/ColorAffector.js';
62
63
  export { ForceAffector } from './particles/affectors/ForceAffector.js';
63
64
  export { ScaleAffector } from './particles/affectors/ScaleAffector.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -24,3 +24,4 @@ export * from './Random';
24
24
  export * from './Segment';
25
25
  export * from './Size';
26
26
  export * from './PolarVector';
27
+ export * from './swept-collision';
@@ -0,0 +1,90 @@
1
+ import { Rectangle } from './Rectangle';
2
+ import type { CircleLike } from './CircleLike';
3
+ /**
4
+ * Result of a swept-collision query. The moving shape's reference point
5
+ * is at `(x, y)` at impact, having travelled fraction `t` ∈ [0..1] of
6
+ * the requested move (where 0 = no movement, 1 = full move). The
7
+ * `(normalX, normalY)` vector is the contact normal pointing AWAY from
8
+ * the target (suitable for sliding response: project the remaining
9
+ * velocity onto the perpendicular).
10
+ */
11
+ export interface SweptHit {
12
+ readonly t: number;
13
+ readonly x: number;
14
+ readonly y: number;
15
+ readonly normalX: number;
16
+ readonly normalY: number;
17
+ }
18
+ /**
19
+ * Swept axis-aligned box vs. axis-aligned box.
20
+ *
21
+ * Uses the separating-axis slab method: for each axis we compute the entry
22
+ * and exit times of the moving box's slab vs the static box's slab, then
23
+ * combine. `t` is the fraction of the requested move at which first contact
24
+ * occurs (0 = already overlapping at start, 1 = just barely reaches).
25
+ *
26
+ * Already-overlapping case (tEntry < 0 overall): returns `t = 0` with the
27
+ * normal of the deepest-penetration axis, allowing callers to handle the
28
+ * "I'm already inside" situation without a separate discrete test.
29
+ */
30
+ export declare function sweepRectangle(moving: Rectangle, deltaX: number, deltaY: number, target: Rectangle): SweptHit | null;
31
+ /**
32
+ * Swept circle vs. axis-aligned box.
33
+ *
34
+ * **V1 implementation** uses the simple Minkowski expansion fallback:
35
+ * the target rectangle is expanded by `circle.radius` on all sides, then
36
+ * `sweepRectangle` is run treating the circle centre as a zero-sized moving
37
+ * box. This over-collides at rectangle corners (the circle collides with the
38
+ * expanded-rect's flat face when geometrically it should curve around the
39
+ * corner), producing slightly early hits in corner-quadrant trajectories —
40
+ * a known and acceptable accuracy trade-off for V1.
41
+ *
42
+ * TODO (V2): Replace with the full Minkowski rounded-rectangle formulation
43
+ * that handles the four corner quadrants with per-corner circle-vs-circle
44
+ * sub-tests.
45
+ */
46
+ export declare function sweepCircleVsRectangle(moving: CircleLike, deltaX: number, deltaY: number, target: Rectangle): SweptHit | null;
47
+ /**
48
+ * Swept circle vs. stationary circle.
49
+ *
50
+ * Solves `|(moving.centre + delta*t) − target.centre|² = (r1+r2)²` for t,
51
+ * yielding a quadratic. Returns the smaller root if it is in [0, 1].
52
+ *
53
+ * Already-overlapping case: returns `{ t: 0 }` with the normal pointing from
54
+ * target → moving (or an arbitrary normal if both centres coincide).
55
+ */
56
+ export declare function sweepCircleVsCircle(moving: CircleLike, deltaX: number, deltaY: number, target: CircleLike): SweptHit | null;
57
+ /**
58
+ * Returns the earliest `SweptHit` against an array of rectangle targets, or
59
+ * `null` if none are hit.
60
+ *
61
+ * Optimisation: before testing each target individually the swept AABB of the
62
+ * moving rectangle is computed once; targets whose AABB does not overlap the
63
+ * swept AABB are skipped.
64
+ */
65
+ export declare function sweepRectangleAgainst(moving: Rectangle, deltaX: number, deltaY: number, targets: ReadonlyArray<Rectangle>): SweptHit | null;
66
+ /**
67
+ * Returns the earliest `SweptHit` against an array of circle targets, or
68
+ * `null` if none are hit.
69
+ *
70
+ * Optimisation: the swept AABB of the moving circle is computed once and used
71
+ * to skip targets that cannot possibly be reached.
72
+ */
73
+ export declare function sweepCircleAgainst(moving: CircleLike, deltaX: number, deltaY: number, targets: ReadonlyArray<CircleLike>): SweptHit | null;
74
+ /**
75
+ * Generator that yields evenly-spaced position snapshots along a movement
76
+ * vector so the caller can run their own discrete intersection check at each
77
+ * step. Useful for arbitrary shape pairs that lack a closed-form swept test.
78
+ *
79
+ * `maxStepSize` controls the step granularity — smaller values produce more
80
+ * accurate detection but more iterations. Use the smallest dimension of the
81
+ * smaller collider as a sensible default.
82
+ *
83
+ * Always yields at least 2 snapshots (t=0 and t=1), even for zero-length
84
+ * deltas.
85
+ */
86
+ export declare function substepSweep(fromX: number, fromY: number, deltaX: number, deltaY: number, maxStepSize: number): IterableIterator<{
87
+ x: number;
88
+ y: number;
89
+ t: number;
90
+ }>;
@@ -0,0 +1,255 @@
1
+ import { Rectangle } from './Rectangle.js';
2
+
3
+ // ---------------------------------------------------------------------------
4
+ // sweepRectangle — AABB vs AABB slab method
5
+ // ---------------------------------------------------------------------------
6
+ /**
7
+ * Swept axis-aligned box vs. axis-aligned box.
8
+ *
9
+ * Uses the separating-axis slab method: for each axis we compute the entry
10
+ * and exit times of the moving box's slab vs the static box's slab, then
11
+ * combine. `t` is the fraction of the requested move at which first contact
12
+ * occurs (0 = already overlapping at start, 1 = just barely reaches).
13
+ *
14
+ * Already-overlapping case (tEntry < 0 overall): returns `t = 0` with the
15
+ * normal of the deepest-penetration axis, allowing callers to handle the
16
+ * "I'm already inside" situation without a separate discrete test.
17
+ */
18
+ function sweepRectangle(moving, deltaX, deltaY, target) {
19
+ const movMinX = moving.x;
20
+ const movMaxX = moving.x + moving.width;
21
+ const movMinY = moving.y;
22
+ const movMaxY = moving.y + moving.height;
23
+ const tarMinX = target.x;
24
+ const tarMaxX = target.x + target.width;
25
+ const tarMinY = target.y;
26
+ const tarMaxY = target.y + target.height;
27
+ // X axis
28
+ let tEntryX = -Infinity;
29
+ let tExitX = Infinity;
30
+ if (deltaX > 0) {
31
+ tEntryX = (tarMinX - movMaxX) / deltaX;
32
+ tExitX = (tarMaxX - movMinX) / deltaX;
33
+ }
34
+ else if (deltaX < 0) {
35
+ tEntryX = (tarMaxX - movMinX) / deltaX;
36
+ tExitX = (tarMinX - movMaxX) / deltaX;
37
+ }
38
+ else if (movMaxX <= tarMinX || movMinX >= tarMaxX) {
39
+ // No movement on X and no static overlap — can never collide
40
+ return null;
41
+ }
42
+ // Y axis
43
+ let tEntryY = -Infinity;
44
+ let tExitY = Infinity;
45
+ if (deltaY > 0) {
46
+ tEntryY = (tarMinY - movMaxY) / deltaY;
47
+ tExitY = (tarMaxY - movMinY) / deltaY;
48
+ }
49
+ else if (deltaY < 0) {
50
+ tEntryY = (tarMaxY - movMinY) / deltaY;
51
+ tExitY = (tarMinY - movMaxY) / deltaY;
52
+ }
53
+ else if (movMaxY <= tarMinY || movMinY >= tarMaxY) {
54
+ // No movement on Y and no static overlap — can never collide
55
+ return null;
56
+ }
57
+ const tEntry = Math.max(tEntryX, tEntryY);
58
+ const tExit = Math.min(tExitX, tExitY);
59
+ // No overlap window
60
+ if (tEntry > tExit || tExit < 0 || tEntry > 1) {
61
+ return null;
62
+ }
63
+ const t = Math.max(0, tEntry);
64
+ const hitX = moving.x + deltaX * t;
65
+ const hitY = moving.y + deltaY * t;
66
+ // Normal is on the axis whose slab entry was latest.
67
+ // Already-overlapping: use the deepest-penetration axis normal.
68
+ let normalX = 0;
69
+ let normalY = 0;
70
+ if (tEntry <= 0) {
71
+ // Already overlapping — pick the axis with least penetration
72
+ const overlapX = Math.min(movMaxX - tarMinX, tarMaxX - movMinX);
73
+ const overlapY = Math.min(movMaxY - tarMinY, tarMaxY - movMinY);
74
+ if (overlapX < overlapY) {
75
+ normalX = movMinX < tarMinX ? -1 : 1;
76
+ }
77
+ else {
78
+ normalY = movMinY < tarMinY ? -1 : 1;
79
+ }
80
+ }
81
+ else if (tEntryX > tEntryY) {
82
+ // X axis had the latest entry
83
+ normalX = deltaX > 0 ? -1 : 1;
84
+ }
85
+ else {
86
+ // Y axis had the latest entry
87
+ normalY = deltaY > 0 ? -1 : 1;
88
+ }
89
+ return { t, x: hitX, y: hitY, normalX, normalY };
90
+ }
91
+ // ---------------------------------------------------------------------------
92
+ // sweepCircleVsRectangle — expanded-AABB simple fallback (V1)
93
+ // ---------------------------------------------------------------------------
94
+ /**
95
+ * Swept circle vs. axis-aligned box.
96
+ *
97
+ * **V1 implementation** uses the simple Minkowski expansion fallback:
98
+ * the target rectangle is expanded by `circle.radius` on all sides, then
99
+ * `sweepRectangle` is run treating the circle centre as a zero-sized moving
100
+ * box. This over-collides at rectangle corners (the circle collides with the
101
+ * expanded-rect's flat face when geometrically it should curve around the
102
+ * corner), producing slightly early hits in corner-quadrant trajectories —
103
+ * a known and acceptable accuracy trade-off for V1.
104
+ *
105
+ * TODO (V2): Replace with the full Minkowski rounded-rectangle formulation
106
+ * that handles the four corner quadrants with per-corner circle-vs-circle
107
+ * sub-tests.
108
+ */
109
+ function sweepCircleVsRectangle(moving, deltaX, deltaY, target) {
110
+ const r = moving.radius;
111
+ // Expanded target: grow each side by the circle radius
112
+ const expanded = new Rectangle(target.x - r, target.y - r, target.width + r * 2, target.height + r * 2);
113
+ // Treat the circle centre as a zero-sized moving box
114
+ const centreBox = new Rectangle(moving.x, moving.y, 0, 0);
115
+ return sweepRectangle(centreBox, deltaX, deltaY, expanded);
116
+ }
117
+ // ---------------------------------------------------------------------------
118
+ // sweepCircleVsCircle — quadratic equation
119
+ // ---------------------------------------------------------------------------
120
+ /**
121
+ * Swept circle vs. stationary circle.
122
+ *
123
+ * Solves `|(moving.centre + delta*t) − target.centre|² = (r1+r2)²` for t,
124
+ * yielding a quadratic. Returns the smaller root if it is in [0, 1].
125
+ *
126
+ * Already-overlapping case: returns `{ t: 0 }` with the normal pointing from
127
+ * target → moving (or an arbitrary normal if both centres coincide).
128
+ */
129
+ function sweepCircleVsCircle(moving, deltaX, deltaY, target) {
130
+ const dx = moving.x - target.x;
131
+ const dy = moving.y - target.y;
132
+ const r = moving.radius + target.radius;
133
+ const a = deltaX * deltaX + deltaY * deltaY;
134
+ const b = 2 * (dx * deltaX + dy * deltaY);
135
+ const c = dx * dx + dy * dy - r * r;
136
+ // Already overlapping at start
137
+ if (c <= 0) {
138
+ const dist = Math.sqrt(dx * dx + dy * dy);
139
+ const normalX = dist > 0 ? dx / dist : 1;
140
+ const normalY = dist > 0 ? dy / dist : 0;
141
+ return { t: 0, x: moving.x, y: moving.y, normalX, normalY };
142
+ }
143
+ // No movement
144
+ if (a === 0) {
145
+ return null;
146
+ }
147
+ const disc = b * b - 4 * a * c;
148
+ if (disc < 0) {
149
+ return null;
150
+ }
151
+ const t = (-b - Math.sqrt(disc)) / (2 * a);
152
+ if (t < 0 || t > 1) {
153
+ return null;
154
+ }
155
+ const hitX = moving.x + deltaX * t;
156
+ const hitY = moving.y + deltaY * t;
157
+ // Normal points from target centre → hit circle centre
158
+ const normalX = (hitX - target.x) / r;
159
+ const normalY = (hitY - target.y) / r;
160
+ return { t, x: hitX, y: hitY, normalX, normalY };
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Batch helpers — sweep a shape against multiple targets
164
+ // ---------------------------------------------------------------------------
165
+ /**
166
+ * Returns the earliest `SweptHit` against an array of rectangle targets, or
167
+ * `null` if none are hit.
168
+ *
169
+ * Optimisation: before testing each target individually the swept AABB of the
170
+ * moving rectangle is computed once; targets whose AABB does not overlap the
171
+ * swept AABB are skipped.
172
+ */
173
+ function sweepRectangleAgainst(moving, deltaX, deltaY, targets) {
174
+ if (targets.length === 0) {
175
+ return null;
176
+ }
177
+ // Swept AABB of the moving rectangle (broad-phase skip)
178
+ const sweptMinX = Math.min(moving.x, moving.x + deltaX);
179
+ const sweptMaxX = Math.max(moving.x + moving.width, moving.x + moving.width + deltaX);
180
+ const sweptMinY = Math.min(moving.y, moving.y + deltaY);
181
+ const sweptMaxY = Math.max(moving.y + moving.height, moving.y + moving.height + deltaY);
182
+ let earliest = null;
183
+ for (const target of targets) {
184
+ // Broad-phase: skip if swept AABB doesn't overlap target AABB
185
+ if (sweptMaxX <= target.x
186
+ || sweptMinX >= target.x + target.width
187
+ || sweptMaxY <= target.y
188
+ || sweptMinY >= target.y + target.height) {
189
+ continue;
190
+ }
191
+ const hit = sweepRectangle(moving, deltaX, deltaY, target);
192
+ if (hit !== null && (earliest === null || hit.t < earliest.t)) {
193
+ earliest = hit;
194
+ }
195
+ }
196
+ return earliest;
197
+ }
198
+ /**
199
+ * Returns the earliest `SweptHit` against an array of circle targets, or
200
+ * `null` if none are hit.
201
+ *
202
+ * Optimisation: the swept AABB of the moving circle is computed once and used
203
+ * to skip targets that cannot possibly be reached.
204
+ */
205
+ function sweepCircleAgainst(moving, deltaX, deltaY, targets) {
206
+ if (targets.length === 0) {
207
+ return null;
208
+ }
209
+ // Swept AABB of the moving circle
210
+ const sweptMinX = Math.min(moving.x, moving.x + deltaX) - moving.radius;
211
+ const sweptMaxX = Math.max(moving.x, moving.x + deltaX) + moving.radius;
212
+ const sweptMinY = Math.min(moving.y, moving.y + deltaY) - moving.radius;
213
+ const sweptMaxY = Math.max(moving.y, moving.y + deltaY) + moving.radius;
214
+ let earliest = null;
215
+ for (const target of targets) {
216
+ // Broad-phase: skip if swept AABB doesn't overlap target's AABB
217
+ if (sweptMaxX <= target.x - target.radius
218
+ || sweptMinX >= target.x + target.radius
219
+ || sweptMaxY <= target.y - target.radius
220
+ || sweptMinY >= target.y + target.radius) {
221
+ continue;
222
+ }
223
+ const hit = sweepCircleVsCircle(moving, deltaX, deltaY, target);
224
+ if (hit !== null && (earliest === null || hit.t < earliest.t)) {
225
+ earliest = hit;
226
+ }
227
+ }
228
+ return earliest;
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // substepSweep — generic fallback iterator
232
+ // ---------------------------------------------------------------------------
233
+ /**
234
+ * Generator that yields evenly-spaced position snapshots along a movement
235
+ * vector so the caller can run their own discrete intersection check at each
236
+ * step. Useful for arbitrary shape pairs that lack a closed-form swept test.
237
+ *
238
+ * `maxStepSize` controls the step granularity — smaller values produce more
239
+ * accurate detection but more iterations. Use the smallest dimension of the
240
+ * smaller collider as a sensible default.
241
+ *
242
+ * Always yields at least 2 snapshots (t=0 and t=1), even for zero-length
243
+ * deltas.
244
+ */
245
+ function* substepSweep(fromX, fromY, deltaX, deltaY, maxStepSize) {
246
+ const length = Math.hypot(deltaX, deltaY);
247
+ const stepCount = Math.max(1, Math.ceil(length / maxStepSize));
248
+ for (let i = 0; i <= stepCount; i++) {
249
+ const t = i / stepCount;
250
+ yield { x: fromX + deltaX * t, y: fromY + deltaY * t, t };
251
+ }
252
+ }
253
+
254
+ export { substepSweep, sweepCircleAgainst, sweepCircleVsCircle, sweepCircleVsRectangle, sweepRectangle, sweepRectangleAgainst };
255
+ //# sourceMappingURL=swept-collision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swept-collision.js","sources":["../../../../src/math/swept-collision.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}