@codexo/exojs 0.6.10 → 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 +103 -0
- package/dist/esm/animation/Easing.d.ts +45 -0
- package/dist/esm/animation/Easing.js +112 -0
- package/dist/esm/animation/Easing.js.map +1 -0
- package/dist/esm/animation/Tween.d.ts +100 -0
- package/dist/esm/animation/Tween.js +270 -0
- package/dist/esm/animation/Tween.js.map +1 -0
- package/dist/esm/animation/TweenManager.d.ts +30 -0
- package/dist/esm/animation/TweenManager.js +65 -0
- package/dist/esm/animation/TweenManager.js.map +1 -0
- package/dist/esm/animation/index.d.ts +4 -0
- package/dist/esm/animation/types.d.ts +10 -0
- package/dist/esm/animation/types.js +11 -0
- package/dist/esm/animation/types.js.map +1 -0
- package/dist/esm/core/Application.d.ts +2 -0
- package/dist/esm/core/Application.js +4 -0
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/math/index.d.ts +1 -0
- package/dist/esm/math/swept-collision.d.ts +90 -0
- package/dist/esm/math/swept-collision.js +255 -0
- package/dist/esm/math/swept-collision.js.map +1 -0
- package/dist/exo.esm.js +700 -1
- package/dist/exo.esm.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Tween } from './Tween';
|
|
2
|
+
export declare class TweenManager {
|
|
3
|
+
private _tweens;
|
|
4
|
+
private _destroyed;
|
|
5
|
+
/**
|
|
6
|
+
* Create a new Tween targeting `target`, register it with this manager, and
|
|
7
|
+
* return it. Call .to(...).start() on the result to begin animating.
|
|
8
|
+
*/
|
|
9
|
+
create<T extends object>(target: T): Tween<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Explicitly add a stand-alone Tween (created via `new Tween(target)`)
|
|
12
|
+
* to this manager so it participates in the update loop.
|
|
13
|
+
*/
|
|
14
|
+
add(tween: Tween): this;
|
|
15
|
+
/** Remove a tween from the manager. Called automatically on stop/complete. */
|
|
16
|
+
remove(tween: Tween): this;
|
|
17
|
+
/**
|
|
18
|
+
* Advance all active tweens by deltaSeconds. Called once per frame by
|
|
19
|
+
* Application.update(). Uses a snapshot of the list so that callbacks that
|
|
20
|
+
* add or remove tweens do not corrupt mid-iteration.
|
|
21
|
+
*/
|
|
22
|
+
update(deltaSeconds: number): this;
|
|
23
|
+
/**
|
|
24
|
+
* Remove all tweens immediately. No callbacks (onComplete etc.) fire.
|
|
25
|
+
* The tweens' states are left as-is; they are simply evicted from the list.
|
|
26
|
+
*/
|
|
27
|
+
clear(): this;
|
|
28
|
+
/** Tear down the manager. Clears tweens and makes subsequent updates no-ops. */
|
|
29
|
+
destroy(): void;
|
|
30
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Tween } from './Tween.js';
|
|
2
|
+
|
|
3
|
+
class TweenManager {
|
|
4
|
+
_tweens = [];
|
|
5
|
+
_destroyed = false;
|
|
6
|
+
/**
|
|
7
|
+
* Create a new Tween targeting `target`, register it with this manager, and
|
|
8
|
+
* return it. Call .to(...).start() on the result to begin animating.
|
|
9
|
+
*/
|
|
10
|
+
create(target) {
|
|
11
|
+
const tween = new Tween(target);
|
|
12
|
+
tween._attachManager(this);
|
|
13
|
+
this._tweens.push(tween);
|
|
14
|
+
return tween;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Explicitly add a stand-alone Tween (created via `new Tween(target)`)
|
|
18
|
+
* to this manager so it participates in the update loop.
|
|
19
|
+
*/
|
|
20
|
+
add(tween) {
|
|
21
|
+
tween._attachManager(this);
|
|
22
|
+
if (!this._tweens.includes(tween)) {
|
|
23
|
+
this._tweens.push(tween);
|
|
24
|
+
}
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
/** Remove a tween from the manager. Called automatically on stop/complete. */
|
|
28
|
+
remove(tween) {
|
|
29
|
+
const index = this._tweens.indexOf(tween);
|
|
30
|
+
if (index !== -1) {
|
|
31
|
+
this._tweens.splice(index, 1);
|
|
32
|
+
}
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Advance all active tweens by deltaSeconds. Called once per frame by
|
|
37
|
+
* Application.update(). Uses a snapshot of the list so that callbacks that
|
|
38
|
+
* add or remove tweens do not corrupt mid-iteration.
|
|
39
|
+
*/
|
|
40
|
+
update(deltaSeconds) {
|
|
41
|
+
if (this._destroyed)
|
|
42
|
+
return this;
|
|
43
|
+
const snapshot = this._tweens.slice();
|
|
44
|
+
for (const tween of snapshot) {
|
|
45
|
+
tween.update(deltaSeconds);
|
|
46
|
+
}
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Remove all tweens immediately. No callbacks (onComplete etc.) fire.
|
|
51
|
+
* The tweens' states are left as-is; they are simply evicted from the list.
|
|
52
|
+
*/
|
|
53
|
+
clear() {
|
|
54
|
+
this._tweens = [];
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
/** Tear down the manager. Clears tweens and makes subsequent updates no-ops. */
|
|
58
|
+
destroy() {
|
|
59
|
+
this.clear();
|
|
60
|
+
this._destroyed = true;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export { TweenManager };
|
|
65
|
+
//# sourceMappingURL=TweenManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TweenManager.js","sources":["../../../../src/animation/TweenManager.ts"],"sourcesContent":[null],"names":[],"mappings":";;MAEa,YAAY,CAAA;IACb,OAAO,GAAiB,EAAE;IAC1B,UAAU,GAAG,KAAK;AAE1B;;;AAGG;AACI,IAAA,MAAM,CAAmB,MAAS,EAAA;AACrC,QAAA,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC;AAC/B,QAAA,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;AAC1B,QAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAc,CAAC;AAEjC,QAAA,OAAO,KAAK;IAChB;AAEA;;;AAGG;AACI,IAAA,GAAG,CAAC,KAAY,EAAA;AACnB,QAAA,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;QAE1B,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;AAC/B,YAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAC5B;AAEA,QAAA,OAAO,IAAI;IACf;;AAGO,IAAA,MAAM,CAAC,KAAY,EAAA;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;AAEzC,QAAA,IAAI,KAAK,KAAK,EAAE,EAAE;YACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACjC;AAEA,QAAA,OAAO,IAAI;IACf;AAEA;;;;AAIG;AACI,IAAA,MAAM,CAAC,YAAoB,EAAA;QAC9B,IAAI,IAAI,CAAC,UAAU;AAAE,YAAA,OAAO,IAAI;QAEhC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE;AAErC,QAAA,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE;AAC1B,YAAA,KAAK,CAAC,MAAM,CAAC,YAAY,CAAC;QAC9B;AAEA,QAAA,OAAO,IAAI;IACf;AAEA;;;AAGG;IACI,KAAK,GAAA;AACR,QAAA,IAAI,CAAC,OAAO,GAAG,EAAE;AAEjB,QAAA,OAAO,IAAI;IACf;;IAGO,OAAO,GAAA;QACV,IAAI,CAAC,KAAK,EAAE;AACZ,QAAA,IAAI,CAAC,UAAU,GAAG,IAAI;IAC1B;AACH;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { EasingFunction } from './Easing';
|
|
2
|
+
export declare enum TweenState {
|
|
3
|
+
Idle = "idle",
|
|
4
|
+
Active = "active",
|
|
5
|
+
Paused = "paused",
|
|
6
|
+
Complete = "complete",
|
|
7
|
+
Stopped = "stopped"
|
|
8
|
+
}
|
|
9
|
+
export type TweenLifecycleCallback = () => void;
|
|
10
|
+
export type TweenUpdateCallback = (progress: number) => void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var TweenState;
|
|
2
|
+
(function (TweenState) {
|
|
3
|
+
TweenState["Idle"] = "idle";
|
|
4
|
+
TweenState["Active"] = "active";
|
|
5
|
+
TweenState["Paused"] = "paused";
|
|
6
|
+
TweenState["Complete"] = "complete";
|
|
7
|
+
TweenState["Stopped"] = "stopped";
|
|
8
|
+
})(TweenState || (TweenState = {}));
|
|
9
|
+
|
|
10
|
+
export { TweenState };
|
|
11
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../../../../src/animation/types.ts"],"sourcesContent":[null],"names":[],"mappings":"IAEY;AAAZ,CAAA,UAAY,UAAU,EAAA;AAClB,IAAA,UAAA,CAAA,MAAA,CAAA,GAAA,MAAa;AACb,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,UAAA,CAAA,QAAA,CAAA,GAAA,QAAiB;AACjB,IAAA,UAAA,CAAA,UAAA,CAAA,GAAA,UAAqB;AACrB,IAAA,UAAA,CAAA,SAAA,CAAA,GAAA,SAAmB;AACvB,CAAC,EANW,UAAU,KAAV,UAAU,GAAA,EAAA,CAAA,CAAA;;;;"}
|
|
@@ -2,6 +2,7 @@ import { Capabilities } from './capabilities';
|
|
|
2
2
|
import { SceneManager } from './SceneManager';
|
|
3
3
|
import { InputManager } from '@/input/InputManager';
|
|
4
4
|
import { Loader } from '@/resources/Loader';
|
|
5
|
+
import { TweenManager } from '@/animation/TweenManager';
|
|
5
6
|
import { Signal } from './Signal';
|
|
6
7
|
import { Color } from './Color';
|
|
7
8
|
import type { Time } from './Time';
|
|
@@ -47,6 +48,7 @@ export declare class Application {
|
|
|
47
48
|
readonly loader: Loader;
|
|
48
49
|
readonly inputManager: InputManager;
|
|
49
50
|
readonly sceneManager: SceneManager;
|
|
51
|
+
readonly tweens: TweenManager;
|
|
50
52
|
readonly onResize: Signal<[number, number, Application]>;
|
|
51
53
|
private readonly _updateHandler;
|
|
52
54
|
private readonly _startupClock;
|
|
@@ -5,6 +5,7 @@ import { WebGl2Backend } from '../rendering/webgl2/WebGl2Backend.js';
|
|
|
5
5
|
import { WebGpuBackend } from '../rendering/webgpu/WebGpuBackend.js';
|
|
6
6
|
import { InputManager } from '../input/InputManager.js';
|
|
7
7
|
import { Loader } from '../resources/Loader.js';
|
|
8
|
+
import { TweenManager } from '../animation/TweenManager.js';
|
|
8
9
|
import { Signal } from './Signal.js';
|
|
9
10
|
import { Color } from './Color.js';
|
|
10
11
|
|
|
@@ -49,6 +50,7 @@ class Application {
|
|
|
49
50
|
loader;
|
|
50
51
|
inputManager;
|
|
51
52
|
sceneManager;
|
|
53
|
+
tweens = new TweenManager();
|
|
52
54
|
onResize = new Signal();
|
|
53
55
|
_updateHandler;
|
|
54
56
|
_startupClock = new Clock();
|
|
@@ -140,6 +142,7 @@ class Application {
|
|
|
140
142
|
const frameStart = performance.now();
|
|
141
143
|
this.backend.resetStats();
|
|
142
144
|
this.inputManager.update();
|
|
145
|
+
this.tweens.update(frameDelta.seconds);
|
|
143
146
|
const runtimeView = this.backend.view;
|
|
144
147
|
if (runtimeView && typeof runtimeView.update === 'function') {
|
|
145
148
|
runtimeView.update(frameDelta.milliseconds);
|
|
@@ -175,6 +178,7 @@ class Application {
|
|
|
175
178
|
this.stop();
|
|
176
179
|
this.loader.destroy();
|
|
177
180
|
this.inputManager.destroy();
|
|
181
|
+
this.tweens.destroy();
|
|
178
182
|
this._backend.destroy();
|
|
179
183
|
this.sceneManager.destroy();
|
|
180
184
|
this._startupClock.destroy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Application.js","sources":["../../../../src/core/Application.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Application.js","sources":["../../../../src/core/Application.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
export { Ease } from './animation/Easing.js';
|
|
2
|
+
export { Tween } from './animation/Tween.js';
|
|
3
|
+
export { TweenManager } from './animation/TweenManager.js';
|
|
4
|
+
export { TweenState } from './animation/types.js';
|
|
1
5
|
export { canvasSourceToDataUrl, emptyArrayBuffer, getCanvasSourceSize, getPreciseTime, getTextureSourceSize, hours, milliseconds, minutes, noop, rand, removeArrayItems, seconds, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio } from './core/utils.js';
|
|
2
6
|
export { Application, ApplicationStatus } from './core/Application.js';
|
|
3
7
|
export { Bounds } from './core/Bounds.js';
|
|
@@ -54,6 +58,7 @@ export { Random } from './math/Random.js';
|
|
|
54
58
|
export { Segment } from './math/Segment.js';
|
|
55
59
|
export { Size } from './math/Size.js';
|
|
56
60
|
export { PolarVector } from './math/PolarVector.js';
|
|
61
|
+
export { substepSweep, sweepCircleAgainst, sweepCircleVsCircle, sweepCircleVsRectangle, sweepRectangle, sweepRectangleAgainst } from './math/swept-collision.js';
|
|
57
62
|
export { ColorAffector } from './particles/affectors/ColorAffector.js';
|
|
58
63
|
export { ForceAffector } from './particles/affectors/ForceAffector.js';
|
|
59
64
|
export { ScaleAffector } from './particles/affectors/ScaleAffector.js';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/esm/math/index.d.ts
CHANGED
|
@@ -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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"}
|