@codexo/exojs 0.6.7 → 0.6.8
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 +51 -0
- package/README.md +0 -36
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/exo.esm.js +1 -470
- package/dist/exo.esm.js.map +1 -1
- package/package.json +1 -9
- package/dist/esm/physics/RapierPhysicsWorld.d.ts +0 -136
- package/dist/esm/physics/RapierPhysicsWorld.js +0 -475
- package/dist/esm/physics/RapierPhysicsWorld.js.map +0 -1
- package/dist/esm/physics/index.d.ts +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,57 @@ 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.8] - 2026-05-02
|
|
8
|
+
|
|
9
|
+
> **Heads-up — breaking change despite the patch number.** Removes
|
|
10
|
+
> the optional Rapier physics integration in its entirety. Pre-1.0
|
|
11
|
+
> SemVer permits breaking changes within the 0.x.y line; we kept
|
|
12
|
+
> the minor digit unchanged because the integration was opt-in and
|
|
13
|
+
> usage outside the engine is presumed minimal.
|
|
14
|
+
|
|
15
|
+
### Removed
|
|
16
|
+
|
|
17
|
+
- **`createRapierPhysicsWorld` factory and the `RapierPhysicsWorld`
|
|
18
|
+
/ `RapierPhysicsBinding` classes.** Plus the entire associated
|
|
19
|
+
type surface (`PhysicsBodyOptions`, `PhysicsBodyType`,
|
|
20
|
+
`PhysicsBoxShape`, `PhysicsCircleShape`, `PhysicsColliderShape`,
|
|
21
|
+
`PhysicsCollisionFilter`, `PhysicsSyncMode`, `RapierModuleLoader`,
|
|
22
|
+
`RapierPhysicsDebugDrawOptions`, `RapierPhysicsEvent`,
|
|
23
|
+
`RapierPhysicsWorldOptions`).
|
|
24
|
+
- **`@dimforge/rapier2d-compat` peerDependency.** Removed from
|
|
25
|
+
`package.json` along with the `peerDependenciesMeta` entry that
|
|
26
|
+
marked it optional.
|
|
27
|
+
- **README's "Optional Rapier Physics" section** and the
|
|
28
|
+
feature-list bullets that mentioned it.
|
|
29
|
+
- **`src/physics/`** and **`test/physics/`** directories deleted.
|
|
30
|
+
|
|
31
|
+
### Migration
|
|
32
|
+
|
|
33
|
+
Apps that depended on `createRapierPhysicsWorld` need to integrate
|
|
34
|
+
Rapier (or any other physics library) directly in their own code
|
|
35
|
+
without library involvement. The adapter was always intentionally
|
|
36
|
+
narrow — it bound Rapier bodies to scene nodes from the outside,
|
|
37
|
+
no rendering / application / core scene code referenced physics.
|
|
38
|
+
Removing it is therefore mechanical for downstream consumers:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// Before (≤ 0.6.7)
|
|
42
|
+
import { createRapierPhysicsWorld } from '@codexo/exojs';
|
|
43
|
+
const physics = await createRapierPhysicsWorld({ gravityY: 9.81 });
|
|
44
|
+
|
|
45
|
+
// After (0.6.8+) — pull Rapier directly:
|
|
46
|
+
import RAPIER from '@dimforge/rapier2d-compat';
|
|
47
|
+
await RAPIER.init();
|
|
48
|
+
const physics = new RAPIER.World({ x: 0, y: 9.81 });
|
|
49
|
+
// Sync bodies to your scene-node positions in your app's update loop.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The motivation: ExoJS doesn't want to be a thin wrapper around
|
|
53
|
+
Rapier's API, and keeping the integration around tied the library
|
|
54
|
+
to a specific physics library forever. Removing it cleans the
|
|
55
|
+
boundary — ExoJS is rendering + scene + input; physics is the
|
|
56
|
+
user's choice.
|
|
57
|
+
|
|
7
58
|
## [0.6.7] - 2026-05-02
|
|
8
59
|
|
|
9
60
|
Touch / multi-touch / pointer support, fully unified — no separate
|
package/README.md
CHANGED
|
@@ -14,7 +14,6 @@ ExoJS is **pre-1.0**. The public API is still under active design — scene grap
|
|
|
14
14
|
- Practical visuals: filters, masks, render passes, cache-as-bitmap
|
|
15
15
|
- Gameplay tools: animated sprites, scene stacking, camera helpers, audio sprites
|
|
16
16
|
- Performance visibility with built-in render stats and benchmark harness
|
|
17
|
-
- Optional Rapier physics integration without forcing physics on every app
|
|
18
17
|
|
|
19
18
|
## What Is Shipped Today
|
|
20
19
|
|
|
@@ -25,7 +24,6 @@ ExoJS is **pre-1.0**. The public API is still under active design — scene grap
|
|
|
25
24
|
- View/camera helpers (`follow`, bounds clamp, shake, zoom)
|
|
26
25
|
- Rendering composition primitives (`RenderTexture`, `RenderTargetPass`, filter chains, visual masks, cache-as-bitmap)
|
|
27
26
|
- Render stats (`submittedNodes`, `culledNodes`, `drawCalls`, `batches`, `renderPasses`, ...)
|
|
28
|
-
- Optional Rapier adapter (`createRapierPhysicsWorld`)
|
|
29
27
|
|
|
30
28
|
## Installation
|
|
31
29
|
|
|
@@ -98,40 +96,6 @@ new Application({ backend: { type: 'webgl2' } });
|
|
|
98
96
|
new Application({ backend: { type: 'auto' } });
|
|
99
97
|
```
|
|
100
98
|
|
|
101
|
-
## Optional Rapier Physics
|
|
102
|
-
|
|
103
|
-
Rapier integration is opt-in and loaded only when you use it.
|
|
104
|
-
|
|
105
|
-
```ts
|
|
106
|
-
import { createRapierPhysicsWorld } from '@codexo/exojs';
|
|
107
|
-
|
|
108
|
-
const physics = await createRapierPhysicsWorld({ gravityY: 9.81 });
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
If Rapier is unavailable, creation fails with a clear setup error.
|
|
112
|
-
|
|
113
|
-
### Physics scope policy
|
|
114
|
-
|
|
115
|
-
ExoJS ships **one** physics adapter: Rapier. The integration is intentionally
|
|
116
|
-
narrow:
|
|
117
|
-
|
|
118
|
-
- Physics is **optional**. `@dimforge/rapier2d-compat` is a peer dependency
|
|
119
|
-
marked `optional`. Apps that do not call `createRapierPhysicsWorld` never
|
|
120
|
-
load it and never pay for it at runtime.
|
|
121
|
-
- Rendering, application, and core scene code **do not** depend on physics.
|
|
122
|
-
The adapter binds Rapier bodies to scene nodes from the outside; the core
|
|
123
|
-
has no knowledge of physics.
|
|
124
|
-
- ExoJS is **not** a physics-engine abstraction layer. There is no
|
|
125
|
-
`PhysicsWorld` interface that spans multiple backends, and no plan to
|
|
126
|
-
add one. If you need a different physics library, integrate it directly
|
|
127
|
-
in your app code without library involvement.
|
|
128
|
-
- A second physics adapter (Box2D, Matter.js, Planck, etc.) is **not** on
|
|
129
|
-
the 1.0 roadmap and will not be accepted as a contribution. The honesty
|
|
130
|
-
rule that applies to rendering backends applies here too: one chosen
|
|
131
|
-
physics, not a fake-universal physics layer.
|
|
132
|
-
|
|
133
|
-
For full integration details see [docs/physics/rapier-integration.md](docs/physics/rapier-integration.md).
|
|
134
|
-
|
|
135
99
|
## Examples
|
|
136
100
|
|
|
137
101
|
The runnable live site (Astro + Lit + Monaco preview) lives in [`examples/`](examples/README.md) and is deployed as the repository's GitHub Pages site at <https://exoridus.github.io/ExoJS/>.
|
package/dist/esm/index.d.ts
CHANGED
package/dist/esm/index.js
CHANGED
|
@@ -129,5 +129,4 @@ export { VideoFactory } from './resources/factories/VideoFactory.js';
|
|
|
129
129
|
export { BinaryFactory } from './resources/factories/BinaryFactory.js';
|
|
130
130
|
export { VttFactory } from './resources/factories/VttFactory.js';
|
|
131
131
|
export { WasmFactory } from './resources/factories/WasmFactory.js';
|
|
132
|
-
export { RapierPhysicsBinding, RapierPhysicsWorld, createRapierPhysicsWorld } from './physics/RapierPhysicsWorld.js';
|
|
133
132
|
//# sourceMappingURL=index.js.map
|
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/exo.esm.js
CHANGED
|
@@ -18519,474 +18519,5 @@ class IndexedDbStore {
|
|
|
18519
18519
|
}
|
|
18520
18520
|
}
|
|
18521
18521
|
|
|
18522
|
-
|
|
18523
|
-
const maxCollisionGroup = 15;
|
|
18524
|
-
const fullGroupMask = 0xFFFF;
|
|
18525
|
-
const defaultDeltaSeconds = 1 / 60;
|
|
18526
|
-
const defaultDebugDrawOptions = {
|
|
18527
|
-
lineWidth: 1,
|
|
18528
|
-
solidLineColor: new Color(64, 196, 255, 1),
|
|
18529
|
-
solidFillColor: new Color(64, 196, 255, 0.12),
|
|
18530
|
-
triggerLineColor: new Color(255, 180, 48, 1),
|
|
18531
|
-
triggerFillColor: new Color(255, 180, 48, 0.08),
|
|
18532
|
-
};
|
|
18533
|
-
const resolveRapierModule = (module) => {
|
|
18534
|
-
const rapier = module;
|
|
18535
|
-
const vector2 = rapier.Vector2;
|
|
18536
|
-
const worldConstructor = rapier.World;
|
|
18537
|
-
const eventQueueConstructor = rapier.EventQueue;
|
|
18538
|
-
const rigidBodyDescFactory = rapier.RigidBodyDesc;
|
|
18539
|
-
const colliderDescFactory = rapier.ColliderDesc;
|
|
18540
|
-
if (typeof vector2 !== 'function' || typeof worldConstructor !== 'function' || typeof eventQueueConstructor !== 'function') {
|
|
18541
|
-
throw new Error('Invalid Rapier module loader result. Expected Vector2, World, and EventQueue exports.');
|
|
18542
|
-
}
|
|
18543
|
-
if (typeof rigidBodyDescFactory !== 'object'
|
|
18544
|
-
|| rigidBodyDescFactory === null
|
|
18545
|
-
|| typeof colliderDescFactory !== 'object'
|
|
18546
|
-
|| colliderDescFactory === null) {
|
|
18547
|
-
throw new Error('Invalid Rapier module loader result. Expected RigidBodyDesc and ColliderDesc exports.');
|
|
18548
|
-
}
|
|
18549
|
-
const activeEvents = rapier.ActiveEvents;
|
|
18550
|
-
const activeCollisionEvents = typeof activeEvents?.COLLISION_EVENTS === 'number'
|
|
18551
|
-
? activeEvents.COLLISION_EVENTS
|
|
18552
|
-
: undefined;
|
|
18553
|
-
return {
|
|
18554
|
-
init: typeof rapier.init === 'function'
|
|
18555
|
-
? rapier.init
|
|
18556
|
-
: undefined,
|
|
18557
|
-
vector2: vector2,
|
|
18558
|
-
worldConstructor: worldConstructor,
|
|
18559
|
-
eventQueueConstructor: eventQueueConstructor,
|
|
18560
|
-
rigidBodyDescFactory: rigidBodyDescFactory,
|
|
18561
|
-
colliderDescFactory: colliderDescFactory,
|
|
18562
|
-
activeCollisionEvents,
|
|
18563
|
-
};
|
|
18564
|
-
};
|
|
18565
|
-
const defaultRapierModuleLoader = async () => {
|
|
18566
|
-
return await import(rapierModuleName);
|
|
18567
|
-
};
|
|
18568
|
-
const assertFiniteNumber = (value, label) => {
|
|
18569
|
-
if (!Number.isFinite(value)) {
|
|
18570
|
-
throw new Error(`${label} must be a finite number.`);
|
|
18571
|
-
}
|
|
18572
|
-
};
|
|
18573
|
-
const assertPositiveNumber = (value, label) => {
|
|
18574
|
-
assertFiniteNumber(value, label);
|
|
18575
|
-
if (value <= 0) {
|
|
18576
|
-
throw new Error(`${label} must be greater than zero.`);
|
|
18577
|
-
}
|
|
18578
|
-
};
|
|
18579
|
-
const assertGroup = (group, label) => {
|
|
18580
|
-
if (!Number.isInteger(group) || group < 0 || group > maxCollisionGroup) {
|
|
18581
|
-
throw new Error(`${label} must be an integer between 0 and ${maxCollisionGroup}.`);
|
|
18582
|
-
}
|
|
18583
|
-
};
|
|
18584
|
-
const toGroupMask = (groups, fallback) => {
|
|
18585
|
-
if (groups === undefined) {
|
|
18586
|
-
return fallback;
|
|
18587
|
-
}
|
|
18588
|
-
if (typeof groups === 'number') {
|
|
18589
|
-
assertGroup(groups, 'collision group');
|
|
18590
|
-
return 1 << groups;
|
|
18591
|
-
}
|
|
18592
|
-
if (groups.length === 0) {
|
|
18593
|
-
return 0;
|
|
18594
|
-
}
|
|
18595
|
-
return groups.reduce((mask, group, index) => {
|
|
18596
|
-
assertGroup(group, `collision groups[${index}]`);
|
|
18597
|
-
return mask | (1 << group);
|
|
18598
|
-
}, 0);
|
|
18599
|
-
};
|
|
18600
|
-
const toPackedCollisionGroups = (filter) => {
|
|
18601
|
-
const membershipMask = toGroupMask(filter?.membership, 1 << 0);
|
|
18602
|
-
const collisionMask = toGroupMask(filter?.collidesWith, fullGroupMask);
|
|
18603
|
-
return ((membershipMask & fullGroupMask) << 16) | (collisionMask & fullGroupMask);
|
|
18604
|
-
};
|
|
18605
|
-
const getOffset = (shape) => ({
|
|
18606
|
-
x: shape.offsetX ?? 0,
|
|
18607
|
-
y: shape.offsetY ?? 0,
|
|
18608
|
-
});
|
|
18609
|
-
const rotatePoint = (x, y, rotation) => {
|
|
18610
|
-
const cos = Math.cos(rotation);
|
|
18611
|
-
const sin = Math.sin(rotation);
|
|
18612
|
-
return {
|
|
18613
|
-
x: (x * cos) - (y * sin),
|
|
18614
|
-
y: (x * sin) + (y * cos),
|
|
18615
|
-
};
|
|
18616
|
-
};
|
|
18617
|
-
const assertShape = (shape) => {
|
|
18618
|
-
if (shape.type === 'box') {
|
|
18619
|
-
assertPositiveNumber(shape.width, 'Box width');
|
|
18620
|
-
assertPositiveNumber(shape.height, 'Box height');
|
|
18621
|
-
assertFiniteNumber(shape.offsetX ?? 0, 'Box offsetX');
|
|
18622
|
-
assertFiniteNumber(shape.offsetY ?? 0, 'Box offsetY');
|
|
18623
|
-
assertFiniteNumber(shape.offsetRotation ?? 0, 'Box offsetRotation');
|
|
18624
|
-
return;
|
|
18625
|
-
}
|
|
18626
|
-
assertPositiveNumber(shape.radius, 'Circle radius');
|
|
18627
|
-
assertFiniteNumber(shape.offsetX ?? 0, 'Circle offsetX');
|
|
18628
|
-
assertFiniteNumber(shape.offsetY ?? 0, 'Circle offsetY');
|
|
18629
|
-
};
|
|
18630
|
-
const assertBodyOptions = (options) => {
|
|
18631
|
-
assertShape(options.shape);
|
|
18632
|
-
assertFiniteNumber(options.friction ?? 0, 'friction');
|
|
18633
|
-
assertFiniteNumber(options.restitution ?? 0, 'restitution');
|
|
18634
|
-
assertFiniteNumber(options.density ?? 0, 'density');
|
|
18635
|
-
assertFiniteNumber(options.gravityScale ?? 1, 'gravityScale');
|
|
18636
|
-
assertFiniteNumber(options.linearDamping ?? 0, 'linearDamping');
|
|
18637
|
-
assertFiniteNumber(options.angularDamping ?? 0, 'angularDamping');
|
|
18638
|
-
toPackedCollisionGroups(options.collisionFilter);
|
|
18639
|
-
};
|
|
18640
|
-
class RapierPhysicsBinding {
|
|
18641
|
-
_world;
|
|
18642
|
-
_body;
|
|
18643
|
-
_collider;
|
|
18644
|
-
_syncMode;
|
|
18645
|
-
node;
|
|
18646
|
-
bodyType;
|
|
18647
|
-
shape;
|
|
18648
|
-
trigger;
|
|
18649
|
-
constructor(world, node, body, collider, options) {
|
|
18650
|
-
this._world = world;
|
|
18651
|
-
this.node = node;
|
|
18652
|
-
this._body = body;
|
|
18653
|
-
this._collider = collider;
|
|
18654
|
-
this.bodyType = options.type ?? 'dynamic';
|
|
18655
|
-
this.shape = options.shape;
|
|
18656
|
-
this.trigger = options.trigger ?? false;
|
|
18657
|
-
this._syncMode = options.syncMode ?? 'physicsToNode';
|
|
18658
|
-
}
|
|
18659
|
-
get bodyHandle() {
|
|
18660
|
-
return this._body.handle;
|
|
18661
|
-
}
|
|
18662
|
-
get colliderHandle() {
|
|
18663
|
-
return this._collider.handle;
|
|
18664
|
-
}
|
|
18665
|
-
getBody() {
|
|
18666
|
-
return this._body;
|
|
18667
|
-
}
|
|
18668
|
-
get syncMode() {
|
|
18669
|
-
return this._syncMode;
|
|
18670
|
-
}
|
|
18671
|
-
set syncMode(syncMode) {
|
|
18672
|
-
this._syncMode = syncMode;
|
|
18673
|
-
}
|
|
18674
|
-
get x() {
|
|
18675
|
-
return this._body.translation().x;
|
|
18676
|
-
}
|
|
18677
|
-
get y() {
|
|
18678
|
-
return this._body.translation().y;
|
|
18679
|
-
}
|
|
18680
|
-
get rotation() {
|
|
18681
|
-
return this._body.rotation();
|
|
18682
|
-
}
|
|
18683
|
-
setSyncMode(syncMode) {
|
|
18684
|
-
this._syncMode = syncMode;
|
|
18685
|
-
return this;
|
|
18686
|
-
}
|
|
18687
|
-
teleport(x, y, rotation = this.node.rotation) {
|
|
18688
|
-
this._world.writeBodyTransform(this._body, x, y, rotation, true);
|
|
18689
|
-
this.node.setPosition(x, y);
|
|
18690
|
-
this.node.setRotation(rotation);
|
|
18691
|
-
return this;
|
|
18692
|
-
}
|
|
18693
|
-
syncBodyFromNode(wakeUp = true) {
|
|
18694
|
-
this._world.writeBodyTransform(this._body, this.node.x, this.node.y, this.node.rotation, wakeUp);
|
|
18695
|
-
return this;
|
|
18696
|
-
}
|
|
18697
|
-
syncNodeFromBody() {
|
|
18698
|
-
const translation = this._body.translation();
|
|
18699
|
-
this.node.setPosition(translation.x, translation.y);
|
|
18700
|
-
this.node.setRotation(this._body.rotation());
|
|
18701
|
-
return this;
|
|
18702
|
-
}
|
|
18703
|
-
setCollisionFilter(filter) {
|
|
18704
|
-
const groups = toPackedCollisionGroups(filter);
|
|
18705
|
-
this._collider.setCollisionGroups(groups);
|
|
18706
|
-
this._collider.setSolverGroups(groups);
|
|
18707
|
-
return this;
|
|
18708
|
-
}
|
|
18709
|
-
destroy() {
|
|
18710
|
-
this._world.removeBinding(this);
|
|
18711
|
-
}
|
|
18712
|
-
}
|
|
18713
|
-
class RapierPhysicsWorld {
|
|
18714
|
-
onCollisionEnter = new Signal();
|
|
18715
|
-
onCollisionExit = new Signal();
|
|
18716
|
-
onTriggerEnter = new Signal();
|
|
18717
|
-
onTriggerExit = new Signal();
|
|
18718
|
-
_rapier;
|
|
18719
|
-
_world;
|
|
18720
|
-
_eventQueue;
|
|
18721
|
-
_bindings = new Set();
|
|
18722
|
-
_nodeBindings = new Map();
|
|
18723
|
-
_colliderBindings = new Map();
|
|
18724
|
-
constructor(rapier, world, eventQueue) {
|
|
18725
|
-
this._rapier = rapier;
|
|
18726
|
-
this._world = world;
|
|
18727
|
-
this._eventQueue = eventQueue;
|
|
18728
|
-
}
|
|
18729
|
-
static async create(options = {}) {
|
|
18730
|
-
const moduleLoader = options.moduleLoader ?? defaultRapierModuleLoader;
|
|
18731
|
-
let loadedModule = null;
|
|
18732
|
-
try {
|
|
18733
|
-
loadedModule = await moduleLoader();
|
|
18734
|
-
}
|
|
18735
|
-
catch (error) {
|
|
18736
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
18737
|
-
throw new Error(`Rapier physics module is unavailable. Install "${rapierModuleName}" or provide a custom module loader. Original error: ${message}`, { cause: error });
|
|
18738
|
-
}
|
|
18739
|
-
const rapier = resolveRapierModule(loadedModule);
|
|
18740
|
-
if (typeof rapier.init === 'function') {
|
|
18741
|
-
await rapier.init();
|
|
18742
|
-
}
|
|
18743
|
-
const gravityX = options.gravityX ?? 0;
|
|
18744
|
-
const gravityY = options.gravityY ?? 9.81;
|
|
18745
|
-
assertFiniteNumber(gravityX, 'gravityX');
|
|
18746
|
-
assertFiniteNumber(gravityY, 'gravityY');
|
|
18747
|
-
const world = new rapier.worldConstructor(new rapier.vector2(gravityX, gravityY));
|
|
18748
|
-
const eventQueue = new rapier.eventQueueConstructor(true);
|
|
18749
|
-
return new RapierPhysicsWorld(rapier, world, eventQueue);
|
|
18750
|
-
}
|
|
18751
|
-
get gravity() {
|
|
18752
|
-
return {
|
|
18753
|
-
x: this._world.gravity.x,
|
|
18754
|
-
y: this._world.gravity.y,
|
|
18755
|
-
};
|
|
18756
|
-
}
|
|
18757
|
-
setGravity(x, y) {
|
|
18758
|
-
assertFiniteNumber(x, 'gravityX');
|
|
18759
|
-
assertFiniteNumber(y, 'gravityY');
|
|
18760
|
-
this._world.gravity.x = x;
|
|
18761
|
-
this._world.gravity.y = y;
|
|
18762
|
-
return this;
|
|
18763
|
-
}
|
|
18764
|
-
hasNode(node) {
|
|
18765
|
-
return this._nodeBindings.has(node);
|
|
18766
|
-
}
|
|
18767
|
-
getBinding(node) {
|
|
18768
|
-
return this._nodeBindings.get(node) ?? null;
|
|
18769
|
-
}
|
|
18770
|
-
attachNode(node, options) {
|
|
18771
|
-
if (this._nodeBindings.has(node)) {
|
|
18772
|
-
throw new Error('This SceneNode is already attached to a physics body.');
|
|
18773
|
-
}
|
|
18774
|
-
assertBodyOptions(options);
|
|
18775
|
-
const bodyDescriptor = this.createBodyDescriptor(node, options);
|
|
18776
|
-
const body = this._world.createRigidBody(bodyDescriptor);
|
|
18777
|
-
const colliderDescriptor = this.createColliderDescriptor(options);
|
|
18778
|
-
const collider = this._world.createCollider(colliderDescriptor, body);
|
|
18779
|
-
const binding = new RapierPhysicsBinding(this, node, body, collider, options);
|
|
18780
|
-
this._bindings.add(binding);
|
|
18781
|
-
this._nodeBindings.set(node, binding);
|
|
18782
|
-
this._colliderBindings.set(collider.handle, binding);
|
|
18783
|
-
return binding;
|
|
18784
|
-
}
|
|
18785
|
-
detachNode(node) {
|
|
18786
|
-
const binding = this._nodeBindings.get(node);
|
|
18787
|
-
if (binding) {
|
|
18788
|
-
this.removeBinding(binding);
|
|
18789
|
-
}
|
|
18790
|
-
return this;
|
|
18791
|
-
}
|
|
18792
|
-
step(deltaSeconds = defaultDeltaSeconds) {
|
|
18793
|
-
assertFiniteNumber(deltaSeconds, 'deltaSeconds');
|
|
18794
|
-
if (deltaSeconds < 0) {
|
|
18795
|
-
throw new Error('deltaSeconds must be zero or greater.');
|
|
18796
|
-
}
|
|
18797
|
-
this.applyStepDelta(deltaSeconds);
|
|
18798
|
-
this._world.step(this._eventQueue);
|
|
18799
|
-
this.drainCollisionEvents();
|
|
18800
|
-
this.syncNodeTransforms();
|
|
18801
|
-
return this;
|
|
18802
|
-
}
|
|
18803
|
-
syncNodeTransforms() {
|
|
18804
|
-
for (const binding of this._bindings) {
|
|
18805
|
-
if (binding.syncMode === 'physicsToNode') {
|
|
18806
|
-
binding.syncNodeFromBody();
|
|
18807
|
-
}
|
|
18808
|
-
}
|
|
18809
|
-
return this;
|
|
18810
|
-
}
|
|
18811
|
-
createDebugGraphics(options = {}) {
|
|
18812
|
-
const graphics = new Graphics();
|
|
18813
|
-
graphics.setCullable(false);
|
|
18814
|
-
this.updateDebugGraphics(graphics, options);
|
|
18815
|
-
return graphics;
|
|
18816
|
-
}
|
|
18817
|
-
updateDebugGraphics(graphics, options = {}) {
|
|
18818
|
-
const lineWidth = options.lineWidth ?? defaultDebugDrawOptions.lineWidth;
|
|
18819
|
-
const solidLineColor = options.solidLineColor ?? defaultDebugDrawOptions.solidLineColor;
|
|
18820
|
-
const solidFillColor = options.solidFillColor ?? defaultDebugDrawOptions.solidFillColor;
|
|
18821
|
-
const triggerLineColor = options.triggerLineColor ?? defaultDebugDrawOptions.triggerLineColor;
|
|
18822
|
-
const triggerFillColor = options.triggerFillColor ?? defaultDebugDrawOptions.triggerFillColor;
|
|
18823
|
-
graphics.clear();
|
|
18824
|
-
graphics.lineWidth = lineWidth;
|
|
18825
|
-
for (const binding of this._bindings) {
|
|
18826
|
-
const bodyTranslation = {
|
|
18827
|
-
x: binding.x,
|
|
18828
|
-
y: binding.y,
|
|
18829
|
-
};
|
|
18830
|
-
const rotation = binding.rotation;
|
|
18831
|
-
const lineColor = binding.trigger ? triggerLineColor : solidLineColor;
|
|
18832
|
-
const fillColor = binding.trigger ? triggerFillColor : solidFillColor;
|
|
18833
|
-
graphics.lineColor = lineColor;
|
|
18834
|
-
graphics.fillColor = fillColor;
|
|
18835
|
-
if (binding.shape.type === 'box') {
|
|
18836
|
-
const path = this.buildBoxPath(binding.shape, bodyTranslation.x, bodyTranslation.y, rotation);
|
|
18837
|
-
graphics.drawPolygon(path);
|
|
18838
|
-
}
|
|
18839
|
-
else {
|
|
18840
|
-
const offset = getOffset(binding.shape);
|
|
18841
|
-
const rotatedOffset = rotatePoint(offset.x, offset.y, rotation);
|
|
18842
|
-
graphics.drawCircle(bodyTranslation.x + rotatedOffset.x, bodyTranslation.y + rotatedOffset.y, binding.shape.radius);
|
|
18843
|
-
}
|
|
18844
|
-
}
|
|
18845
|
-
return graphics;
|
|
18846
|
-
}
|
|
18847
|
-
destroy() {
|
|
18848
|
-
for (const binding of Array.from(this._bindings)) {
|
|
18849
|
-
this.removeBinding(binding);
|
|
18850
|
-
}
|
|
18851
|
-
this.onCollisionEnter.destroy();
|
|
18852
|
-
this.onCollisionExit.destroy();
|
|
18853
|
-
this.onTriggerEnter.destroy();
|
|
18854
|
-
this.onTriggerExit.destroy();
|
|
18855
|
-
}
|
|
18856
|
-
writeBodyTransform(body, x, y, rotation, wakeUp) {
|
|
18857
|
-
body.setTranslation(new this._rapier.vector2(x, y), wakeUp);
|
|
18858
|
-
body.setRotation(rotation, wakeUp);
|
|
18859
|
-
}
|
|
18860
|
-
removeBinding(binding) {
|
|
18861
|
-
if (!this._bindings.has(binding)) {
|
|
18862
|
-
return;
|
|
18863
|
-
}
|
|
18864
|
-
this._bindings.delete(binding);
|
|
18865
|
-
this._nodeBindings.delete(binding.node);
|
|
18866
|
-
this._colliderBindings.delete(binding.colliderHandle);
|
|
18867
|
-
this._world.removeRigidBody(binding.getBody());
|
|
18868
|
-
}
|
|
18869
|
-
createBodyDescriptor(node, options) {
|
|
18870
|
-
const type = options.type ?? 'dynamic';
|
|
18871
|
-
let descriptor = this._rapier.rigidBodyDescFactory.dynamic();
|
|
18872
|
-
switch (type) {
|
|
18873
|
-
case 'static':
|
|
18874
|
-
descriptor = this._rapier.rigidBodyDescFactory.fixed();
|
|
18875
|
-
break;
|
|
18876
|
-
case 'kinematic':
|
|
18877
|
-
if (typeof this._rapier.rigidBodyDescFactory.kinematicPositionBased === 'function') {
|
|
18878
|
-
descriptor = this._rapier.rigidBodyDescFactory.kinematicPositionBased();
|
|
18879
|
-
}
|
|
18880
|
-
else if (typeof this._rapier.rigidBodyDescFactory.kinematicVelocityBased === 'function') {
|
|
18881
|
-
descriptor = this._rapier.rigidBodyDescFactory.kinematicVelocityBased();
|
|
18882
|
-
}
|
|
18883
|
-
else {
|
|
18884
|
-
throw new Error('Rapier module does not expose a kinematic rigid-body descriptor.');
|
|
18885
|
-
}
|
|
18886
|
-
break;
|
|
18887
|
-
default:
|
|
18888
|
-
descriptor = this._rapier.rigidBodyDescFactory.dynamic();
|
|
18889
|
-
break;
|
|
18890
|
-
}
|
|
18891
|
-
descriptor
|
|
18892
|
-
.setTranslation(node.x, node.y)
|
|
18893
|
-
.setRotation(node.rotation)
|
|
18894
|
-
.setLinearDamping(options.linearDamping ?? 0)
|
|
18895
|
-
.setAngularDamping(options.angularDamping ?? 0)
|
|
18896
|
-
.setGravityScale(options.gravityScale ?? 1)
|
|
18897
|
-
.lockRotations(options.lockRotation ?? false);
|
|
18898
|
-
return descriptor;
|
|
18899
|
-
}
|
|
18900
|
-
createColliderDescriptor(options) {
|
|
18901
|
-
const shape = options.shape;
|
|
18902
|
-
const descriptor = shape.type === 'box'
|
|
18903
|
-
? this._rapier.colliderDescFactory.cuboid(shape.width / 2, shape.height / 2)
|
|
18904
|
-
: this._rapier.colliderDescFactory.ball(shape.radius);
|
|
18905
|
-
const offset = getOffset(shape);
|
|
18906
|
-
const groups = toPackedCollisionGroups(options.collisionFilter);
|
|
18907
|
-
descriptor
|
|
18908
|
-
.setTranslation(offset.x, offset.y)
|
|
18909
|
-
.setRotation(shape.type === 'box' ? (shape.offsetRotation ?? 0) : 0)
|
|
18910
|
-
.setSensor(options.trigger ?? false)
|
|
18911
|
-
.setFriction(options.friction ?? 0.5)
|
|
18912
|
-
.setRestitution(options.restitution ?? 0)
|
|
18913
|
-
.setDensity(options.density ?? 1)
|
|
18914
|
-
.setCollisionGroups(groups)
|
|
18915
|
-
.setSolverGroups(groups);
|
|
18916
|
-
const collisionEvents = this._rapier.activeCollisionEvents;
|
|
18917
|
-
if (typeof collisionEvents === 'number') {
|
|
18918
|
-
descriptor.setActiveEvents(collisionEvents);
|
|
18919
|
-
}
|
|
18920
|
-
return descriptor;
|
|
18921
|
-
}
|
|
18922
|
-
applyStepDelta(deltaSeconds) {
|
|
18923
|
-
const worldWithTimestep = this._world;
|
|
18924
|
-
if (typeof worldWithTimestep.timestep === 'number') {
|
|
18925
|
-
worldWithTimestep.timestep = deltaSeconds;
|
|
18926
|
-
}
|
|
18927
|
-
if (worldWithTimestep.integrationParameters
|
|
18928
|
-
&& typeof worldWithTimestep.integrationParameters.dt === 'number') {
|
|
18929
|
-
worldWithTimestep.integrationParameters.dt = deltaSeconds;
|
|
18930
|
-
}
|
|
18931
|
-
}
|
|
18932
|
-
drainCollisionEvents() {
|
|
18933
|
-
this._eventQueue.drainCollisionEvents((handleA, handleB, started) => {
|
|
18934
|
-
const first = this._colliderBindings.get(handleA);
|
|
18935
|
-
const second = this._colliderBindings.get(handleB);
|
|
18936
|
-
if (!first || !second) {
|
|
18937
|
-
return;
|
|
18938
|
-
}
|
|
18939
|
-
const trigger = first.trigger || second.trigger;
|
|
18940
|
-
const event = {
|
|
18941
|
-
started,
|
|
18942
|
-
trigger,
|
|
18943
|
-
first,
|
|
18944
|
-
second,
|
|
18945
|
-
};
|
|
18946
|
-
if (trigger) {
|
|
18947
|
-
if (started) {
|
|
18948
|
-
this.onTriggerEnter.dispatch(event);
|
|
18949
|
-
}
|
|
18950
|
-
else {
|
|
18951
|
-
this.onTriggerExit.dispatch(event);
|
|
18952
|
-
}
|
|
18953
|
-
return;
|
|
18954
|
-
}
|
|
18955
|
-
if (started) {
|
|
18956
|
-
this.onCollisionEnter.dispatch(event);
|
|
18957
|
-
}
|
|
18958
|
-
else {
|
|
18959
|
-
this.onCollisionExit.dispatch(event);
|
|
18960
|
-
}
|
|
18961
|
-
});
|
|
18962
|
-
}
|
|
18963
|
-
buildBoxPath(shape, bodyX, bodyY, bodyRotation) {
|
|
18964
|
-
const halfWidth = shape.width / 2;
|
|
18965
|
-
const halfHeight = shape.height / 2;
|
|
18966
|
-
const corners = [
|
|
18967
|
-
{ x: -halfWidth, y: -halfHeight },
|
|
18968
|
-
{ x: halfWidth, y: -halfHeight },
|
|
18969
|
-
{ x: halfWidth, y: halfHeight },
|
|
18970
|
-
{ x: -halfWidth, y: halfHeight },
|
|
18971
|
-
];
|
|
18972
|
-
const offset = getOffset(shape);
|
|
18973
|
-
const offsetRotation = shape.offsetRotation ?? 0;
|
|
18974
|
-
const path = [];
|
|
18975
|
-
for (const corner of corners) {
|
|
18976
|
-
const local = rotatePoint(corner.x, corner.y, offsetRotation);
|
|
18977
|
-
const withOffset = {
|
|
18978
|
-
x: local.x + offset.x,
|
|
18979
|
-
y: local.y + offset.y,
|
|
18980
|
-
};
|
|
18981
|
-
const worldPoint = rotatePoint(withOffset.x, withOffset.y, bodyRotation);
|
|
18982
|
-
path.push(bodyX + worldPoint.x, bodyY + worldPoint.y);
|
|
18983
|
-
}
|
|
18984
|
-
return path;
|
|
18985
|
-
}
|
|
18986
|
-
}
|
|
18987
|
-
const createRapierPhysicsWorld = async (options = {}) => {
|
|
18988
|
-
return await RapierPhysicsWorld.create(options);
|
|
18989
|
-
};
|
|
18990
|
-
|
|
18991
|
-
export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, RapierPhysicsBinding, RapierPhysicsWorld, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRapierPhysicsWorld, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign$1 as sign, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio, tau, trimRotation, webGl2PrimitiveArrayConstructors, webGl2PrimitiveByteSizeMapping, webGl2PrimitiveTypeNames };
|
|
18522
|
+
export { AbstractAssetFactory, AbstractMedia, AbstractWebGl2BatchedRenderer, AbstractWebGl2Renderer, AbstractWebGpuRenderer, AnimatedSprite, Application, ApplicationStatus, ArcadeStickGamepadMapping, AudioAnalyser, BinaryFactory, BlendModes, BlurFilter, Bounds, BufferTypes, BufferUsage, BundleLoadError, CacheFirstStrategy, CallbackRenderPass, Capabilities, ChannelOffset, ChannelSize, Circle, Clock, CollisionType, Color, ColorAffector, ColorFilter, Container, Drawable, Ellipse, FactoryRegistry, Filter, Flags, FontFactory, ForceAffector, GameCubeGamepadMapping, Gamepad, GamepadChannel, GamepadControl, GamepadMapping, GamepadMappingFamily, GamepadPromptLayouts, GenericDualAnalogGamepadMapping, Graphics, ImageFactory, IndexedDbDatabase, IndexedDbStore, Input, InputManager, Interval, JoyConLeftGamepadMapping, JoyConRightGamepadMapping, Json, JsonFactory, Keyboard, Line, Loader, Matrix, Mesh, Music, MusicFactory, NetworkOnlyStrategy, ObservableSize, ObservableVector, Particle, ParticleOptions, ParticleSystem, PlayStationGamepadMapping, Pointer, PointerState, PointerStateFlag, PolarVector, Polygon, Quadtree, Random, Rectangle, RenderBackendType, RenderNode, RenderTarget, RenderTargetPass, RenderTexture, RendererRegistry, RenderingPrimitives, Sampler, ScaleAffector, ScaleModes, Scene, SceneManager, SceneNode, Segment, Shader, ShaderAttribute, ShaderPrimitives, ShaderUniform, Signal, Size, Sound, SoundFactory, Sprite, SpriteFlags, Spritesheet, SteamControllerGamepadMapping, SvgAsset, SvgFactory, SwitchProGamepadMapping, Text, TextAsset, TextFactory, TextStyle, Texture, TextureFactory, Time, Timer, TorqueAffector, UniversalEmitter, Vector, Video, VideoFactory, View, ViewFlags, VoronoiRegion, VttAsset, VttFactory, WasmFactory, WebGl2Backend, WebGl2MeshRenderer, WebGl2ParticleRenderer, WebGl2RenderBuffer, WebGl2ShaderBlock, WebGl2SpriteRenderer, WebGl2VertexArrayObject, WebGpuBackend, WebGpuMeshRenderer, WebGpuParticleRenderer, WebGpuSpriteRenderer, WrapModes, XboxGamepadMapping, bezierCurveTo, buildCircle, buildEllipse, buildLine, buildPath, buildPolygon, buildRectangle, buildStar, builtInGamepadDefinitions, canvasSourceToDataUrl, clamp, createRenderStats, createWebGl2ShaderProgram, decodeAudioData, defineAssetManifest, degreesPerRadian, degreesToRadians, determineMimeType, emptyArrayBuffer, getAudioContext, getCanvasSourceSize, getCollisionCircleCircle, getCollisionCircleRectangle, getCollisionPolygonCircle, getCollisionRectangleRectangle, getCollisionSat, getDistance, getOfflineAudioContext, getPreciseTime, getTextureSourceSize, getVoronoiRegion$1 as getVoronoiRegion, getWebGpuBlendState, hours, inRange, intersectionCircleCircle, intersectionCircleEllipse, intersectionCirclePoly, intersectionEllipseEllipse, intersectionEllipsePoly, intersectionLineCircle, intersectionLineEllipse, intersectionLineLine, intersectionLinePoly, intersectionLineRect, intersectionPointCircle, intersectionPointEllipse, intersectionPointLine, intersectionPointPoint, intersectionPointPoly, intersectionPointRect, intersectionPolyPoly, intersectionRectCircle, intersectionRectEllipse, intersectionRectPoly, intersectionRectRect, intersectionSat, isAudioContextReady, isPowerOfTwo, lerp, matchesIds, maxPointers, milliseconds, minutes, noop$1 as noop, normalizeIds, onAudioContextReady, parseGamepadDescriptor, pointerSlotSize, quadraticCurveTo, radiansPerDegree, radiansToDegrees, rand, removeArrayItems, resetRenderStats, resolveDefinition, resolveGamepadDefinition, seconds, sign$1 as sign, stopEvent, supportsCodec, supportsEventOptions, supportsIndexedDb, supportsPointerEvents, supportsTouchEvents, supportsWebAudio, tau, trimRotation, webGl2PrimitiveArrayConstructors, webGl2PrimitiveByteSizeMapping, webGl2PrimitiveTypeNames };
|
|
18992
18523
|
//# sourceMappingURL=exo.esm.js.map
|