@certe/atmos-physics 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/LICENCE +674 -0
  2. package/README.md +152 -0
  3. package/dist/collider-offset.d.ts +19 -0
  4. package/dist/collider-offset.d.ts.map +1 -0
  5. package/dist/collider-offset.js +33 -0
  6. package/dist/collider-offset.js.map +1 -0
  7. package/dist/collider.d.ts +75 -0
  8. package/dist/collider.d.ts.map +1 -0
  9. package/dist/collider.js +223 -0
  10. package/dist/collider.js.map +1 -0
  11. package/dist/fixed-joint.d.ts +8 -0
  12. package/dist/fixed-joint.d.ts.map +1 -0
  13. package/dist/fixed-joint.js +10 -0
  14. package/dist/fixed-joint.js.map +1 -0
  15. package/dist/hinge-joint.d.ts +78 -0
  16. package/dist/hinge-joint.d.ts.map +1 -0
  17. package/dist/hinge-joint.js +271 -0
  18. package/dist/hinge-joint.js.map +1 -0
  19. package/dist/index.d.ts +23 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +14 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/init.d.ts +8 -0
  24. package/dist/init.d.ts.map +1 -0
  25. package/dist/init.js +98 -0
  26. package/dist/init.js.map +1 -0
  27. package/dist/joint.d.ts +52 -0
  28. package/dist/joint.d.ts.map +1 -0
  29. package/dist/joint.js +143 -0
  30. package/dist/joint.js.map +1 -0
  31. package/dist/physics-hierarchy.d.ts +8 -0
  32. package/dist/physics-hierarchy.d.ts.map +1 -0
  33. package/dist/physics-hierarchy.js +32 -0
  34. package/dist/physics-hierarchy.js.map +1 -0
  35. package/dist/physics-query.d.ts +30 -0
  36. package/dist/physics-query.d.ts.map +1 -0
  37. package/dist/physics-query.js +139 -0
  38. package/dist/physics-query.js.map +1 -0
  39. package/dist/physics-system.d.ts +17 -0
  40. package/dist/physics-system.d.ts.map +1 -0
  41. package/dist/physics-system.js +133 -0
  42. package/dist/physics-system.js.map +1 -0
  43. package/dist/physics-world.d.ts +33 -0
  44. package/dist/physics-world.d.ts.map +1 -0
  45. package/dist/physics-world.js +65 -0
  46. package/dist/physics-world.js.map +1 -0
  47. package/dist/register-builtins.d.ts +2 -0
  48. package/dist/register-builtins.d.ts.map +1 -0
  49. package/dist/register-builtins.js +84 -0
  50. package/dist/register-builtins.js.map +1 -0
  51. package/dist/rigid-body.d.ts +42 -0
  52. package/dist/rigid-body.d.ts.map +1 -0
  53. package/dist/rigid-body.js +189 -0
  54. package/dist/rigid-body.js.map +1 -0
  55. package/dist/spring-joint.d.ts +23 -0
  56. package/dist/spring-joint.d.ts.map +1 -0
  57. package/dist/spring-joint.js +26 -0
  58. package/dist/spring-joint.js.map +1 -0
  59. package/package.json +29 -0
  60. package/src/index.ts +26 -0
