emeraldengine 2.2.1 → 3.0.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 +2359 -968
- package/dist/types/index.d.ts +72 -32
- package/dist/types/src/Animator.d.ts +50 -0
- package/dist/types/{BitmapText.d.ts → src/BitmapText.d.ts} +19 -21
- package/dist/types/src/Camera.d.ts +122 -0
- package/dist/types/src/CameraController.d.ts +107 -0
- package/dist/types/src/CanvasText.d.ts +91 -0
- package/dist/types/src/CollisionLayers.d.ts +58 -0
- package/dist/types/{Color.d.ts → src/Color.d.ts} +5 -6
- package/dist/types/src/Coroutine.d.ts +111 -0
- package/dist/types/src/DebugOverlay.d.ts +86 -0
- package/dist/types/src/Drawable.d.ts +271 -0
- package/dist/types/src/Easing.d.ts +22 -0
- package/dist/types/src/Emerald.d.ts +420 -0
- package/dist/types/src/EmeraldDB.d.ts +159 -0
- package/dist/types/{FPSCounter.d.ts → src/FPSCounter.d.ts} +1 -3
- package/dist/types/src/GLUtils.d.ts +4 -0
- package/dist/types/{Instance.d.ts → src/Instance.d.ts} +37 -15
- package/dist/types/{InstancedTexture.d.ts → src/InstancedTexture.d.ts} +60 -23
- package/dist/types/src/Interpolator.d.ts +66 -0
- package/dist/types/src/Material.d.ts +87 -0
- package/dist/types/src/MathUtils.d.ts +80 -0
- package/dist/types/src/ParticleEmitter.d.ts +131 -0
- package/dist/types/{Physics.d.ts → src/Physics.d.ts} +88 -20
- package/dist/types/src/Pool.d.ts +53 -0
- package/dist/types/src/PostEffects.d.ts +68 -0
- package/dist/types/src/PostProcessor.d.ts +124 -0
- package/dist/types/src/RenderTarget.d.ts +56 -0
- package/dist/types/src/Scene.d.ts +62 -0
- package/dist/types/src/ScreenEffects.d.ts +111 -0
- package/dist/types/src/Serializer.d.ts +86 -0
- package/dist/types/src/Shaders.d.ts +2 -0
- package/dist/types/{Shapes.d.ts → src/Shapes.d.ts} +4 -6
- package/dist/types/src/SpatialGrid.d.ts +50 -0
- package/dist/types/src/SpriteBatch.d.ts +89 -0
- package/dist/types/src/StateMachine.d.ts +59 -0
- package/dist/types/src/Storage.d.ts +89 -0
- package/dist/types/{Texture.d.ts → src/Texture.d.ts} +3 -4
- package/dist/types/src/TextureAtlas.d.ts +55 -0
- package/dist/types/src/Tilemap.d.ts +91 -0
- package/dist/types/src/Time.d.ts +53 -0
- package/dist/types/src/Timer.d.ts +54 -0
- package/dist/types/src/Transform.d.ts +94 -0
- package/dist/types/src/Tween.d.ts +81 -0
- package/dist/types/src/UI.d.ts +121 -0
- package/dist/types/src/components/Behaviour.d.ts +71 -0
- package/dist/types/{components → src/components}/BoxCollider.d.ts +14 -14
- package/dist/types/src/components/BoxColliderDebug.d.ts +15 -0
- package/dist/types/{components → src/components}/CircleCollider.d.ts +14 -12
- package/dist/types/src/components/CircleColliderDebug.d.ts +15 -0
- package/dist/types/src/components/Collider.d.ts +96 -0
- package/dist/types/src/components/GameObject.d.ts +135 -0
- package/dist/types/src/components/RigidBody.d.ts +183 -0
- package/dist/types/src/importers/Aseprite.d.ts +79 -0
- package/dist/types/src/importers/TiledMap.d.ts +62 -0
- package/dist/types/{lights → src/lights}/DirectionalLight.d.ts +7 -9
- package/dist/types/{lights → src/lights}/PointLight.d.ts +6 -9
- package/dist/types/src/managers/AssetManager.d.ts +116 -0
- package/dist/types/src/managers/AudioManager.d.ts +259 -0
- package/dist/types/{managers → src/managers}/CameraManager.d.ts +8 -8
- package/dist/types/{managers → src/managers}/EventManager.d.ts +46 -32
- package/dist/types/src/managers/GLManager.d.ts +84 -0
- package/dist/types/src/managers/GLState.d.ts +37 -0
- package/dist/types/src/managers/IDManager.d.ts +31 -0
- package/dist/types/src/managers/InputManager.d.ts +290 -0
- package/dist/types/src/managers/NetworkManager.d.ts +93 -0
- package/dist/types/src/managers/RenderStats.d.ts +34 -0
- package/dist/types/src/managers/SceneManager.d.ts +44 -0
- package/dist/types/src/managers/ShaderManager.d.ts +55 -0
- package/dist/types/src/managers/TextureManager.d.ts +102 -0
- package/dist/types/src/particlesystem/Particle.d.ts +64 -0
- package/dist/types/{particlesystem → src/particlesystem}/ParticleSettings.d.ts +32 -24
- package/dist/types/{particlesystem → src/particlesystem}/Particles.d.ts +20 -12
- package/index.js +72 -0
- package/package.json +74 -60
- package/src/Animator.js +95 -0
- package/src/BitmapText.js +6 -5
- package/src/Camera.js +183 -0
- package/src/CameraController.js +192 -0
- package/src/CanvasText.js +281 -0
- package/src/CollisionLayers.js +86 -0
- package/src/Color.js +18 -18
- package/src/Coroutine.js +259 -0
- package/src/DebugOverlay.js +246 -0
- package/src/Drawable.js +842 -582
- package/src/Easing.js +57 -0
- package/src/Emerald.js +1150 -459
- package/src/EmeraldDB.js +328 -0
- package/src/FPSCounter.js +43 -43
- package/src/GLUtils.js +60 -67
- package/src/Instance.js +41 -5
- package/src/InstancedTexture.js +251 -118
- package/src/Interpolator.js +124 -0
- package/src/Material.js +202 -0
- package/src/MathUtils.js +133 -0
- package/src/ParticleEmitter.js +284 -0
- package/src/Physics.js +186 -5
- package/src/Pool.js +85 -0
- package/src/PostEffects.js +296 -0
- package/src/PostProcessor.js +304 -0
- package/src/RenderTarget.js +134 -0
- package/src/Scene.js +115 -83
- package/src/ScreenEffects.js +266 -0
- package/src/Serializer.js +131 -0
- package/src/Shaders.js +150 -165
- package/src/Shapes.js +118 -129
- package/src/SpatialGrid.js +111 -0
- package/src/SpriteBatch.js +299 -0
- package/src/StateMachine.js +82 -0
- package/src/Storage.js +175 -47
- package/src/Texture.js +58 -67
- package/src/TextureAtlas.js +96 -0
- package/src/Tilemap.js +274 -0
- package/src/Time.js +51 -6
- package/src/Timer.js +99 -0
- package/src/Transform.js +100 -7
- package/src/Tween.js +160 -0
- package/src/UI.js +394 -0
- package/src/components/Behaviour.js +90 -0
- package/src/components/BoxCollider.js +22 -3
- package/src/components/CircleCollider.js +19 -3
- package/src/components/CircleColliderDebug.js +24 -24
- package/src/components/Collider.js +140 -34
- package/src/components/GameObject.js +130 -21
- package/src/components/RigidBody.js +123 -2
- package/src/importers/Aseprite.js +142 -0
- package/src/importers/TiledMap.js +158 -0
- package/src/lights/DirectionalLight.js +6 -15
- package/src/lights/PointLight.js +4 -4
- package/src/managers/AssetManager.js +239 -0
- package/src/managers/AudioManager.js +565 -146
- package/src/managers/EventManager.js +488 -477
- package/src/managers/GLManager.js +57 -0
- package/src/managers/GLState.js +70 -0
- package/src/managers/IDManager.js +24 -2
- package/src/managers/InputManager.js +779 -0
- package/src/managers/NetworkManager.js +178 -0
- package/src/managers/RenderStats.js +34 -0
- package/src/managers/SceneManager.js +30 -0
- package/src/managers/ShaderManager.js +0 -2
- package/src/managers/TextureManager.js +218 -0
- package/src/particlesystem/Particle.js +82 -7
- package/src/particlesystem/ParticleSettings.js +21 -3
- package/src/particlesystem/Particles.js +80 -31
- package/dist/types/Drawable.d.ts +0 -157
- package/dist/types/Emerald.d.ts +0 -73
- package/dist/types/GLUtils.d.ts +0 -6
- package/dist/types/Scene.d.ts +0 -39
- package/dist/types/Shaders.d.ts +0 -4
- package/dist/types/Storage.d.ts +0 -46
- package/dist/types/Time.d.ts +0 -22
- package/dist/types/Transform.d.ts +0 -41
- package/dist/types/components/BoxColliderDebug.d.ts +0 -19
- package/dist/types/components/CircleColliderDebug.d.ts +0 -19
- package/dist/types/components/Collider.d.ts +0 -53
- package/dist/types/components/GameObject.d.ts +0 -72
- package/dist/types/components/RigidBody.d.ts +0 -104
- package/dist/types/managers/AudioManager.d.ts +0 -60
- package/dist/types/managers/GLManager.d.ts +0 -47
- package/dist/types/managers/IDManager.d.ts +0 -21
- package/dist/types/managers/SceneManager.d.ts +0 -22
- package/dist/types/particlesystem/Particle.d.ts +0 -42
package/src/Tilemap.js
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import GameObject from "./components/GameObject.js";
|
|
2
|
+
import InstancedTexture from "./InstancedTexture.js";
|
|
3
|
+
import Instance from "./Instance.js";
|
|
4
|
+
import RigidBody from "./components/RigidBody.js";
|
|
5
|
+
import BoxCollider from "./components/BoxCollider.js";
|
|
6
|
+
import { Vector2, Vector3 } from "./Physics.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @class Tilemap
|
|
10
|
+
* @description Builds a grid of tiles from a 2D array of frame indices, rendered
|
|
11
|
+
* as a single instanced draw call. Use -1 (or null) for empty cells. The tiles
|
|
12
|
+
* live on `tilemap.gameObject`, which you add to the scene.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const map = new Tilemap("level", "tiles.png", {
|
|
16
|
+
* tileSize: 32, frameWidth: 16, frameHeight: 16, framesPerRow: 4, totalFrames: 16,
|
|
17
|
+
* });
|
|
18
|
+
* map.setMap([
|
|
19
|
+
* [0, 0, 0, 0],
|
|
20
|
+
* [1, -1, -1, 1],
|
|
21
|
+
* [2, 2, 2, 2],
|
|
22
|
+
* ]);
|
|
23
|
+
* scene.add(map.gameObject);
|
|
24
|
+
*/
|
|
25
|
+
class Tilemap {
|
|
26
|
+
/**
|
|
27
|
+
* @param {string} name - Name for the underlying GameObject
|
|
28
|
+
* @param {string} texturePath - Path to the tile sheet
|
|
29
|
+
* @param {Object} [options] - tileSize, frameWidth, frameHeight, framesPerRow, totalFrames, pixelart
|
|
30
|
+
*/
|
|
31
|
+
constructor(name, texturePath, options = {}) {
|
|
32
|
+
const {
|
|
33
|
+
tileSize = 32,
|
|
34
|
+
frameWidth = tileSize,
|
|
35
|
+
frameHeight = tileSize,
|
|
36
|
+
framesPerRow = 1,
|
|
37
|
+
totalFrames = 1,
|
|
38
|
+
pixelart = true,
|
|
39
|
+
} = options;
|
|
40
|
+
|
|
41
|
+
this.name = name;
|
|
42
|
+
this.tileSize = tileSize;
|
|
43
|
+
/** @private */
|
|
44
|
+
this._config = {
|
|
45
|
+
texturePath,
|
|
46
|
+
frameWidth,
|
|
47
|
+
frameHeight,
|
|
48
|
+
framesPerRow,
|
|
49
|
+
totalFrames,
|
|
50
|
+
pixelart,
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
this.gameObject = new GameObject(
|
|
54
|
+
name,
|
|
55
|
+
new Vector3(0, 0, 0),
|
|
56
|
+
0,
|
|
57
|
+
new Vector2(1, 1)
|
|
58
|
+
);
|
|
59
|
+
this.texture = null;
|
|
60
|
+
|
|
61
|
+
/** @private */
|
|
62
|
+
this._map = null;
|
|
63
|
+
/** @private */
|
|
64
|
+
this._layout = null;
|
|
65
|
+
/** @private */
|
|
66
|
+
this._colliders = [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @method setMap
|
|
71
|
+
* @description Builds (or rebuilds) the tile instances from a 2D array.
|
|
72
|
+
* @param {number[][]} map - Rows of frame indices (-1/null = empty)
|
|
73
|
+
* @param {Object} [options] - { originX = 0, originY = 0, flipY = true }
|
|
74
|
+
* @returns {Tilemap} - this
|
|
75
|
+
*/
|
|
76
|
+
setMap(map, options = {}) {
|
|
77
|
+
const { originX = 0, originY = 0, flipY = true } = options;
|
|
78
|
+
const rows = map.length;
|
|
79
|
+
const cols = map.reduce(
|
|
80
|
+
(max, row) => Math.max(max, row ? row.length : 0),
|
|
81
|
+
0
|
|
82
|
+
);
|
|
83
|
+
const count = Math.max(1, rows * cols);
|
|
84
|
+
|
|
85
|
+
this._map = map;
|
|
86
|
+
this._layout = { originX, originY, flipY, rows, cols };
|
|
87
|
+
|
|
88
|
+
const existing = this.gameObject.getComponent(InstancedTexture);
|
|
89
|
+
if (existing) this.gameObject.removeComponent(existing);
|
|
90
|
+
|
|
91
|
+
this.texture = new InstancedTexture(
|
|
92
|
+
this._config.texturePath,
|
|
93
|
+
count,
|
|
94
|
+
this._config.frameWidth,
|
|
95
|
+
this._config.frameHeight,
|
|
96
|
+
this._config.framesPerRow,
|
|
97
|
+
this._config.totalFrames,
|
|
98
|
+
0,
|
|
99
|
+
false,
|
|
100
|
+
this._config.pixelart
|
|
101
|
+
);
|
|
102
|
+
this.texture.clearInstances();
|
|
103
|
+
|
|
104
|
+
const half = this.tileSize / 2;
|
|
105
|
+
for (let r = 0; r < rows; r++) {
|
|
106
|
+
const row = map[r];
|
|
107
|
+
if (!row) continue;
|
|
108
|
+
for (let c = 0; c < row.length; c++) {
|
|
109
|
+
const frame = row[c];
|
|
110
|
+
if (frame == null || frame < 0) continue;
|
|
111
|
+
const rowIndex = flipY ? rows - 1 - r : r;
|
|
112
|
+
const x = originX + c * this.tileSize + half;
|
|
113
|
+
const y = originY + rowIndex * this.tileSize + half;
|
|
114
|
+
this.texture.addInstance(
|
|
115
|
+
new Instance(
|
|
116
|
+
`${this.name}_${r}_${c}`,
|
|
117
|
+
new Vector3(x, y, 0),
|
|
118
|
+
new Vector2(half, half),
|
|
119
|
+
0,
|
|
120
|
+
frame
|
|
121
|
+
)
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.texture.setStatic(true);
|
|
127
|
+
this.gameObject.addComponent(this.texture);
|
|
128
|
+
return this;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @method buildColliders
|
|
133
|
+
* @description Generates static physics colliders from the current map. Solid
|
|
134
|
+
* cells are merged greedily into horizontal runs, so a row of N tiles becomes
|
|
135
|
+
* one box collider instead of N — far fewer bodies for the physics engine.
|
|
136
|
+
* The bodies are tagged so collision callbacks resolve back to `ownerObject`
|
|
137
|
+
* (defaults to the tilemap's GameObject). Call again after setMap to rebuild.
|
|
138
|
+
*
|
|
139
|
+
* @param {Physics} physics - The physics engine
|
|
140
|
+
* @param {Object} [options] - { isSolid, friction = 0.2, restitution = 0,
|
|
141
|
+
* density = 0, ownerObject }
|
|
142
|
+
* @returns {Tilemap} - this
|
|
143
|
+
*/
|
|
144
|
+
buildColliders(physics, options = {}) {
|
|
145
|
+
if (!this._map || !this._layout) return this;
|
|
146
|
+
const {
|
|
147
|
+
isSolid = (frame) => frame != null && frame >= 0,
|
|
148
|
+
friction = 0.2,
|
|
149
|
+
restitution = 0,
|
|
150
|
+
density = 0,
|
|
151
|
+
ownerObject = this.gameObject,
|
|
152
|
+
} = options;
|
|
153
|
+
|
|
154
|
+
this.clearColliders();
|
|
155
|
+
|
|
156
|
+
const { originX, originY, flipY, rows } = this._layout;
|
|
157
|
+
const ts = this.tileSize;
|
|
158
|
+
const half = ts / 2;
|
|
159
|
+
const scale = physics.getScale();
|
|
160
|
+
|
|
161
|
+
for (let r = 0; r < rows; r++) {
|
|
162
|
+
const row = this._map[r];
|
|
163
|
+
if (!row) continue;
|
|
164
|
+
let c = 0;
|
|
165
|
+
while (c < row.length) {
|
|
166
|
+
if (!isSolid(row[c])) {
|
|
167
|
+
c++;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
let runStart = c;
|
|
171
|
+
while (c < row.length && isSolid(row[c])) c++;
|
|
172
|
+
const runLen = c - runStart;
|
|
173
|
+
|
|
174
|
+
const rowIndex = flipY ? rows - 1 - r : r;
|
|
175
|
+
const runWidth = runLen * ts;
|
|
176
|
+
const centerX = originX + runStart * ts + runWidth / 2;
|
|
177
|
+
const centerY = originY + rowIndex * ts + half;
|
|
178
|
+
|
|
179
|
+
const body = new RigidBody(
|
|
180
|
+
physics,
|
|
181
|
+
"static",
|
|
182
|
+
new Vector2(centerX, centerY),
|
|
183
|
+
true,
|
|
184
|
+
ownerObject,
|
|
185
|
+
new Vector2(0, 0)
|
|
186
|
+
);
|
|
187
|
+
new BoxCollider(
|
|
188
|
+
body,
|
|
189
|
+
new Vector2(runWidth / 2 / scale, half / scale),
|
|
190
|
+
density,
|
|
191
|
+
friction,
|
|
192
|
+
restitution,
|
|
193
|
+
false,
|
|
194
|
+
ownerObject
|
|
195
|
+
);
|
|
196
|
+
this._colliders.push(body);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @method clearColliders
|
|
204
|
+
* @description Destroys the physics bodies created by buildColliders.
|
|
205
|
+
* @returns {Tilemap} - this
|
|
206
|
+
*/
|
|
207
|
+
clearColliders() {
|
|
208
|
+
for (const body of this._colliders) {
|
|
209
|
+
if (body && typeof body.destroy === "function") body.destroy();
|
|
210
|
+
}
|
|
211
|
+
this._colliders = [];
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* @method setAutoTiledMap
|
|
217
|
+
* @description Convenience: computes frame indices from a solidity grid using
|
|
218
|
+
* bitmask auto-tiling, then builds the map. See Tilemap.computeAutoTile.
|
|
219
|
+
* @param {Array<Array<boolean|number>>} solidGrid - Truthy = solid cell
|
|
220
|
+
* @param {Object} [options] - Auto-tile options + setMap options
|
|
221
|
+
* @returns {Tilemap} - this
|
|
222
|
+
*/
|
|
223
|
+
setAutoTiledMap(solidGrid, options = {}) {
|
|
224
|
+
const frames = Tilemap.computeAutoTile(solidGrid, options);
|
|
225
|
+
return this.setMap(frames, options);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @method computeAutoTile
|
|
230
|
+
* @description Pure helper that converts a 2D solidity grid into a 2D frame
|
|
231
|
+
* index grid using 4-bit edge bitmasking. For each solid cell the neighbor
|
|
232
|
+
* mask is built as up|right|down|left (bits 1,2,4,8); empty cells become -1.
|
|
233
|
+
* Provide `frames` (a length-16 lookup from mask -> frame index) to match your
|
|
234
|
+
* tilesheet layout; otherwise the mask itself is used as the frame index, and
|
|
235
|
+
* `base` is added to every solid frame.
|
|
236
|
+
*
|
|
237
|
+
* @param {Array<Array<boolean|number>>} grid - Truthy = solid
|
|
238
|
+
* @param {Object} [options] - { frames, base = 0, edgesSolid = true }
|
|
239
|
+
* @returns {number[][]} - Frame indices (-1 for empty)
|
|
240
|
+
*/
|
|
241
|
+
static computeAutoTile(grid, options = {}) {
|
|
242
|
+
const { frames = null, base = 0, edgesSolid = true } = options;
|
|
243
|
+
const rows = grid.length;
|
|
244
|
+
const out = [];
|
|
245
|
+
const solidAt = (r, c) => {
|
|
246
|
+
if (r < 0 || c < 0 || r >= rows || !grid[r] || c >= grid[r].length) {
|
|
247
|
+
return edgesSolid;
|
|
248
|
+
}
|
|
249
|
+
return !!grid[r][c];
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
for (let r = 0; r < rows; r++) {
|
|
253
|
+
const row = grid[r] || [];
|
|
254
|
+
const outRow = [];
|
|
255
|
+
for (let c = 0; c < row.length; c++) {
|
|
256
|
+
if (!row[c]) {
|
|
257
|
+
outRow.push(-1);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
let mask = 0;
|
|
261
|
+
if (solidAt(r - 1, c)) mask |= 1;
|
|
262
|
+
if (solidAt(r, c + 1)) mask |= 2;
|
|
263
|
+
if (solidAt(r + 1, c)) mask |= 4;
|
|
264
|
+
if (solidAt(r, c - 1)) mask |= 8;
|
|
265
|
+
const frame = frames ? frames[mask] : mask;
|
|
266
|
+
outRow.push(base + (frame == null ? 0 : frame));
|
|
267
|
+
}
|
|
268
|
+
out.push(outRow);
|
|
269
|
+
}
|
|
270
|
+
return out;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export default Tilemap;
|
package/src/Time.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @class Time
|
|
3
|
-
* @description
|
|
4
|
-
*
|
|
3
|
+
* @description Global time state for the game. `deltaTime` is the (scaled)
|
|
4
|
+
* seconds since the last frame, `elapsedTime` accumulates total scaled time, and
|
|
5
|
+
* `timeScale` lets you slow down / speed up / pause the simulation.
|
|
5
6
|
*/
|
|
6
7
|
class Time {
|
|
7
8
|
/**
|
|
8
9
|
* @method getDeltaTime
|
|
9
|
-
* @description Returns the delta time
|
|
10
|
+
* @description Returns the (time-scaled) delta time in seconds
|
|
10
11
|
* @returns {number} - The delta time
|
|
11
12
|
*/
|
|
12
13
|
static getDeltaTime() {
|
|
@@ -15,14 +16,58 @@ class Time {
|
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @method setDeltaTime
|
|
18
|
-
* @description Sets the delta time
|
|
19
|
-
*
|
|
19
|
+
* @description Sets the delta time. The stored value is multiplied by
|
|
20
|
+
* `timeScale`, and `elapsedTime` is advanced by the scaled amount. Called by
|
|
21
|
+
* `Emerald.drawScene`, but can be called manually for custom loops.
|
|
22
|
+
* @param {number} deltaTime - The unscaled delta time in seconds
|
|
20
23
|
*/
|
|
21
24
|
static setDeltaTime(deltaTime) {
|
|
22
|
-
|
|
25
|
+
const scaled = deltaTime * Time.timeScale;
|
|
26
|
+
Time.unscaledDeltaTime = deltaTime;
|
|
27
|
+
Time.deltaTime = scaled;
|
|
28
|
+
Time.elapsedTime += scaled;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @method getUnscaledDeltaTime
|
|
33
|
+
* @description Returns the raw delta time, ignoring timeScale
|
|
34
|
+
* @returns {number} - The unscaled delta time
|
|
35
|
+
*/
|
|
36
|
+
static getUnscaledDeltaTime() {
|
|
37
|
+
return Time.unscaledDeltaTime;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @method getElapsedTime
|
|
42
|
+
* @description Returns the total accumulated (scaled) time in seconds
|
|
43
|
+
* @returns {number} - The elapsed time
|
|
44
|
+
*/
|
|
45
|
+
static getElapsedTime() {
|
|
46
|
+
return Time.elapsedTime;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @method setTimeScale
|
|
51
|
+
* @description Sets the time scale (1 = normal, 0 = paused, 2 = double speed)
|
|
52
|
+
* @param {number} scale - The time scale (clamped to >= 0)
|
|
53
|
+
*/
|
|
54
|
+
static setTimeScale(scale) {
|
|
55
|
+
Time.timeScale = Math.max(0, scale);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @method getTimeScale
|
|
60
|
+
* @description Returns the current time scale
|
|
61
|
+
* @returns {number} - The time scale
|
|
62
|
+
*/
|
|
63
|
+
static getTimeScale() {
|
|
64
|
+
return Time.timeScale;
|
|
23
65
|
}
|
|
24
66
|
}
|
|
25
67
|
|
|
26
68
|
Time.deltaTime = 0;
|
|
69
|
+
Time.unscaledDeltaTime = 0;
|
|
70
|
+
Time.elapsedTime = 0;
|
|
71
|
+
Time.timeScale = 1;
|
|
27
72
|
|
|
28
73
|
export default Time;
|
package/src/Timer.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @class Timer
|
|
3
|
+
* @description Schedules delayed and repeating callbacks measured in seconds.
|
|
4
|
+
* Driven by `Emerald.drawScene` with time-scaled delta, so timers honor
|
|
5
|
+
* pause/slow-mo. Each scheduler call returns a handle you can pass to `clear`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* Timer.after(2, () => spawnEnemy()); // once, after 2s
|
|
9
|
+
* Timer.every(0.5, () => tick(), 10); // 10 times, every 0.5s
|
|
10
|
+
* const h = Timer.every(1, () => poll()); // forever until cleared
|
|
11
|
+
* Timer.clear(h);
|
|
12
|
+
*/
|
|
13
|
+
class Timer {
|
|
14
|
+
/**
|
|
15
|
+
* @method after
|
|
16
|
+
* @description Runs a callback once after a delay.
|
|
17
|
+
* @param {number} seconds - Delay in seconds
|
|
18
|
+
* @param {Function} callback
|
|
19
|
+
* @returns {Object} - A handle for clear()
|
|
20
|
+
*/
|
|
21
|
+
static after(seconds, callback) {
|
|
22
|
+
return Timer._add(seconds, callback, 1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @method every
|
|
27
|
+
* @description Runs a callback repeatedly on an interval.
|
|
28
|
+
* @param {number} seconds - Interval in seconds
|
|
29
|
+
* @param {Function} callback
|
|
30
|
+
* @param {number} [repeats] - Number of repeats (default Infinity)
|
|
31
|
+
* @returns {Object} - A handle for clear()
|
|
32
|
+
*/
|
|
33
|
+
static every(seconds, callback, repeats = Infinity) {
|
|
34
|
+
return Timer._add(seconds, callback, repeats);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** @private */
|
|
38
|
+
static _add(interval, callback, repeats) {
|
|
39
|
+
const entry = {
|
|
40
|
+
interval: Math.max(0, interval),
|
|
41
|
+
callback,
|
|
42
|
+
repeats,
|
|
43
|
+
elapsed: 0,
|
|
44
|
+
cancelled: false,
|
|
45
|
+
};
|
|
46
|
+
Timer.entries.push(entry);
|
|
47
|
+
return entry;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* @method clear
|
|
52
|
+
* @description Cancels a scheduled timer by its handle.
|
|
53
|
+
* @param {Object} handle - The handle returned by after/every
|
|
54
|
+
*/
|
|
55
|
+
static clear(handle) {
|
|
56
|
+
if (handle) handle.cancelled = true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @method clearAll
|
|
61
|
+
* @description Cancels all timers.
|
|
62
|
+
*/
|
|
63
|
+
static clearAll() {
|
|
64
|
+
Timer.entries.length = 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @method update
|
|
69
|
+
* @description Advances all timers. Driven by Emerald.drawScene.
|
|
70
|
+
* @param {number} dt - Seconds since the last frame
|
|
71
|
+
*/
|
|
72
|
+
static update(dt) {
|
|
73
|
+
const entries = Timer.entries;
|
|
74
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
75
|
+
const entry = entries[i];
|
|
76
|
+
if (entry.cancelled) {
|
|
77
|
+
entries.splice(i, 1);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
entry.elapsed += dt;
|
|
82
|
+
while (!entry.cancelled && entry.elapsed >= entry.interval) {
|
|
83
|
+
entry.elapsed -= entry.interval;
|
|
84
|
+
entry.repeats -= 1;
|
|
85
|
+
entry.callback();
|
|
86
|
+
if (entry.repeats <= 0) {
|
|
87
|
+
entry.cancelled = true;
|
|
88
|
+
}
|
|
89
|
+
if (entry.interval === 0) break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (entry.cancelled) entries.splice(i, 1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Timer.entries = [];
|
|
98
|
+
|
|
99
|
+
export default Timer;
|
package/src/Transform.js
CHANGED
|
@@ -1,15 +1,108 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @class Transform
|
|
3
|
-
* @description Represents a transform
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* @description Represents a transform with optional parent/child hierarchy.
|
|
4
|
+
* Local position/rotation/scale are composed up the parent chain to produce a
|
|
5
|
+
* world transform. Objects with no parent behave exactly as before (the world
|
|
6
|
+
* transform is the local transform), so existing code is unaffected.
|
|
7
|
+
* @param {Vector3} position - The local position
|
|
8
|
+
* @param {number} rotation - The local rotation (radians)
|
|
9
|
+
* @param {Vector2} scale - The local scale
|
|
7
10
|
*/
|
|
8
11
|
class Transform {
|
|
9
12
|
constructor(position, rotation, scale) {
|
|
10
13
|
this.position = position;
|
|
11
14
|
this.rotation = rotation;
|
|
12
15
|
this.scale = scale;
|
|
16
|
+
|
|
17
|
+
this.parent = null;
|
|
18
|
+
this.children = [];
|
|
19
|
+
|
|
20
|
+
/** @private */
|
|
21
|
+
this._world = {
|
|
22
|
+
position: { x: 0, y: 0, z: 0 },
|
|
23
|
+
rotation: 0,
|
|
24
|
+
scale: { x: 1, y: 1 },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @method setParent
|
|
30
|
+
* @description Sets (or clears) the parent transform, maintaining the
|
|
31
|
+
* children list on both sides.
|
|
32
|
+
* @param {Transform|null} parent - The parent transform, or null to detach
|
|
33
|
+
*/
|
|
34
|
+
setParent(parent) {
|
|
35
|
+
if (this.parent === parent) return;
|
|
36
|
+
if (this.parent) {
|
|
37
|
+
const idx = this.parent.children.indexOf(this);
|
|
38
|
+
if (idx !== -1) this.parent.children.splice(idx, 1);
|
|
39
|
+
}
|
|
40
|
+
this.parent = parent || null;
|
|
41
|
+
if (this.parent && this.parent.children.indexOf(this) === -1) {
|
|
42
|
+
this.parent.children.push(this);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @method getWorldParts
|
|
48
|
+
* @description Returns the composed world TRS as primitives. Composition is
|
|
49
|
+
* standard 2D: child local space is scaled and rotated by the parent.
|
|
50
|
+
* @returns {{px:number, py:number, pz:number, rot:number, sx:number, sy:number}}
|
|
51
|
+
*/
|
|
52
|
+
getWorldParts() {
|
|
53
|
+
if (!this.parent) {
|
|
54
|
+
return {
|
|
55
|
+
px: this.position.x,
|
|
56
|
+
py: this.position.y,
|
|
57
|
+
pz: this.position.z,
|
|
58
|
+
rot: this.rotation,
|
|
59
|
+
sx: this.scale.x,
|
|
60
|
+
sy: this.scale.y,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const p = this.parent.getWorldParts();
|
|
65
|
+
const cos = Math.cos(p.rot);
|
|
66
|
+
const sin = Math.sin(p.rot);
|
|
67
|
+
const lx = this.position.x * p.sx;
|
|
68
|
+
const ly = this.position.y * p.sy;
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
px: p.px + (lx * cos - ly * sin),
|
|
72
|
+
py: p.py + (lx * sin + ly * cos),
|
|
73
|
+
pz: p.pz + this.position.z,
|
|
74
|
+
rot: p.rot + this.rotation,
|
|
75
|
+
sx: p.sx * this.scale.x,
|
|
76
|
+
sy: p.sy * this.scale.y,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @method getWorldTransform
|
|
82
|
+
* @description Returns a transform-shaped object ({position, rotation, scale})
|
|
83
|
+
* in world space. The returned object is reused between calls.
|
|
84
|
+
* @returns {{position:{x,y,z}, rotation:number, scale:{x,y}}}
|
|
85
|
+
*/
|
|
86
|
+
getWorldTransform() {
|
|
87
|
+
if (!this.parent) return this;
|
|
88
|
+
const w = this.getWorldParts();
|
|
89
|
+
const out = this._world;
|
|
90
|
+
out.position.x = w.px;
|
|
91
|
+
out.position.y = w.py;
|
|
92
|
+
out.position.z = w.pz;
|
|
93
|
+
out.rotation = w.rot;
|
|
94
|
+
out.scale.x = w.sx;
|
|
95
|
+
out.scale.y = w.sy;
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @method getWorldPosition
|
|
101
|
+
* @description Returns the world-space position as a plain { x, y, z }.
|
|
102
|
+
*/
|
|
103
|
+
getWorldPosition() {
|
|
104
|
+
const w = this.getWorldParts();
|
|
105
|
+
return { x: w.px, y: w.py, z: w.pz };
|
|
13
106
|
}
|
|
14
107
|
|
|
15
108
|
/**
|
|
@@ -30,7 +123,7 @@ class Transform {
|
|
|
30
123
|
|
|
31
124
|
/**
|
|
32
125
|
* @method getPosition
|
|
33
|
-
* @description Returns the position of the transform
|
|
126
|
+
* @description Returns the local position of the transform
|
|
34
127
|
* @returns {Vector3} - The position of the transform
|
|
35
128
|
*/
|
|
36
129
|
getPosition() {
|
|
@@ -39,7 +132,7 @@ class Transform {
|
|
|
39
132
|
|
|
40
133
|
/**
|
|
41
134
|
* @method getRotation
|
|
42
|
-
* @description Returns the rotation of the transform
|
|
135
|
+
* @description Returns the local rotation of the transform
|
|
43
136
|
* @returns {number} - The rotation of the transform
|
|
44
137
|
*/
|
|
45
138
|
getRotation() {
|
|
@@ -48,7 +141,7 @@ class Transform {
|
|
|
48
141
|
|
|
49
142
|
/**
|
|
50
143
|
* @method getScale
|
|
51
|
-
* @description Returns the scale of the transform
|
|
144
|
+
* @description Returns the local scale of the transform
|
|
52
145
|
* @returns {Vector2} - The scale of the transform
|
|
53
146
|
*/
|
|
54
147
|
getScale() {
|