@waica/engine 0.25.0 → 0.27.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.
- package/README.md +77 -1
- package/dist/anchored-pieces.d.ts +3 -2
- package/dist/anchored-pieces.js +12 -8
- package/dist/animation/clip-player.d.ts +7 -0
- package/dist/animation/clip-player.js +9 -0
- package/dist/animation/clip-target.d.ts +38 -0
- package/dist/animation/clip-target.js +9 -0
- package/dist/animation/pose-hash.d.ts +10 -0
- package/dist/animation/pose-hash.js +43 -0
- package/dist/archetype.d.ts +2 -2
- package/dist/assets/asset-loader.d.ts +28 -5
- package/dist/assets/asset-loader.js +63 -7
- package/dist/assets/model-backend.d.ts +21 -0
- package/dist/assets/model-backend.js +21 -0
- package/dist/assets/model-cache.d.ts +47 -0
- package/dist/assets/model-cache.js +117 -0
- package/dist/audio/audio-subsystem.d.ts +6 -1
- package/dist/audio/audio-subsystem.js +8 -15
- package/dist/audio/placement.d.ts +41 -0
- package/dist/audio/placement.js +21 -0
- package/dist/audio/spatial.d.ts +20 -0
- package/dist/audio/spatial.js +26 -0
- package/dist/audio/types.d.ts +7 -1
- package/dist/camera-projection.d.ts +38 -0
- package/dist/camera-projection.js +44 -0
- package/dist/camera-rig.d.ts +48 -0
- package/dist/camera-rig.js +98 -0
- package/dist/camera.d.ts +20 -3
- package/dist/camera.js +3 -1
- package/dist/component.d.ts +38 -2
- package/dist/component.js +3 -0
- package/dist/components/animated-sprite.d.ts +14 -3
- package/dist/components/animated-sprite.js +16 -2
- package/dist/components/animator.d.ts +98 -0
- package/dist/components/animator.js +197 -0
- package/dist/components/collider.d.ts +89 -0
- package/dist/components/collider.js +57 -0
- package/dist/components/dynamic-body.d.ts +2 -1
- package/dist/components/dynamic-body.js +1 -0
- package/dist/components/hitbox.d.ts +2 -1
- package/dist/components/hitbox.js +1 -0
- package/dist/components/light.d.ts +2 -1
- package/dist/components/light.js +1 -0
- package/dist/components/model.d.ts +71 -0
- package/dist/components/model.js +128 -0
- package/dist/components/particle-emitter.d.ts +2 -1
- package/dist/components/particle-emitter.js +1 -0
- package/dist/components/point-light.d.ts +75 -0
- package/dist/components/point-light.js +102 -0
- package/dist/components/rigid-body.d.ts +114 -0
- package/dist/components/rigid-body.js +83 -0
- package/dist/components/solid.d.ts +2 -1
- package/dist/components/solid.js +1 -0
- package/dist/components/sprite.d.ts +2 -1
- package/dist/components/sprite.js +1 -0
- package/dist/components/sun.d.ts +46 -0
- package/dist/components/sun.js +74 -0
- package/dist/components/tilemap.d.ts +2 -1
- package/dist/components/tilemap.js +1 -0
- package/dist/entity-transform.d.ts +18 -0
- package/dist/entity-transform.js +17 -0
- package/dist/game.d.ts +51 -15
- package/dist/game.js +83 -70
- package/dist/index.d.ts +34 -4
- package/dist/index.js +15 -1
- package/dist/lit-frame.js +10 -3
- package/dist/physics-3d/body-contacts.d.ts +10 -0
- package/dist/physics-3d/body-contacts.js +59 -0
- package/dist/physics-3d/body-sync.d.ts +52 -0
- package/dist/physics-3d/body-sync.js +153 -0
- package/dist/physics-3d/character-controller.d.ts +44 -0
- package/dist/physics-3d/character-controller.js +126 -0
- package/dist/physics-3d/physics-host.d.ts +86 -0
- package/dist/physics-3d/physics-host.js +174 -0
- package/dist/physics-3d/physics-world.d.ts +65 -0
- package/dist/physics-3d/physics-world.js +158 -0
- package/dist/physics-3d/rapier-module.d.ts +17 -0
- package/dist/physics-3d/rapier-module.js +19 -0
- package/dist/physics-3d/sensor-dispatch.d.ts +10 -0
- package/dist/physics-3d/sensor-dispatch.js +77 -0
- package/dist/physics-3d/world-queries.d.ts +39 -0
- package/dist/physics-3d/world-queries.js +63 -0
- package/dist/pointer-raycast.d.ts +17 -0
- package/dist/pointer-raycast.js +48 -0
- package/dist/pointer.d.ts +27 -6
- package/dist/pointer.js +43 -17
- package/dist/runtime-bridge.d.ts +1 -1
- package/dist/runtime-inspection.d.ts +9 -0
- package/dist/runtime-inspection.js +8 -2
- package/dist/runtime-lighting-snapshot.d.ts +27 -1
- package/dist/runtime-lighting-snapshot.js +31 -0
- package/dist/runtime-physics-snapshot.d.ts +41 -0
- package/dist/runtime-physics-snapshot.js +45 -0
- package/dist/runtime-view-snapshot.d.ts +25 -0
- package/dist/runtime-view-snapshot.js +30 -0
- package/dist/scene-camera-3d.d.ts +66 -0
- package/dist/scene-camera-3d.js +117 -0
- package/dist/scene-lights-3d.d.ts +17 -0
- package/dist/scene-lights-3d.js +27 -0
- package/dist/scene-simulation.d.ts +22 -0
- package/dist/scene-simulation.js +29 -0
- package/dist/scene-space.d.ts +50 -0
- package/dist/scene-space.js +103 -0
- package/dist/scene.d.ts +12 -2
- package/dist/scene.js +11 -4
- package/dist/simulation-phases.d.ts +9 -0
- package/dist/simulation-phases.js +19 -0
- package/dist/spatial-query-3d.d.ts +48 -0
- package/dist/spatial-query-3d.js +96 -0
- package/dist/spatial-query.d.ts +18 -4
- package/dist/spatial-query.js +57 -1
- package/dist/state/state-machine.d.ts +32 -8
- package/dist/state/state-machine.js +88 -27
- package/package.json +2 -1
|
@@ -8,6 +8,7 @@ import { resolveCollisionPoints, } from '../collision-shape.js';
|
|
|
8
8
|
*/
|
|
9
9
|
export class Hitbox extends Component {
|
|
10
10
|
static componentName = 'Hitbox';
|
|
11
|
+
static space = '2d';
|
|
11
12
|
static params = {
|
|
12
13
|
layer: { label: 'Collision Layer' },
|
|
13
14
|
collidesWith: { label: 'Collision Mask', kind: 'string-list' },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from '../component.js';
|
|
1
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
2
2
|
import type { LightField } from '../light-field.js';
|
|
3
3
|
/**
|
|
4
4
|
* A source of 2D light owned by its entity (issue #78, `CONTEXT.md` Light):
|
|
@@ -10,6 +10,7 @@ import type { LightField } from '../light-field.js';
|
|
|
10
10
|
*/
|
|
11
11
|
export declare class Light extends Component {
|
|
12
12
|
static componentName: string;
|
|
13
|
+
static space: ComponentSpace;
|
|
13
14
|
static params: {
|
|
14
15
|
radius: {
|
|
15
16
|
label: string;
|
package/dist/components/light.js
CHANGED
|
@@ -12,6 +12,7 @@ const finiteOr = (value, fallback) => (Number.isFinite(value) ? value : fallback
|
|
|
12
12
|
*/
|
|
13
13
|
export class Light extends Component {
|
|
14
14
|
static componentName = 'Light';
|
|
15
|
+
static space = '2d';
|
|
15
16
|
static params = {
|
|
16
17
|
radius: { label: 'Radius', min: 0, step: 0.25 },
|
|
17
18
|
color: { label: 'Color', kind: 'color' },
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import type { ModelHandle } from '../assets/model-cache.js';
|
|
3
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
4
|
+
export type ModelShape = 'box' | 'sphere' | 'plane';
|
|
5
|
+
/**
|
|
6
|
+
* A 3D thing an entity draws (3D scenes, ADR 0027): a glTF/glb from `src`
|
|
7
|
+
* (a `waica:` uri or a project path, loaded once through `game.assets`) or a
|
|
8
|
+
* primitive `shape` of a `color` and a uniform `size`. With both, `src` wins.
|
|
9
|
+
* Its root hangs under the entity's node, so the entity's position, rotation
|
|
10
|
+
* and scale place it; the glTF keeps the materials it ships with, a
|
|
11
|
+
* primitive has a standard (lit) node material. `color` and `size` follow the
|
|
12
|
+
* inspector live; a new `src` or `shape` rebuilds the content. Destroying it
|
|
13
|
+
* removes the root and disposes only what it created — never the cached glTF.
|
|
14
|
+
* In a 2D scene it creates nothing (`validate_project` reports it).
|
|
15
|
+
*/
|
|
16
|
+
export declare class Model extends Component {
|
|
17
|
+
static componentName: string;
|
|
18
|
+
static space: ComponentSpace;
|
|
19
|
+
static params: {
|
|
20
|
+
src: {
|
|
21
|
+
label: string;
|
|
22
|
+
kind: "model";
|
|
23
|
+
};
|
|
24
|
+
shape: {
|
|
25
|
+
label: string;
|
|
26
|
+
options: ModelShape[];
|
|
27
|
+
};
|
|
28
|
+
color: {
|
|
29
|
+
label: string;
|
|
30
|
+
kind: "color";
|
|
31
|
+
};
|
|
32
|
+
size: {
|
|
33
|
+
label: string;
|
|
34
|
+
min: number;
|
|
35
|
+
step: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
static transient: string[];
|
|
39
|
+
/** What this Model draws, under the entity's node; null until it is ready. The Pointer ray-casts against it. */
|
|
40
|
+
root: THREE.Group | null;
|
|
41
|
+
/**
|
|
42
|
+
* The handle of the glTF it draws (issue #166 CA-6): `handle.root` is the
|
|
43
|
+
* child of `root`, `handle.animations` its clips once settled — what an
|
|
44
|
+
* Animator beside it plays. Null for a primitive, in a 2D scene and before
|
|
45
|
+
* the component is ready; replaced on every rebuild.
|
|
46
|
+
*/
|
|
47
|
+
handle: ModelHandle | null;
|
|
48
|
+
private _src;
|
|
49
|
+
private _shape;
|
|
50
|
+
private _color;
|
|
51
|
+
private _size;
|
|
52
|
+
private _primitive;
|
|
53
|
+
/** A `waica:` uri or project path to a `.glb` / `.gltf`; empty draws the primitive `shape`. */
|
|
54
|
+
get src(): string;
|
|
55
|
+
set src(value: string);
|
|
56
|
+
get shape(): ModelShape;
|
|
57
|
+
set shape(value: ModelShape);
|
|
58
|
+
/** `0xrrggbb` of a primitive. */
|
|
59
|
+
get color(): number;
|
|
60
|
+
set color(value: number);
|
|
61
|
+
/** Uniform scale of a primitive: the box side, sphere diameter or plane side in world units. */
|
|
62
|
+
get size(): number;
|
|
63
|
+
set size(value: number);
|
|
64
|
+
onReady(): void;
|
|
65
|
+
onDestroy(): void;
|
|
66
|
+
private build;
|
|
67
|
+
private buildPrimitive;
|
|
68
|
+
private rebuild;
|
|
69
|
+
/** Empties the root and disposes the primitive this Model created; a glTF's clone only leaves the graph. */
|
|
70
|
+
private clear;
|
|
71
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import { Component } from '../component.js';
|
|
3
|
+
const SHAPES = ['box', 'sphere', 'plane'];
|
|
4
|
+
/** One unit of the shape: a box of side 1, a sphere of diameter 1, a plane of side 1 lying flat on the ground (normal up). */
|
|
5
|
+
function primitiveGeometry(shape) {
|
|
6
|
+
switch (shape) {
|
|
7
|
+
case 'sphere':
|
|
8
|
+
return new THREE.SphereGeometry(0.5, 32, 16);
|
|
9
|
+
case 'plane':
|
|
10
|
+
return new THREE.PlaneGeometry(1, 1).rotateX(-Math.PI / 2);
|
|
11
|
+
case 'box':
|
|
12
|
+
return new THREE.BoxGeometry(1, 1, 1);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A 3D thing an entity draws (3D scenes, ADR 0027): a glTF/glb from `src`
|
|
17
|
+
* (a `waica:` uri or a project path, loaded once through `game.assets`) or a
|
|
18
|
+
* primitive `shape` of a `color` and a uniform `size`. With both, `src` wins.
|
|
19
|
+
* Its root hangs under the entity's node, so the entity's position, rotation
|
|
20
|
+
* and scale place it; the glTF keeps the materials it ships with, a
|
|
21
|
+
* primitive has a standard (lit) node material. `color` and `size` follow the
|
|
22
|
+
* inspector live; a new `src` or `shape` rebuilds the content. Destroying it
|
|
23
|
+
* removes the root and disposes only what it created — never the cached glTF.
|
|
24
|
+
* In a 2D scene it creates nothing (`validate_project` reports it).
|
|
25
|
+
*/
|
|
26
|
+
export class Model extends Component {
|
|
27
|
+
static componentName = 'Model';
|
|
28
|
+
static space = '3d';
|
|
29
|
+
static params = {
|
|
30
|
+
src: { label: 'Model file', kind: 'model' },
|
|
31
|
+
shape: { label: 'Shape', options: [...SHAPES] },
|
|
32
|
+
color: { label: 'Color', kind: 'color' },
|
|
33
|
+
size: { label: 'Size', min: 0.01, step: 0.1 },
|
|
34
|
+
};
|
|
35
|
+
static transient = ['root', 'handle'];
|
|
36
|
+
/** What this Model draws, under the entity's node; null until it is ready. The Pointer ray-casts against it. */
|
|
37
|
+
root = null;
|
|
38
|
+
/**
|
|
39
|
+
* The handle of the glTF it draws (issue #166 CA-6): `handle.root` is the
|
|
40
|
+
* child of `root`, `handle.animations` its clips once settled — what an
|
|
41
|
+
* Animator beside it plays. Null for a primitive, in a 2D scene and before
|
|
42
|
+
* the component is ready; replaced on every rebuild.
|
|
43
|
+
*/
|
|
44
|
+
handle = null;
|
|
45
|
+
_src = '';
|
|
46
|
+
_shape = 'box';
|
|
47
|
+
_color = 0xffffff;
|
|
48
|
+
_size = 1;
|
|
49
|
+
_primitive = null;
|
|
50
|
+
/** A `waica:` uri or project path to a `.glb` / `.gltf`; empty draws the primitive `shape`. */
|
|
51
|
+
get src() {
|
|
52
|
+
return this._src;
|
|
53
|
+
}
|
|
54
|
+
set src(value) {
|
|
55
|
+
this._src = value;
|
|
56
|
+
this.rebuild();
|
|
57
|
+
}
|
|
58
|
+
get shape() {
|
|
59
|
+
return this._shape;
|
|
60
|
+
}
|
|
61
|
+
set shape(value) {
|
|
62
|
+
this._shape = SHAPES.includes(value) ? value : 'box';
|
|
63
|
+
this.rebuild();
|
|
64
|
+
}
|
|
65
|
+
/** `0xrrggbb` of a primitive. */
|
|
66
|
+
get color() {
|
|
67
|
+
return this._color;
|
|
68
|
+
}
|
|
69
|
+
set color(value) {
|
|
70
|
+
this._color = value;
|
|
71
|
+
this._primitive?.mesh.material.color.setHex(value);
|
|
72
|
+
}
|
|
73
|
+
/** Uniform scale of a primitive: the box side, sphere diameter or plane side in world units. */
|
|
74
|
+
get size() {
|
|
75
|
+
return this._size;
|
|
76
|
+
}
|
|
77
|
+
set size(value) {
|
|
78
|
+
this._size = value;
|
|
79
|
+
this._primitive?.mesh.scale.setScalar(value);
|
|
80
|
+
}
|
|
81
|
+
onReady() {
|
|
82
|
+
// Draws only in a 3D scene, like Sun and PointLight: 2.5D is a later block, and a lit-less mesh would come out black.
|
|
83
|
+
if (this.game.space !== '3d')
|
|
84
|
+
return;
|
|
85
|
+
this.root = new THREE.Group();
|
|
86
|
+
this.root.name = 'waica:model';
|
|
87
|
+
this.entity.node.add(this.root);
|
|
88
|
+
this.build();
|
|
89
|
+
}
|
|
90
|
+
onDestroy() {
|
|
91
|
+
this.clear();
|
|
92
|
+
this.root?.removeFromParent();
|
|
93
|
+
}
|
|
94
|
+
build() {
|
|
95
|
+
if (!this.root)
|
|
96
|
+
return;
|
|
97
|
+
if (this._src) {
|
|
98
|
+
this.handle = this.game.assets.model(this._src);
|
|
99
|
+
this.root.add(this.handle.root);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
this.buildPrimitive(this.root);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
buildPrimitive(root) {
|
|
106
|
+
const material = new THREE.MeshStandardNodeMaterial({ color: this._color });
|
|
107
|
+
const mesh = new THREE.Mesh(primitiveGeometry(this._shape), material);
|
|
108
|
+
mesh.scale.setScalar(this._size);
|
|
109
|
+
root.add(mesh);
|
|
110
|
+
this._primitive = { mesh };
|
|
111
|
+
}
|
|
112
|
+
rebuild() {
|
|
113
|
+
if (!this.root)
|
|
114
|
+
return;
|
|
115
|
+
this.clear();
|
|
116
|
+
this.build();
|
|
117
|
+
}
|
|
118
|
+
/** Empties the root and disposes the primitive this Model created; a glTF's clone only leaves the graph. */
|
|
119
|
+
clear() {
|
|
120
|
+
this.root?.clear();
|
|
121
|
+
this.handle = null;
|
|
122
|
+
if (!this._primitive)
|
|
123
|
+
return;
|
|
124
|
+
this._primitive.mesh.geometry.dispose();
|
|
125
|
+
this._primitive.mesh.material.dispose();
|
|
126
|
+
this._primitive = null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from '../component.js';
|
|
1
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
2
2
|
import type { YSortBatchParticipant, YSortEntry } from '../render-sort.js';
|
|
3
3
|
export type ParticleVector = [number, number];
|
|
4
4
|
export type ParticleSpace = 'world' | 'local';
|
|
@@ -8,6 +8,7 @@ export type ParticleBlend = 'normal' | 'additive';
|
|
|
8
8
|
/** A fixed-capacity source of short-lived, batched 2D particles. */
|
|
9
9
|
export declare class ParticleEmitter extends Component implements YSortBatchParticipant {
|
|
10
10
|
static componentName: string;
|
|
11
|
+
static space: ComponentSpace;
|
|
11
12
|
static displayName: string;
|
|
12
13
|
static params: {
|
|
13
14
|
rate: {
|
|
@@ -5,6 +5,7 @@ import { setEmissive } from '../render-layers.js';
|
|
|
5
5
|
/** A fixed-capacity source of short-lived, batched 2D particles. */
|
|
6
6
|
export class ParticleEmitter extends Component {
|
|
7
7
|
static componentName = 'ParticleEmitter';
|
|
8
|
+
static space = '2d';
|
|
8
9
|
static displayName = 'Particle Emitter';
|
|
9
10
|
static params = {
|
|
10
11
|
rate: { label: 'Rate', min: 0 },
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
3
|
+
/**
|
|
4
|
+
* A point light in a 3D scene (ADR 0027, `CONTEXT.md` Point Light): it shines
|
|
5
|
+
* in every direction from the entity's position plus an offset (in the
|
|
6
|
+
* entity's local frame: it turns and scales with the entity, so a lantern's
|
|
7
|
+
* offset follows the object it hangs on), reaching
|
|
8
|
+
* `distance` world units (0 = without limit) and fading with `decay` (2 is
|
|
9
|
+
* physical). Not the 2D `Light`, which paints a light-map. No shadows. In a
|
|
10
|
+
* 2D scene it creates nothing; the three light lives under the entity's node
|
|
11
|
+
* and leaves with it.
|
|
12
|
+
*/
|
|
13
|
+
export declare class PointLight extends Component {
|
|
14
|
+
static componentName: string;
|
|
15
|
+
static space: ComponentSpace;
|
|
16
|
+
static displayName: string;
|
|
17
|
+
static params: {
|
|
18
|
+
color: {
|
|
19
|
+
label: string;
|
|
20
|
+
kind: "color";
|
|
21
|
+
};
|
|
22
|
+
intensity: {
|
|
23
|
+
label: string;
|
|
24
|
+
min: number;
|
|
25
|
+
step: number;
|
|
26
|
+
};
|
|
27
|
+
distance: {
|
|
28
|
+
label: string;
|
|
29
|
+
min: number;
|
|
30
|
+
step: number;
|
|
31
|
+
};
|
|
32
|
+
decay: {
|
|
33
|
+
label: string;
|
|
34
|
+
min: number;
|
|
35
|
+
step: number;
|
|
36
|
+
};
|
|
37
|
+
offsetX: {
|
|
38
|
+
label: string;
|
|
39
|
+
};
|
|
40
|
+
offsetY: {
|
|
41
|
+
label: string;
|
|
42
|
+
};
|
|
43
|
+
offsetZ: {
|
|
44
|
+
label: string;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
static transient: string[];
|
|
48
|
+
/** The three light, null in a 2D scene or before the component is ready. */
|
|
49
|
+
light: THREE.PointLight | null;
|
|
50
|
+
private _color;
|
|
51
|
+
private _intensity;
|
|
52
|
+
private _distance;
|
|
53
|
+
private _decay;
|
|
54
|
+
private _offsetX;
|
|
55
|
+
private _offsetY;
|
|
56
|
+
private _offsetZ;
|
|
57
|
+
get color(): number;
|
|
58
|
+
set color(value: number);
|
|
59
|
+
get intensity(): number;
|
|
60
|
+
set intensity(value: number);
|
|
61
|
+
/** World units the light reaches; 0 reaches without limit. */
|
|
62
|
+
get distance(): number;
|
|
63
|
+
set distance(value: number);
|
|
64
|
+
get decay(): number;
|
|
65
|
+
set decay(value: number);
|
|
66
|
+
get offsetX(): number;
|
|
67
|
+
set offsetX(value: number);
|
|
68
|
+
get offsetY(): number;
|
|
69
|
+
set offsetY(value: number);
|
|
70
|
+
get offsetZ(): number;
|
|
71
|
+
set offsetZ(value: number);
|
|
72
|
+
onReady(): void;
|
|
73
|
+
onDestroy(): void;
|
|
74
|
+
private place;
|
|
75
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import * as THREE from 'three/webgpu';
|
|
2
|
+
import { Component } from '../component.js';
|
|
3
|
+
/**
|
|
4
|
+
* A point light in a 3D scene (ADR 0027, `CONTEXT.md` Point Light): it shines
|
|
5
|
+
* in every direction from the entity's position plus an offset (in the
|
|
6
|
+
* entity's local frame: it turns and scales with the entity, so a lantern's
|
|
7
|
+
* offset follows the object it hangs on), reaching
|
|
8
|
+
* `distance` world units (0 = without limit) and fading with `decay` (2 is
|
|
9
|
+
* physical). Not the 2D `Light`, which paints a light-map. No shadows. In a
|
|
10
|
+
* 2D scene it creates nothing; the three light lives under the entity's node
|
|
11
|
+
* and leaves with it.
|
|
12
|
+
*/
|
|
13
|
+
export class PointLight extends Component {
|
|
14
|
+
static componentName = 'PointLight';
|
|
15
|
+
static space = '3d';
|
|
16
|
+
static displayName = 'Point light (3D)';
|
|
17
|
+
static params = {
|
|
18
|
+
color: { label: 'Color', kind: 'color' },
|
|
19
|
+
intensity: { label: 'Intensity', min: 0, step: 0.5 },
|
|
20
|
+
distance: { label: 'Distance (0 = unlimited)', min: 0, step: 0.5 },
|
|
21
|
+
decay: { label: 'Decay', min: 0, step: 0.1 },
|
|
22
|
+
offsetX: { label: 'x offset' },
|
|
23
|
+
offsetY: { label: 'y offset' },
|
|
24
|
+
offsetZ: { label: 'z offset' },
|
|
25
|
+
};
|
|
26
|
+
static transient = ['light'];
|
|
27
|
+
/** The three light, null in a 2D scene or before the component is ready. */
|
|
28
|
+
light = null;
|
|
29
|
+
_color = 0xffffff;
|
|
30
|
+
_intensity = 1;
|
|
31
|
+
_distance = 0;
|
|
32
|
+
_decay = 2;
|
|
33
|
+
_offsetX = 0;
|
|
34
|
+
_offsetY = 0;
|
|
35
|
+
_offsetZ = 0;
|
|
36
|
+
get color() {
|
|
37
|
+
return this._color;
|
|
38
|
+
}
|
|
39
|
+
set color(value) {
|
|
40
|
+
this._color = value;
|
|
41
|
+
this.light?.color.setHex(value);
|
|
42
|
+
}
|
|
43
|
+
get intensity() {
|
|
44
|
+
return this._intensity;
|
|
45
|
+
}
|
|
46
|
+
set intensity(value) {
|
|
47
|
+
this._intensity = value;
|
|
48
|
+
if (this.light)
|
|
49
|
+
this.light.intensity = value;
|
|
50
|
+
}
|
|
51
|
+
/** World units the light reaches; 0 reaches without limit. */
|
|
52
|
+
get distance() {
|
|
53
|
+
return this._distance;
|
|
54
|
+
}
|
|
55
|
+
set distance(value) {
|
|
56
|
+
this._distance = value;
|
|
57
|
+
if (this.light)
|
|
58
|
+
this.light.distance = value;
|
|
59
|
+
}
|
|
60
|
+
get decay() {
|
|
61
|
+
return this._decay;
|
|
62
|
+
}
|
|
63
|
+
set decay(value) {
|
|
64
|
+
this._decay = value;
|
|
65
|
+
if (this.light)
|
|
66
|
+
this.light.decay = value;
|
|
67
|
+
}
|
|
68
|
+
get offsetX() {
|
|
69
|
+
return this._offsetX;
|
|
70
|
+
}
|
|
71
|
+
set offsetX(value) {
|
|
72
|
+
this._offsetX = value;
|
|
73
|
+
this.place();
|
|
74
|
+
}
|
|
75
|
+
get offsetY() {
|
|
76
|
+
return this._offsetY;
|
|
77
|
+
}
|
|
78
|
+
set offsetY(value) {
|
|
79
|
+
this._offsetY = value;
|
|
80
|
+
this.place();
|
|
81
|
+
}
|
|
82
|
+
get offsetZ() {
|
|
83
|
+
return this._offsetZ;
|
|
84
|
+
}
|
|
85
|
+
set offsetZ(value) {
|
|
86
|
+
this._offsetZ = value;
|
|
87
|
+
this.place();
|
|
88
|
+
}
|
|
89
|
+
onReady() {
|
|
90
|
+
if (this.game.space !== '3d')
|
|
91
|
+
return;
|
|
92
|
+
this.light = new THREE.PointLight(this._color, this._intensity, this._distance, this._decay);
|
|
93
|
+
this.entity.node.add(this.light);
|
|
94
|
+
this.place();
|
|
95
|
+
}
|
|
96
|
+
onDestroy() {
|
|
97
|
+
this.light?.removeFromParent();
|
|
98
|
+
}
|
|
99
|
+
place() {
|
|
100
|
+
this.light?.position.set(this._offsetX, this._offsetY, this._offsetZ);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
2
|
+
import type { Vec3Json } from '../scene-camera-3d.js';
|
|
3
|
+
export type RigidBodyType = 'dynamic' | 'kinematic';
|
|
4
|
+
export declare const RIGID_BODY_TYPES: readonly RigidBodyType[];
|
|
5
|
+
/** A 3D vector as the body's public API reads and writes it. */
|
|
6
|
+
export interface BodyVector {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
z: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Makes the entity's `Collider` a body that moves (ADR 0028). A `dynamic` body
|
|
13
|
+
* is Rapier's: it falls under the scene's gravity, bounces, stacks and rests,
|
|
14
|
+
* and after every Simulation Step the engine writes the entity's position and
|
|
15
|
+
* rotation from it. A `kinematic` body is moved by code. It needs a `Collider`
|
|
16
|
+
* on the same entity (`validate_project` reports a body without one, and at
|
|
17
|
+
* runtime none is created). `mass` is the collider's mass; `velocity` is the
|
|
18
|
+
* initial linear velocity. A `kinematic` body is a character: every step the
|
|
19
|
+
* engine moves it through Rapier's character controller by its
|
|
20
|
+
* `desiredVelocity` on x and z and its own vertical velocity under gravity,
|
|
21
|
+
* stopping at walls, climbing steps up to `stepHeight` and slopes up to
|
|
22
|
+
* `maxSlope`, sticking to the ground within `snapDistance`, and pushing
|
|
23
|
+
* dynamic bodies it walks into. A param outside its range (`type` unknown,
|
|
24
|
+
* `mass` under the minimum, a `velocity` that is not three numbers) creates
|
|
25
|
+
* no body and warns once; `validate_project` reports it as
|
|
26
|
+
* `invalid-rigid-body-param`. A RigidBody in a 2D scene creates nothing.
|
|
27
|
+
*/
|
|
28
|
+
export declare class RigidBody extends Component {
|
|
29
|
+
static componentName: string;
|
|
30
|
+
static space: ComponentSpace;
|
|
31
|
+
static params: {
|
|
32
|
+
type: {
|
|
33
|
+
label: string;
|
|
34
|
+
options: RigidBodyType[];
|
|
35
|
+
};
|
|
36
|
+
mass: {
|
|
37
|
+
label: string;
|
|
38
|
+
min: number;
|
|
39
|
+
step: number;
|
|
40
|
+
};
|
|
41
|
+
gravityScale: {
|
|
42
|
+
label: string;
|
|
43
|
+
step: number;
|
|
44
|
+
};
|
|
45
|
+
linearDamping: {
|
|
46
|
+
label: string;
|
|
47
|
+
min: number;
|
|
48
|
+
step: number;
|
|
49
|
+
};
|
|
50
|
+
angularDamping: {
|
|
51
|
+
label: string;
|
|
52
|
+
min: number;
|
|
53
|
+
step: number;
|
|
54
|
+
};
|
|
55
|
+
lockRotations: {
|
|
56
|
+
label: string;
|
|
57
|
+
};
|
|
58
|
+
velocity: {
|
|
59
|
+
label: string;
|
|
60
|
+
kind: "vector3";
|
|
61
|
+
};
|
|
62
|
+
stepHeight: {
|
|
63
|
+
label: string;
|
|
64
|
+
min: number;
|
|
65
|
+
step: number;
|
|
66
|
+
};
|
|
67
|
+
maxSlope: {
|
|
68
|
+
label: string;
|
|
69
|
+
min: number;
|
|
70
|
+
max: number;
|
|
71
|
+
step: number;
|
|
72
|
+
};
|
|
73
|
+
snapDistance: {
|
|
74
|
+
label: string;
|
|
75
|
+
min: number;
|
|
76
|
+
step: number;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
static transient: string[];
|
|
80
|
+
type: RigidBodyType;
|
|
81
|
+
mass: number;
|
|
82
|
+
gravityScale: number;
|
|
83
|
+
linearDamping: number;
|
|
84
|
+
angularDamping: number;
|
|
85
|
+
lockRotations: boolean;
|
|
86
|
+
/** The initial linear velocity `[x, y, z]`, applied when the body is created. */
|
|
87
|
+
velocity: Vec3Json;
|
|
88
|
+
/** Kinematic only: the tallest step it climbs without jumping. */
|
|
89
|
+
stepHeight: number;
|
|
90
|
+
/** Kinematic only: the steepest slope it climbs, in degrees. */
|
|
91
|
+
maxSlope: number;
|
|
92
|
+
/** Kinematic only: how far below its feet it still sticks to the ground (walking down steps and slopes). */
|
|
93
|
+
snapDistance: number;
|
|
94
|
+
/**
|
|
95
|
+
* Kinematic only: where it walks, in units per second on the world x and z
|
|
96
|
+
* axes. A motor sets it; the physics step reads it every Simulation Step and
|
|
97
|
+
* moves the body through the character controller. It stays until set again.
|
|
98
|
+
*/
|
|
99
|
+
desiredVelocity: {
|
|
100
|
+
x: number;
|
|
101
|
+
z: number;
|
|
102
|
+
};
|
|
103
|
+
/** The body's linear velocity now, in units per second; zero before it exists. Assigning sets it. */
|
|
104
|
+
get linearVelocity(): BodyVector;
|
|
105
|
+
set linearVelocity(value: BodyVector);
|
|
106
|
+
/** Launches a kinematic body upward at `speed` (units per second), only while it stands on something; whether it did. */
|
|
107
|
+
jump(speed: number): boolean;
|
|
108
|
+
/** Whether the body stands on something; only a kinematic body moved by the character controller can. */
|
|
109
|
+
get grounded(): boolean;
|
|
110
|
+
/** Pushes a dynamic body with an instantaneous impulse (mass · velocity change); a no-op on any other body. */
|
|
111
|
+
applyImpulse(impulse: BodyVector): void;
|
|
112
|
+
onReady(): void;
|
|
113
|
+
onDestroy(): void;
|
|
114
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Component } from '../component.js';
|
|
2
|
+
export const RIGID_BODY_TYPES = ['dynamic', 'kinematic'];
|
|
3
|
+
const ZERO = { x: 0, y: 0, z: 0 };
|
|
4
|
+
/**
|
|
5
|
+
* Makes the entity's `Collider` a body that moves (ADR 0028). A `dynamic` body
|
|
6
|
+
* is Rapier's: it falls under the scene's gravity, bounces, stacks and rests,
|
|
7
|
+
* and after every Simulation Step the engine writes the entity's position and
|
|
8
|
+
* rotation from it. A `kinematic` body is moved by code. It needs a `Collider`
|
|
9
|
+
* on the same entity (`validate_project` reports a body without one, and at
|
|
10
|
+
* runtime none is created). `mass` is the collider's mass; `velocity` is the
|
|
11
|
+
* initial linear velocity. A `kinematic` body is a character: every step the
|
|
12
|
+
* engine moves it through Rapier's character controller by its
|
|
13
|
+
* `desiredVelocity` on x and z and its own vertical velocity under gravity,
|
|
14
|
+
* stopping at walls, climbing steps up to `stepHeight` and slopes up to
|
|
15
|
+
* `maxSlope`, sticking to the ground within `snapDistance`, and pushing
|
|
16
|
+
* dynamic bodies it walks into. A param outside its range (`type` unknown,
|
|
17
|
+
* `mass` under the minimum, a `velocity` that is not three numbers) creates
|
|
18
|
+
* no body and warns once; `validate_project` reports it as
|
|
19
|
+
* `invalid-rigid-body-param`. A RigidBody in a 2D scene creates nothing.
|
|
20
|
+
*/
|
|
21
|
+
export class RigidBody extends Component {
|
|
22
|
+
static componentName = 'RigidBody';
|
|
23
|
+
static space = '3d';
|
|
24
|
+
static params = {
|
|
25
|
+
type: { label: 'Type', options: [...RIGID_BODY_TYPES] },
|
|
26
|
+
mass: { label: 'Mass', min: 0.001, step: 0.1 },
|
|
27
|
+
gravityScale: { label: 'Gravity scale', step: 0.1 },
|
|
28
|
+
linearDamping: { label: 'Linear damping', min: 0, step: 0.1 },
|
|
29
|
+
angularDamping: { label: 'Angular damping', min: 0, step: 0.1 },
|
|
30
|
+
lockRotations: { label: 'Lock rotations' },
|
|
31
|
+
velocity: { label: 'Initial velocity', kind: 'vector3' },
|
|
32
|
+
stepHeight: { label: 'Step height', min: 0, step: 0.05 },
|
|
33
|
+
maxSlope: { label: 'Max slope (degrees)', min: 0, max: 89, step: 1 },
|
|
34
|
+
snapDistance: { label: 'Snap to ground', min: 0, step: 0.05 },
|
|
35
|
+
};
|
|
36
|
+
// Live reads and writes of the body, not authorable defaults (they need a Game to answer).
|
|
37
|
+
static transient = ['linearVelocity', 'desiredVelocity'];
|
|
38
|
+
type = 'dynamic';
|
|
39
|
+
mass = 1;
|
|
40
|
+
gravityScale = 1;
|
|
41
|
+
linearDamping = 0;
|
|
42
|
+
angularDamping = 0;
|
|
43
|
+
lockRotations = false;
|
|
44
|
+
/** The initial linear velocity `[x, y, z]`, applied when the body is created. */
|
|
45
|
+
velocity = [0, 0, 0];
|
|
46
|
+
/** Kinematic only: the tallest step it climbs without jumping. */
|
|
47
|
+
stepHeight = 0.3;
|
|
48
|
+
/** Kinematic only: the steepest slope it climbs, in degrees. */
|
|
49
|
+
maxSlope = 45;
|
|
50
|
+
/** Kinematic only: how far below its feet it still sticks to the ground (walking down steps and slopes). */
|
|
51
|
+
snapDistance = 0.2;
|
|
52
|
+
/**
|
|
53
|
+
* Kinematic only: where it walks, in units per second on the world x and z
|
|
54
|
+
* axes. A motor sets it; the physics step reads it every Simulation Step and
|
|
55
|
+
* moves the body through the character controller. It stays until set again.
|
|
56
|
+
*/
|
|
57
|
+
desiredVelocity = { x: 0, z: 0 };
|
|
58
|
+
/** The body's linear velocity now, in units per second; zero before it exists. Assigning sets it. */
|
|
59
|
+
get linearVelocity() {
|
|
60
|
+
return this.game.physics.velocityOf(this.entity) ?? { ...ZERO };
|
|
61
|
+
}
|
|
62
|
+
set linearVelocity(value) {
|
|
63
|
+
this.game.physics.setVelocityOf(this.entity, value);
|
|
64
|
+
}
|
|
65
|
+
/** Launches a kinematic body upward at `speed` (units per second), only while it stands on something; whether it did. */
|
|
66
|
+
jump(speed) {
|
|
67
|
+
return this.game.physics.jumpOf(this.entity, speed);
|
|
68
|
+
}
|
|
69
|
+
/** Whether the body stands on something; only a kinematic body moved by the character controller can. */
|
|
70
|
+
get grounded() {
|
|
71
|
+
return this.game.physics.groundedOf(this.entity);
|
|
72
|
+
}
|
|
73
|
+
/** Pushes a dynamic body with an instantaneous impulse (mass · velocity change); a no-op on any other body. */
|
|
74
|
+
applyImpulse(impulse) {
|
|
75
|
+
this.game.physics.applyImpulseTo(this.entity, impulse);
|
|
76
|
+
}
|
|
77
|
+
onReady() {
|
|
78
|
+
this.game.physics.attach(this.entity);
|
|
79
|
+
}
|
|
80
|
+
onDestroy() {
|
|
81
|
+
this.game.physics.detach(this.entity);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from '../component.js';
|
|
1
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
2
2
|
import { type CollisionPoint, type CollisionShape } from '../collision-shape.js';
|
|
3
3
|
/**
|
|
4
4
|
* Static collider. Character motors (e.g. PlatformerMotor) collide against
|
|
@@ -9,6 +9,7 @@ import { type CollisionPoint, type CollisionShape } from '../collision-shape.js'
|
|
|
9
9
|
*/
|
|
10
10
|
export declare class Solid extends Component {
|
|
11
11
|
static componentName: string;
|
|
12
|
+
static space: ComponentSpace;
|
|
12
13
|
static params: {
|
|
13
14
|
offsetX: {
|
|
14
15
|
label: string;
|
package/dist/components/solid.js
CHANGED
|
@@ -9,6 +9,7 @@ import { collisionBounds, resolveCollisionPoints, } from '../collision-shape.js'
|
|
|
9
9
|
*/
|
|
10
10
|
export class Solid extends Component {
|
|
11
11
|
static componentName = 'Solid';
|
|
12
|
+
static space = '2d';
|
|
12
13
|
static params = {
|
|
13
14
|
offsetX: { label: 'x offset' },
|
|
14
15
|
offsetY: { label: 'y offset' },
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Component } from '../component.js';
|
|
1
|
+
import { Component, type ComponentSpace } from '../component.js';
|
|
2
2
|
import type { YSortParticipant } from '../render-sort.js';
|
|
3
3
|
export type SpriteShape = 'rectangle' | 'circle';
|
|
4
4
|
/**
|
|
@@ -7,6 +7,7 @@ export type SpriteShape = 'rectangle' | 'circle';
|
|
|
7
7
|
*/
|
|
8
8
|
export declare class Sprite extends Component implements YSortParticipant {
|
|
9
9
|
static componentName: string;
|
|
10
|
+
static space: ComponentSpace;
|
|
10
11
|
static params: {
|
|
11
12
|
offsetX: {
|
|
12
13
|
label: string;
|
|
@@ -11,6 +11,7 @@ const clampAnchor = (value) => Math.min(1, Math.max(0, value));
|
|
|
11
11
|
*/
|
|
12
12
|
export class Sprite extends Component {
|
|
13
13
|
static componentName = 'Sprite';
|
|
14
|
+
static space = '2d';
|
|
14
15
|
static params = {
|
|
15
16
|
offsetX: { label: 'x offset' },
|
|
16
17
|
offsetY: { label: 'y offset' },
|