package/README.md ADDED
@@ -0,0 +1,152 @@
1
+ # ⚡ @certe/atmos-physics
2
+
3
+ Physics integration for the Atmos Engine, wrapping [Rapier](https://rapier.rs/) (WASM). Provides rigid bodies, collider shapes, joints, and stateless physics queries — all as components that sync automatically with the engine's Transform system.
4
+
5
+ ---
6
+
7
+ ## 🚀 Quick Start
8
+
9
+ ```ts
10
+ import { initRapier, PhysicsWorld, PhysicsSystem,
11
+ RigidBody, Collider } from '@certe/atmos-physics';
12
+
13
+ await initRapier();
14
+ const world = new PhysicsWorld({ gravity: { x: 0, y: -9.81, z: 0 } });
15
+
16
+ // Dynamic cube
17
+ const cube = new GameObject('Cube');
18
+ const rb = cube.addComponent(RigidBody);
19
+ rb.init(world, { type: 'dynamic', mass: 1 });
20
+ const col = cube.addComponent(Collider);
21
+ col.init(world, { shape: { type: 'box', halfExtents: { x: 0.5, y: 0.5, z: 0.5 } } });
22
+
23
+ // Static floor
24
+ const floor = new GameObject('Floor');
25
+ const floorRb = floor.addComponent(RigidBody);
26
+ floorRb.init(world, { type: 'fixed' });
27
+ const floorCol = floor.addComponent(Collider);
28
+ floorCol.init(world, { shape: { type: 'box', halfExtents: { x: 50, y: 0.5, z: 50 } } });
29
+
30
+ // Wire into engine
31
+ const physicsSystem = new PhysicsSystem(world, scene);
32
+ engine.setPhysics(physicsSystem);
33
+ ```
34
+
35
+ ---
36
+
37
+ ## 📖 API Overview
38
+
39
+ ### Initialization
40
+
41
+ | Function | Description |
42
+ |---|---|
43
+ | `initRapier()` | Load Rapier WASM (idempotent, call once at startup) |
44
+ | `new PhysicsWorld(opts?)` | Create simulation with gravity, timestep, solver iterations |
45
+
46
+ ### RigidBody Component
47
+
48
+ | Property | Description |
49
+ |---|---|
50
+ | `type` | `'dynamic'` · `'fixed'` · `'kinematic'` |
51
+ | `mass` | Mass for dynamic bodies |
52
+ | `linearDamping` / `angularDamping` | Velocity damping |
53
+ | `gravityScale` | Per-body gravity multiplier |
54
+
55
+ ```ts
56
+ rb.addForce(0, 100, 0); // continuous force
57
+ rb.addImpulse(0, 10, 0); // instant impulse
58
+ ```
59
+
60
+ ### Collider Component
61
+
62
+ Supported shapes:
63
+
64
+ | Shape | Parameters |
65
+ |---|---|
66
+ | `box` | `halfExtents: {x, y, z}` |
67
+ | `sphere` | `radius` |
68
+ | `capsule` | `halfHeight, radius` |
69
+ | `cylinder` | `halfHeight, radius` |
70
+ | `convexHull` | `vertices: Float32Array` |
71
+
72
+ ```ts
73
+ col.init(world, {
74
+ shape: { type: 'sphere', radius: 1.0 },
75
+ friction: 0.5,
76
+ restitution: 0.3,
77
+ isSensor: false, // true = trigger volume
78
+ });
79
+ ```
80
+
81
+ Colliders auto-attach to the nearest ancestor `RigidBody` and compute offsets for child GameObjects.
82
+
83
+ ### Joints
84
+
85
+ | Joint Type | Description |
86
+ |---|---|
87
+ | `FixedJoint` | Rigid constraint (no relative motion) |
88
+ | `HingeJoint` | Revolute (rotation around one axis), with optional limits and motor |
89
+ | `SpringJoint` | Spring with rest length, stiffness, and damping |
90
+
91
+ ```ts
92
+ const hinge = obj.addComponent(HingeJoint);
93
+ hinge.init(world, {
94
+ connectedObject: otherObj,
95
+ axis: { x: 0, y: 1, z: 0 },
96
+ limitsEnabled: true,
97
+ limitMin: -Math.PI / 4,
98
+ limitMax: Math.PI / 4,
99
+ });
100
+ ```
101
+
102
+ ### Physics Queries
103
+
104
+ Stateless raycasting and shape-casting via the `Physics` class:
105
+
106
+ ```ts
107
+ import { Physics } from '@certe/atmos-physics';
108
+
109
+ const hit = Physics.raycast(world, origin, direction, 100);
110
+ if (hit) {
111
+ console.log(hit.gameObject.name, hit.point, hit.normal, hit.distance);
112
+ }
113
+
114
+ const hits = Physics.sphereCastAll(world, center, radius);
115
+ const boxHit = Physics.boxCast(world, center, halfExtents);
116
+ ```
117
+
118
+ ### PhysicsSystem
119
+
120
+ Runs each frame via the engine. Handles:
121
+
122
+ - **Pre-step**: Detects external transform changes → teleports dynamic bodies; syncs kinematic bodies
123
+ - **Step**: Fixed-timestep accumulator (`world.step(dt)`)
124
+ - **Post-step**: Copies Rapier transforms back to engine Transforms
125
+
126
+ ---
127
+
128
+ ## 📁 Structure
129
+
130
+ ```
131
+ packages/physics/src/
132
+ index.ts # Public API
133
+ rapier-init.ts # WASM loader
134
+ physics-world.ts # Rapier world wrapper
135
+ physics-system.ts # Per-frame sync orchestrator
136
+ rigid-body.ts # RigidBody component
137
+ collider.ts # Collider component + shapes
138
+ joint.ts # Abstract Joint base
139
+ fixed-joint.ts # FixedJoint
140
+ hinge-joint.ts # HingeJoint (limits, motor)
141
+ spring-joint.ts # SpringJoint
142
+ physics-query.ts # Raycast, sphere/box cast
143
+ helpers.ts # Ancestor traversal utilities
144
+ ```
145
+
146
+ ---
147
+
148
+ ## 🔗 Dependencies
149
+
150
+ - `@certe/atmos-core` — Component, GameObject, Transform, Scene
151
+ - `@certe/atmos-math` — Vec3, Quat for transform sync
152
+ - `@dimforge/rapier3d-compat` — WASM physics engine
@@ -0,0 +1,19 @@
1
+ import type { GameObject } from '@certe/atmos-core';
2
+ export interface ColliderOffset {
3
+ tx: number;
4
+ ty: number;
5
+ tz: number;
6
+ rx: number;
7
+ ry: number;
8
+ rz: number;
9
+ rw: number;
10
+ sx: number;
11
+ sy: number;
12
+ sz: number;
13
+ }
14
+ /**
15
+ * Compute the offset of a child collider GO relative to its body's GO.
16
+ * Both transforms must have up-to-date world matrices before calling.
17
+ */
18
+ export declare function computeColliderOffset(bodyGo: GameObject, childGo: GameObject): ColliderOffset;
19
+ //# sourceMappingURL=collider-offset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collider-offset.d.ts","sourceRoot":"","sources":["../src/collider-offset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IACnC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAC/C,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;CACpC;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,UAAU,GAClB,cAAc,CA0BhB"}
@@ -0,0 +1,33 @@
1
+ import { Mat4, Quat } from '@certe/atmos-math';
2
+ // Scratch arrays — reused to avoid heap allocs
3
+ const _invParent = Mat4.create();
4
+ const _relative = Mat4.create();
5
+ const _tmpQuat = Quat.create();
6
+ /**
7
+ * Compute the offset of a child collider GO relative to its body's GO.
8
+ * Both transforms must have up-to-date world matrices before calling.
9
+ */
10
+ export function computeColliderOffset(bodyGo, childGo) {
11
+ // relative = inv(bodyWorld) * childWorld
12
+ if (!Mat4.invert(_invParent, bodyGo.transform.worldMatrix)) {
13
+ // Singular body world matrix (e.g. zero scale) — return identity offset
14
+ return { tx: 0, ty: 0, tz: 0, rx: 0, ry: 0, rz: 0, rw: 1, sx: 1, sy: 1, sz: 1 };
15
+ }
16
+ Mat4.multiply(_relative, _invParent, childGo.transform.worldMatrix);
17
+ // Translation from column 3
18
+ const tx = _relative[12];
19
+ const ty = _relative[13];
20
+ const tz = _relative[14];
21
+ // Scale from column lengths
22
+ const sx = Math.sqrt(_relative[0] ** 2 + _relative[1] ** 2 + _relative[2] ** 2);
23
+ const sy = Math.sqrt(_relative[4] ** 2 + _relative[5] ** 2 + _relative[6] ** 2);
24
+ const sz = Math.sqrt(_relative[8] ** 2 + _relative[9] ** 2 + _relative[10] ** 2);
25
+ // Rotation (Quat.fromMat4 normalizes columns internally)
26
+ Quat.fromMat4(_tmpQuat, _relative);
27
+ return {
28
+ tx, ty, tz,
29
+ rx: _tmpQuat[0], ry: _tmpQuat[1], rz: _tmpQuat[2], rw: _tmpQuat[3],
30
+ sx, sy, sz,
31
+ };
32
+ }
33
+ //# sourceMappingURL=collider-offset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collider-offset.js","sourceRoot":"","sources":["../src/collider-offset.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAQ/C,+CAA+C;AAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;AACjC,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;AAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;AAE/B;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAkB,EAClB,OAAmB;IAEnB,yCAAyC;IACzC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC;QAC3D,wEAAwE;QACxE,OAAO,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;IAEpE,4BAA4B;IAC5B,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,CAAC;IAC1B,MAAM,EAAE,GAAG,SAAS,CAAC,EAAE,CAAE,CAAC;IAE1B,4BAA4B;IAC5B,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC;IACnF,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC;IACnF,MAAM,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE,CAAE,IAAI,CAAC,CAAC,CAAC;IAEpF,yDAAyD;IACzD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAEnC,OAAO;QACL,EAAE,EAAE,EAAE,EAAE,EAAE;QACV,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAE;QACtE,EAAE,EAAE,EAAE,EAAE,EAAE;KACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Component } from '@certe/atmos-core';
3
+ import type { PhysicsWorld } from './physics-world.js';
4
+ import { RigidBody } from './rigid-body.js';
5
+ export type ColliderShape = {
6
+ type: 'box';
7
+ halfExtents: {
8
+ x: number;
9
+ y: number;
10
+ z: number;
11
+ };
12
+ center?: {
13
+ x: number;
14
+ y: number;
15
+ z: number;
16
+ };
17
+ } | {
18
+ type: 'sphere';
19
+ radius: number;
20
+ } | {
21
+ type: 'capsule';
22
+ halfHeight: number;
23
+ radius: number;
24
+ } | {
25
+ type: 'cylinder';
26
+ halfHeight: number;
27
+ radius: number;
28
+ } | {
29
+ type: 'convexHull';
30
+ vertices: Float32Array;
31
+ };
32
+ export interface ColliderOptions {
33
+ shape: ColliderShape;
34
+ friction?: number;
35
+ restitution?: number;
36
+ density?: number;
37
+ isSensor?: boolean;
38
+ }
39
+ export declare class Collider extends Component {
40
+ collider: RAPIER.Collider | null;
41
+ /** Unscaled base shape dimensions, stored at init time */
42
+ private _baseShape;
43
+ private _options;
44
+ private _world;
45
+ /** The RigidBody this collider is attached to (may be on an ancestor) */
46
+ private _bodyRb;
47
+ /** The GameObject that owns the RigidBody */
48
+ private _bodyGo;
49
+ private _friction;
50
+ private _restitution;
51
+ private _density;
52
+ private _isSensor;
53
+ get friction(): number;
54
+ set friction(v: number);
55
+ get restitution(): number;
56
+ set restitution(v: number);
57
+ get density(): number;
58
+ set density(v: number);
59
+ get isSensor(): boolean;
60
+ set isSensor(v: boolean);
61
+ get attachedBody(): RigidBody | null;
62
+ get shape(): ColliderShape | null;
63
+ get isChildCollider(): boolean;
64
+ init(world: PhysicsWorld, options: ColliderOptions): void;
65
+ /** Recompute this child collider's offset from the current transform hierarchy. */
66
+ syncOffset(): void;
67
+ /** Destroy and re-create the collider (e.g. after reparenting). */
68
+ reattach(world: PhysicsWorld): void;
69
+ applyScale(sx: number, sy: number, sz: number): void;
70
+ /** Apply shape center offset (scaled), e.g. for plane collider where top face = visual surface. */
71
+ private _applyCenterOffset;
72
+ onDestroy(): void;
73
+ private _createDesc;
74
+ }
75
+ //# sourceMappingURL=collider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collider.d.ts","sourceRoot":"","sources":["../src/collider.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,MAAM,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC/G;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,EAAE,YAAY,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAOD,qBAAa,QAAS,SAAQ,SAAS;IACrC,QAAQ,EAAE,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAQ;IAExC,0DAA0D;IAC1D,OAAO,CAAC,UAAU,CAA8B;IAChD,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,MAAM,CAA6B;IAC3C,yEAAyE;IACzE,OAAO,CAAC,OAAO,CAA0B;IACzC,6CAA6C;IAC7C,OAAO,CAAC,OAAO,CAA2B;IAE1C,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAK;IACrB,OAAO,CAAC,SAAS,CAAS;IAE1B,IAAI,QAAQ,IAAI,MAAM,CAA2B;IACjD,IAAI,QAAQ,CAAC,CAAC,EAAE,MAAM,EAGrB;IAED,IAAI,WAAW,IAAI,MAAM,CAA8B;IACvD,IAAI,WAAW,CAAC,CAAC,EAAE,MAAM,EAGxB;IAED,IAAI,OAAO,IAAI,MAAM,CAA0B;IAC/C,IAAI,OAAO,CAAC,CAAC,EAAE,MAAM,EAGpB;IAED,IAAI,QAAQ,IAAI,OAAO,CAA2B;IAClD,IAAI,QAAQ,CAAC,CAAC,EAAE,OAAO,EAGtB;IAED,IAAI,YAAY,IAAI,SAAS,GAAG,IAAI,CAEnC;IAED,IAAI,KAAK,IAAI,aAAa,GAAG,IAAI,CAEhC;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAiDzD,mFAAmF;IACnF,UAAU,IAAI,IAAI;IAalB,mEAAmE;IACnE,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAWnC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAiCpD,mGAAmG;IACnG,OAAO,CAAC,kBAAkB;IAY1B,SAAS,IAAI,IAAI;IASjB,OAAO,CAAC,WAAW;CA8BpB"}
@@ -0,0 +1,223 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Component } from '@certe/atmos-core';
3
+ import { RigidBody } from './rigid-body.js';
4
+ import { findAncestorComponent } from './physics-hierarchy.js';
5
+ import { computeColliderOffset } from './collider-offset.js';
6
+ // Scratch vectors reused to avoid allocations
7
+ const _scaleVec = new RAPIER.Vector3(0, 0, 0);
8
+ const _offsetVec = new RAPIER.Vector3(0, 0, 0);
9
+ const _offsetRot = new RAPIER.Quaternion(0, 0, 0, 1);
10
+ export class Collider extends Component {
11
+ collider = null;
12
+ /** Unscaled base shape dimensions, stored at init time */
13
+ _baseShape = null;
14
+ _options = null;
15
+ _world = null;
16
+ /** The RigidBody this collider is attached to (may be on an ancestor) */
17
+ _bodyRb = null;
18
+ /** The GameObject that owns the RigidBody */
19
+ _bodyGo = null;
20
+ _friction = 0.5;
21
+ _restitution = 0;
22
+ _density = 1;
23
+ _isSensor = false;
24
+ get friction() { return this._friction; }
25
+ set friction(v) {
26
+ this._friction = v;
27
+ if (this.collider)
28
+ this.collider.setFriction(v);
29
+ }
30
+ get restitution() { return this._restitution; }
31
+ set restitution(v) {
32
+ this._restitution = v;
33
+ if (this.collider)
34
+ this.collider.setRestitution(v);
35
+ }
36
+ get density() { return this._density; }
37
+ set density(v) {
38
+ this._density = v;
39
+ if (this.collider)
40
+ this.collider.setDensity(v);
41
+ }
42
+ get isSensor() { return this._isSensor; }
43
+ set isSensor(v) {
44
+ this._isSensor = v;
45
+ if (this.collider)
46
+ this.collider.setSensor(v);
47
+ }
48
+ get attachedBody() {
49
+ return this._bodyRb;
50
+ }
51
+ get shape() {
52
+ return this._baseShape;
53
+ }
54
+ get isChildCollider() {
55
+ return this._bodyGo !== null && this._bodyGo !== this.gameObject;
56
+ }
57
+ init(world, options) {
58
+ this._world = world;
59
+ this._baseShape = options.shape;
60
+ this._options = options;
61
+ if (options.friction !== undefined)
62
+ this._friction = options.friction;
63
+ if (options.restitution !== undefined)
64
+ this._restitution = options.restitution;
65
+ if (options.density !== undefined)
66
+ this._density = options.density;
67
+ if (options.isSensor !== undefined)
68
+ this._isSensor = options.isSensor;
69
+ // Find body: self first, then walk up hierarchy
70
+ const rb = findAncestorComponent(this.gameObject, RigidBody);
71
+ if (!rb || !rb.body) {
72
+ throw new Error('Collider requires a RigidBody on this GameObject or an ancestor');
73
+ }
74
+ this._bodyRb = rb;
75
+ this._bodyGo = rb.gameObject;
76
+ const desc = this._createDesc(options);
77
+ // If attached to an ancestor's body, compute offset from hierarchy transforms
78
+ if (this._bodyGo !== this.gameObject) {
79
+ this._bodyGo.transform.updateWorldMatrix();
80
+ this.gameObject.transform.updateWorldMatrix();
81
+ const offset = computeColliderOffset(this._bodyGo, this.gameObject);
82
+ desc.setTranslation(offset.tx, offset.ty, offset.tz);
83
+ desc.setRotation({ x: offset.rx, y: offset.ry, z: offset.rz, w: offset.rw });
84
+ }
85
+ this.collider = world.createCollider(desc, rb.body);
86
+ // Apply scale: use accumulated scale for child colliders, local for self
87
+ if (this._bodyGo !== this.gameObject) {
88
+ const offset = computeColliderOffset(this._bodyGo, this.gameObject);
89
+ this.applyScale(offset.sx, offset.sy, offset.sz);
90
+ }
91
+ else {
92
+ const scale = this.gameObject.transform.scale;
93
+ if (scale[0] !== 1 || scale[1] !== 1 || scale[2] !== 1) {
94
+ this.applyScale(scale[0], scale[1], scale[2]);
95
+ }
96
+ else {
97
+ this._applyCenterOffset();
98
+ }
99
+ }
100
+ rb.body.wakeUp();
101
+ }
102
+ /** Recompute this child collider's offset from the current transform hierarchy. */
103
+ syncOffset() {
104
+ if (!this.collider || !this._bodyGo || this._bodyGo === this.gameObject)
105
+ return;
106
+ this._bodyGo.transform.updateWorldMatrix();
107
+ this.gameObject.transform.updateWorldMatrix();
108
+ const offset = computeColliderOffset(this._bodyGo, this.gameObject);
109
+ _offsetVec.x = offset.tx;
110
+ _offsetVec.y = offset.ty;
111
+ _offsetVec.z = offset.tz;
112
+ this.collider.setTranslationWrtParent(_offsetVec);
113
+ _offsetRot.x = offset.rx;
114
+ _offsetRot.y = offset.ry;
115
+ _offsetRot.z = offset.rz;
116
+ _offsetRot.w = offset.rw;
117
+ this.collider.setRotationWrtParent(_offsetRot);
118
+ this.applyScale(offset.sx, offset.sy, offset.sz);
119
+ }
120
+ /** Destroy and re-create the collider (e.g. after reparenting). */
121
+ reattach(world) {
122
+ if (!this._options)
123
+ return;
124
+ if (this.collider && this._world) {
125
+ try {
126
+ this._world.removeCollider(this.collider);
127
+ }
128
+ catch { /* already removed */ }
129
+ this.collider = null;
130
+ }
131
+ this._bodyRb = null;
132
+ this._bodyGo = null;
133
+ this.init(world, this._options);
134
+ }
135
+ applyScale(sx, sy, sz) {
136
+ if (!this.collider || !this._baseShape)
137
+ return;
138
+ switch (this._baseShape.type) {
139
+ case 'box': {
140
+ const h = this._baseShape.halfExtents;
141
+ _scaleVec.x = h.x * Math.abs(sx);
142
+ _scaleVec.y = h.y * Math.abs(sy);
143
+ _scaleVec.z = h.z * Math.abs(sz);
144
+ this.collider.setHalfExtents(_scaleVec);
145
+ break;
146
+ }
147
+ case 'sphere':
148
+ this.collider.setRadius(this._baseShape.radius * Math.max(Math.abs(sx), Math.abs(sy), Math.abs(sz)));
149
+ break;
150
+ case 'cylinder':
151
+ this.collider.setHalfHeight(this._baseShape.halfHeight * Math.abs(sy));
152
+ this.collider.setRadius(this._baseShape.radius * Math.max(Math.abs(sx), Math.abs(sz)));
153
+ break;
154
+ case 'capsule':
155
+ this.collider.setHalfHeight(this._baseShape.halfHeight * Math.abs(sy));
156
+ this.collider.setRadius(this._baseShape.radius * Math.max(Math.abs(sx), Math.abs(sz)));
157
+ break;
158
+ }
159
+ this._applyCenterOffset(sx, sy, sz);
160
+ }
161
+ /** Apply shape center offset (scaled), e.g. for plane collider where top face = visual surface. */
162
+ _applyCenterOffset(sx = 1, sy = 1, sz = 1) {
163
+ if (!this.collider || !this._baseShape || this._baseShape.type !== 'box')
164
+ return;
165
+ const c = this._baseShape.center;
166
+ if (!c)
167
+ return;
168
+ // Only apply for self-colliders (not child colliders, which use hierarchy offset)
169
+ if (this._bodyGo && this._bodyGo !== this.gameObject)
170
+ return;
171
+ _offsetVec.x = c.x * sx;
172
+ _offsetVec.y = c.y * sy;
173
+ _offsetVec.z = c.z * sz;
174
+ this.collider.setTranslationWrtParent(_offsetVec);
175
+ }
176
+ onDestroy() {
177
+ if (this.collider && this._world) {
178
+ try {
179
+ this._world.removeCollider(this.collider);
180
+ }
181
+ catch { /* stale handle */ }
182
+ this.collider = null;
183
+ }
184
+ this._bodyRb = null;
185
+ this._bodyGo = null;
186
+ }
187
+ _createDesc(options) {
188
+ let desc;
189
+ switch (options.shape.type) {
190
+ case 'box': {
191
+ const h = options.shape.halfExtents;
192
+ desc = RAPIER.ColliderDesc.cuboid(h.x, h.y, h.z);
193
+ break;
194
+ }
195
+ case 'sphere':
196
+ desc = RAPIER.ColliderDesc.ball(options.shape.radius);
197
+ break;
198
+ case 'capsule':
199
+ desc = RAPIER.ColliderDesc.capsule(options.shape.halfHeight, options.shape.radius);
200
+ break;
201
+ case 'cylinder':
202
+ desc = RAPIER.ColliderDesc.cylinder(options.shape.halfHeight, options.shape.radius);
203
+ break;
204
+ case 'convexHull': {
205
+ const hull = RAPIER.ColliderDesc.convexHull(options.shape.vertices);
206
+ if (!hull)
207
+ throw new Error('Failed to compute convex hull from vertices');
208
+ desc = hull;
209
+ break;
210
+ }
211
+ }
212
+ if (options.friction !== undefined)
213
+ desc.setFriction(options.friction);
214
+ if (options.restitution !== undefined)
215
+ desc.setRestitution(options.restitution);
216
+ if (options.density !== undefined)
217
+ desc.setDensity(options.density);
218
+ if (options.isSensor)
219
+ desc.setSensor(true);
220
+ return desc;
221
+ }
222
+ }
223
+ //# sourceMappingURL=collider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collider.js","sourceRoot":"","sources":["../src/collider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Joint } from './joint.js';
3
+ import type { JointOptions } from './joint.js';
4
+ export type FixedJointOptions = JointOptions;
5
+ export declare class FixedJoint extends Joint {
6
+ protected _createJointData(): RAPIER.JointData;
7
+ }
8
+ //# sourceMappingURL=fixed-joint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixed-joint.d.ts","sourceRoot":"","sources":["../src/fixed-joint.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,MAAM,MAAM,iBAAiB,GAAG,YAAY,CAAC;AAE7C,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAS,CAAC,gBAAgB,IAAI,MAAM,CAAC,SAAS;CAK/C"}
@@ -0,0 +1,10 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ import { Joint } from './joint.js';
3
+ export class FixedJoint extends Joint {
4
+ _createJointData() {
5
+ const frame1 = { x: 0, y: 0, z: 0, w: 1 };
6
+ const frame2 = { x: 0, y: 0, z: 0, w: 1 };
7
+ return RAPIER.JointData.fixed(this._toXYZ(this.anchor), frame1, this._toXYZ(this.connectedAnchor), frame2);
8
+ }
9
+ }
10
+ //# sourceMappingURL=fixed-joint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixed-joint.js","sourceRoot":"","sources":["../src/fixed-joint.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,2BAA2B,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAKnC,MAAM,OAAO,UAAW,SAAQ,KAAK;IACzB,gBAAgB;QACxB,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC;IAC7G,CAAC;CACF"}
@@ -0,0 +1,78 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ import type { Vec3Type } from '@certe/atmos-math';
3
+ import { Joint } from './joint.js';
4
+ import type { JointOptions } from './joint.js';
5
+ import type { PhysicsWorld } from './physics-world.js';
6
+ type AxisOption = {
7
+ x: number;
8
+ y: number;
9
+ z: number;
10
+ } | Float32Array;
11
+ export interface HingeJointOptions extends JointOptions {
12
+ axis?: AxisOption;
13
+ connectedAxis?: AxisOption;
14
+ autoConfigureConnectedAxis?: boolean;
15
+ limitsEnabled?: boolean;
16
+ limitMin?: number;
17
+ limitMax?: number;
18
+ motorEnabled?: boolean;
19
+ motorMode?: 'velocity' | 'position';
20
+ motorTargetVelocity?: number;
21
+ motorMaxForce?: number;
22
+ motorTargetPosition?: number;
23
+ motorStiffness?: number;
24
+ motorDamping?: number;
25
+ }
26
+ export declare class HingeJoint extends Joint {
27
+ private readonly _axis;
28
+ private readonly _connectedAxisVec;
29
+ private _autoConfigureConnectedAxis;
30
+ private _limitsEnabled;
31
+ private _limitMin;
32
+ private _limitMax;
33
+ private _motorEnabled;
34
+ private _motorMode;
35
+ private _motorTargetVelocity;
36
+ private _motorMaxForce;
37
+ private _motorTargetPosition;
38
+ private _motorStiffness;
39
+ private _motorDamping;
40
+ /** Current joint angle in radians. Computed from body orientations and joint frames. */
41
+ get angle(): number;
42
+ get axis(): Vec3Type;
43
+ set axis(v: Vec3Type);
44
+ get connectedAxis(): Vec3Type;
45
+ set connectedAxis(v: Vec3Type);
46
+ get autoConfigureConnectedAxis(): boolean;
47
+ set autoConfigureConnectedAxis(v: boolean);
48
+ get limitsEnabled(): boolean;
49
+ set limitsEnabled(v: boolean);
50
+ get limitMin(): number;
51
+ set limitMin(v: number);
52
+ get limitMax(): number;
53
+ set limitMax(v: number);
54
+ get motorEnabled(): boolean;
55
+ set motorEnabled(v: boolean);
56
+ get motorMode(): 'velocity' | 'position';
57
+ set motorMode(v: 'velocity' | 'position');
58
+ get motorTargetVelocity(): number;
59
+ set motorTargetVelocity(v: number);
60
+ get motorMaxForce(): number;
61
+ set motorMaxForce(v: number);
62
+ get motorTargetPosition(): number;
63
+ set motorTargetPosition(v: number);
64
+ get motorStiffness(): number;
65
+ set motorStiffness(v: number);
66
+ get motorDamping(): number;
67
+ set motorDamping(v: number);
68
+ init(world: PhysicsWorld, options?: HingeJointOptions): void;
69
+ refreshAutoConfig(): void;
70
+ protected _tryCreateJoint(): void;
71
+ private _computeConnectedAxis;
72
+ private _setVec3;
73
+ private _applyLimits;
74
+ private _applyMotor;
75
+ protected _createJointData(): RAPIER.JointData;
76
+ }
77
+ export {};
78
+ //# sourceMappingURL=hinge-joint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hinge-joint.d.ts","sourceRoot":"","sources":["../src/hinge-joint.ts"],"names":[],"mappings":"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"}