littlejsengine 1.14.11 → 1.14.19
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/dist/littlejs.d.ts +303 -137
- package/dist/littlejs.esm.js +936 -463
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +934 -462
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +859 -417
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/breakout/gameObjects.js +2 -2
- package/examples/breakoutTutorial/README.md +32 -32
- package/examples/breakoutTutorial/game.js +1 -1
- package/examples/electron/game.js +4 -4
- package/examples/electron/index.html +2 -2
- package/examples/electron/package.json +1 -8
- package/examples/index.html +67 -56
- package/examples/module/game.js +4 -4
- package/examples/platformer/gameEffects.js +5 -5
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gameObjects.js +4 -4
- package/examples/puzzle/game.js +1 -1
- package/examples/shorts/animation.js +1 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/blending.js +8 -14
- package/examples/shorts/box2d.js +7 -3
- package/examples/shorts/box2dCar.js +2 -1
- package/examples/shorts/empty.js +30 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +10 -4
- package/examples/shorts/landerGame.js +11 -8
- package/examples/shorts/medals.js +4 -4
- package/examples/shorts/music.js +29 -56
- package/examples/shorts/musicPlayer.js +135 -0
- package/examples/shorts/nineSlice.js +34 -15
- package/examples/shorts/parallax.js +5 -4
- package/examples/shorts/particles.js +15 -15
- package/examples/shorts/piano.js +15 -21
- package/examples/shorts/pongGame.js +6 -4
- package/examples/shorts/raycasting.js +9 -4
- package/examples/shorts/sequencer.js +122 -0
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/shapes.js +7 -4
- package/examples/shorts/slidingPuzzle.js +4 -2
- package/examples/shorts/sound.js +18 -9
- package/examples/shorts/spaceGame.js +12 -8
- package/examples/shorts/spriteAtlas.js +7 -7
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/systemFont.js +2 -2
- package/examples/shorts/texture.js +2 -2
- package/examples/shorts/tileLayer.js +10 -10
- package/examples/shorts/tiltedView.js +24 -5
- package/examples/shorts/timers.js +10 -0
- package/examples/shorts/topDown.js +4 -1
- package/examples/shorts/uiSystem.js +8 -5
- package/examples/starter/game.js +4 -4
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +4 -4
- package/examples/typescript/game.ts +4 -4
- package/examples/uiSystem/game.js +4 -3
- package/package.json +4 -2
- package/plugins/box2d.js +17 -2
- package/plugins/newgrounds.js +7 -5
- package/plugins/postProcess.js +76 -53
- package/plugins/uiSystem.js +192 -53
- package/plugins/zzfxm.js +5 -1
- package/reference.md +1 -1
- package/src/engine.js +60 -23
- package/src/engineAudio.js +44 -17
- package/src/engineDebug.js +75 -45
- package/src/engineDraw.js +94 -59
- package/src/engineExport.js +2 -1
- package/src/engineMedals.js +10 -2
- package/src/engineObject.js +14 -10
- package/src/engineParticles.js +60 -47
- package/src/engineSettings.js +7 -7
- package/src/engineTileLayer.js +73 -56
- package/src/engineUtilities.js +67 -20
- package/src/engineWebGL.js +134 -63
package/src/engineSettings.js
CHANGED
|
@@ -306,7 +306,7 @@ let medalsPreventUnlock = false;
|
|
|
306
306
|
/** Set position of camera in world space
|
|
307
307
|
* @param {Vector2} pos
|
|
308
308
|
* @memberof Settings */
|
|
309
|
-
function setCameraPos(pos) { cameraPos = pos; }
|
|
309
|
+
function setCameraPos(pos) { cameraPos = pos.copy(); }
|
|
310
310
|
|
|
311
311
|
/** Set angle of camera in world space
|
|
312
312
|
* @param {number} angle
|
|
@@ -329,17 +329,17 @@ function setCanvasColorTiles(colorTiles) { canvasColorTiles = colorTiles; }
|
|
|
329
329
|
/** Set color to clear the canvas to before render
|
|
330
330
|
* @param {Color} color
|
|
331
331
|
* @memberof Settings */
|
|
332
|
-
function setCanvasClearColor(color) { canvasClearColor = color; }
|
|
332
|
+
function setCanvasClearColor(color) { canvasClearColor = color.copy(); }
|
|
333
333
|
|
|
334
334
|
/** Set max size of the canvas
|
|
335
335
|
* @param {Vector2} size
|
|
336
336
|
* @memberof Settings */
|
|
337
|
-
function setCanvasMaxSize(size) { canvasMaxSize = size; }
|
|
337
|
+
function setCanvasMaxSize(size) { canvasMaxSize = size.copy(); }
|
|
338
338
|
|
|
339
339
|
/** Set fixed size of the canvas
|
|
340
340
|
* @param {Vector2} size
|
|
341
341
|
* @memberof Settings */
|
|
342
|
-
function setCanvasFixedSize(size) { canvasFixedSize = size; }
|
|
342
|
+
function setCanvasFixedSize(size) { canvasFixedSize = size.copy(); }
|
|
343
343
|
|
|
344
344
|
/** Use nearest scaling algorithm for canvas for more pixelated look
|
|
345
345
|
* - If enabled sets css image-rendering:pixelated
|
|
@@ -404,7 +404,7 @@ function setGLCircleSides(sides) { glCircleSides = sides; }
|
|
|
404
404
|
/** Set default size of tiles in pixels
|
|
405
405
|
* @param {Vector2} size
|
|
406
406
|
* @memberof Settings */
|
|
407
|
-
function setTileSizeDefault(size) { tileSizeDefault = size; }
|
|
407
|
+
function setTileSizeDefault(size) { tileSizeDefault = size.copy(); }
|
|
408
408
|
|
|
409
409
|
/** Set to prevent tile bleeding from neighbors in pixels
|
|
410
410
|
* @param {number} scale
|
|
@@ -449,7 +449,7 @@ function setObjectMaxSpeed(speed) { objectMaxSpeed = speed; }
|
|
|
449
449
|
/** Set how much gravity to apply to objects
|
|
450
450
|
* @param {Vector2} newGravity
|
|
451
451
|
* @memberof Settings */
|
|
452
|
-
function setGravity(newGravity) { gravity = newGravity; }
|
|
452
|
+
function setGravity(newGravity) { gravity = newGravity.copy(); }
|
|
453
453
|
|
|
454
454
|
/** Set to scales emit rate of particles
|
|
455
455
|
* @param {number} scale
|
|
@@ -539,7 +539,7 @@ function setMedalDisplaySlideTime(time) { medalDisplaySlideTime = time; }
|
|
|
539
539
|
/** Set size of medal display
|
|
540
540
|
* @param {Vector2} size
|
|
541
541
|
* @memberof Settings */
|
|
542
|
-
function setMedalDisplaySize(size) { medalDisplaySize = size; }
|
|
542
|
+
function setMedalDisplaySize(size) { medalDisplaySize = size.copy(); }
|
|
543
543
|
|
|
544
544
|
/** Set to stop medals from being unlockable
|
|
545
545
|
* @param {boolean} preventUnlock
|
package/src/engineTileLayer.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* - Unlimited numbers of layers, allocates canvases as needed
|
|
5
5
|
* - Tile layers can be drawn to using their context with canvas2d
|
|
6
6
|
* - Tile layers can also have collision with EngineObjects
|
|
7
|
-
* @namespace
|
|
7
|
+
* @namespace TileLayers
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
|
|
15
15
|
/** Keep track of all tile layers with collision
|
|
16
16
|
* @type {Array<TileCollisionLayer>}
|
|
17
|
-
* @memberof
|
|
17
|
+
* @memberof TileLayers */
|
|
18
18
|
const tileCollisionLayers = [];
|
|
19
19
|
|
|
20
20
|
/** Get tile collision data for a given cell in the grid
|
|
21
21
|
* @param {Vector2} pos
|
|
22
22
|
* @return {number}
|
|
23
|
-
* @memberof
|
|
23
|
+
* @memberof TileLayers */
|
|
24
24
|
function tileCollisionGetData(pos)
|
|
25
25
|
{
|
|
26
26
|
// check all tile collision layers
|
|
@@ -36,7 +36,7 @@ function tileCollisionGetData(pos)
|
|
|
36
36
|
* @param {EngineObject} [object] - An object or undefined for generic test
|
|
37
37
|
* @param {boolean} [solidOnly] - Only check solid layers if true
|
|
38
38
|
* @return {TileCollisionLayer}
|
|
39
|
-
* @memberof
|
|
39
|
+
* @memberof TileLayers */
|
|
40
40
|
function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
|
|
41
41
|
{
|
|
42
42
|
for (const layer of tileCollisionLayers)
|
|
@@ -54,7 +54,7 @@ function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
|
|
|
54
54
|
* @param {EngineObject} [object] - An object or undefined for generic test
|
|
55
55
|
* @param {boolean} [solidOnly=true] - Only check solid layers if true
|
|
56
56
|
* @return {Vector2}
|
|
57
|
-
* @memberof
|
|
57
|
+
* @memberof TileLayers */
|
|
58
58
|
function tileCollisionRaycast(posStart, posEnd, object, solidOnly=true)
|
|
59
59
|
{
|
|
60
60
|
for (const layer of tileCollisionLayers)
|
|
@@ -77,8 +77,8 @@ function tileCollisionRaycast(posStart, posEnd, object, solidOnly=true)
|
|
|
77
77
|
* @param {number} [collisionLayer] - Layer to use for collision if any
|
|
78
78
|
* @param {boolean} [draw] - Should the layer be drawn automatically
|
|
79
79
|
* @return {Array<TileCollisionLayer>}
|
|
80
|
-
* @memberof
|
|
81
|
-
function
|
|
80
|
+
* @memberof TileLayers */
|
|
81
|
+
function tileLayersLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisionLayer, draw=true)
|
|
82
82
|
{
|
|
83
83
|
if (!tileMapData)
|
|
84
84
|
{
|
|
@@ -109,9 +109,9 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
109
109
|
tileLayers[layerIndex] = tileLayer;
|
|
110
110
|
|
|
111
111
|
// apply layer color
|
|
112
|
-
const layerColor = dataLayer.
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
const layerColor = dataLayer.tintcolor ?
|
|
113
|
+
new Color().setHex(dataLayer.tintcolor) :
|
|
114
|
+
dataLayer.color || WHITE;
|
|
115
115
|
ASSERT(isColor(layerColor), 'layer color is not a color');
|
|
116
116
|
|
|
117
117
|
for (let x=levelSize.x; x--;)
|
|
@@ -138,6 +138,7 @@ function tileCollisionLoad(tileMapData, tileInfo=tile(), renderOrder=0, collisio
|
|
|
138
138
|
///////////////////////////////////////////////////////////////////////////////
|
|
139
139
|
/**
|
|
140
140
|
* Tile layer data object stores info about how to draw a tile
|
|
141
|
+
* @memberof TileLayers
|
|
141
142
|
* @example
|
|
142
143
|
* // create tile layer data with tile index 0 and random orientation and color
|
|
143
144
|
* const tileIndex = 0;
|
|
@@ -175,6 +176,7 @@ class TileLayerData
|
|
|
175
176
|
* - Contains an offscreen canvas that can be rendered to
|
|
176
177
|
* - WebGL rendering is optional, call useWebGL to enable
|
|
177
178
|
* @extends EngineObject
|
|
179
|
+
* @memberof TileLayers
|
|
178
180
|
* @example
|
|
179
181
|
* const canvasLayer = new CanvasLayer(vec2(), vec2(200,100));
|
|
180
182
|
*/
|
|
@@ -189,15 +191,19 @@ class CanvasLayer extends EngineObject
|
|
|
189
191
|
*/
|
|
190
192
|
constructor(position, size, angle=0, renderOrder=0, canvasSize=vec2(512))
|
|
191
193
|
{
|
|
194
|
+
ASSERT(isVector2(canvasSize), 'canvasSize must be a Vector2');
|
|
192
195
|
super(position, size, undefined, angle, WHITE, renderOrder);
|
|
193
196
|
|
|
194
197
|
/** @property {HTMLCanvasElement} - The canvas used by this layer */
|
|
195
198
|
this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
196
199
|
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
|
|
197
|
-
this.context =
|
|
198
|
-
/** @property {
|
|
199
|
-
|
|
200
|
-
this.
|
|
200
|
+
this.context = this.canvas?.getContext('2d');
|
|
201
|
+
/** @property {TextureInfo} - Texture info to use for this object rendering */
|
|
202
|
+
const useWebGL = false; // do not use webgl by default
|
|
203
|
+
this.textureInfo = new TextureInfo(this.canvas, useWebGL);
|
|
204
|
+
|
|
205
|
+
// disable physics by default
|
|
206
|
+
this.mass = this.gravityScale = this.friction = this.restitution = 0;
|
|
201
207
|
}
|
|
202
208
|
|
|
203
209
|
/** Destroy this canvas layer */
|
|
@@ -206,9 +212,7 @@ class CanvasLayer extends EngineObject
|
|
|
206
212
|
if (this.destroyed)
|
|
207
213
|
return;
|
|
208
214
|
|
|
209
|
-
|
|
210
|
-
if (this.glTexture)
|
|
211
|
-
glDeleteTexture(this.glTexture);
|
|
215
|
+
this.textureInfo.destroyWebGLTexture();
|
|
212
216
|
super.destroy();
|
|
213
217
|
}
|
|
214
218
|
|
|
@@ -231,19 +235,27 @@ class CanvasLayer extends EngineObject
|
|
|
231
235
|
draw(pos, size, angle=0, color=WHITE, mirror=false, additiveColor, screenSpace=false, context)
|
|
232
236
|
{
|
|
233
237
|
// draw the canvas layer as a single tile that uses the whole texture
|
|
234
|
-
const useWebGL = glEnable && this.
|
|
235
|
-
const tileInfo = new TileInfo().setFullImage(this.
|
|
238
|
+
const useWebGL = glEnable && this.textureInfo.hasWebGL();
|
|
239
|
+
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
236
240
|
drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
|
|
237
241
|
}
|
|
238
242
|
|
|
243
|
+
/**
|
|
244
|
+
* @callback Canvas2DDrawCallback - Function that draws to a canvas 2D context
|
|
245
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
|
|
246
|
+
* @memberof TileLayers
|
|
247
|
+
*/
|
|
248
|
+
|
|
239
249
|
/** Draw onto the layer canvas in world space (bypass WebGL)
|
|
240
250
|
* @param {Vector2} pos
|
|
241
251
|
* @param {Vector2} size
|
|
242
252
|
* @param {number} angle
|
|
243
253
|
* @param {boolean} mirror
|
|
244
|
-
* @param {
|
|
254
|
+
* @param {Canvas2DDrawCallback} drawFunction */
|
|
245
255
|
drawCanvas2D(pos, size, angle, mirror, drawFunction)
|
|
246
256
|
{
|
|
257
|
+
if (!this.context) return;
|
|
258
|
+
|
|
247
259
|
const context = this.context;
|
|
248
260
|
context.save();
|
|
249
261
|
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
@@ -278,7 +290,7 @@ class CanvasLayer extends EngineObject
|
|
|
278
290
|
else
|
|
279
291
|
{
|
|
280
292
|
// untextured
|
|
281
|
-
context.fillStyle = color;
|
|
293
|
+
context.fillStyle = color.toString();
|
|
282
294
|
context.fillRect(-.5, -.5, 1, 1);
|
|
283
295
|
}
|
|
284
296
|
});
|
|
@@ -296,15 +308,10 @@ class CanvasLayer extends EngineObject
|
|
|
296
308
|
* @param {boolean} [enable] - enable WebGL rendering and update the texture */
|
|
297
309
|
useWebGL(enable=true)
|
|
298
310
|
{
|
|
299
|
-
if (
|
|
300
|
-
|
|
301
|
-
if (this.glTexture)
|
|
302
|
-
glSetTextureData(this.glTexture, this.canvas);
|
|
303
|
-
else
|
|
304
|
-
this.glTexture = glCreateTexture(this.canvas);
|
|
305
|
-
}
|
|
311
|
+
if (enable)
|
|
312
|
+
this.textureInfo.createWebGLTexture();
|
|
306
313
|
else
|
|
307
|
-
this.
|
|
314
|
+
this.textureInfo.destroyWebGLTexture();
|
|
308
315
|
}
|
|
309
316
|
}
|
|
310
317
|
|
|
@@ -315,7 +322,9 @@ class CanvasLayer extends EngineObject
|
|
|
315
322
|
* - To allow dynamic modifications, layers are rendered using canvas 2d
|
|
316
323
|
* - Some devices like mobile phones are limited to 4k texture resolution
|
|
317
324
|
* - For with 16x16 tiles this limits layers to 256x256 on mobile devices
|
|
325
|
+
* - Tile layers are centered on their corner, so normal levels are at (0,0)
|
|
318
326
|
* @extends CanvasLayer
|
|
327
|
+
* @memberof TileLayers
|
|
319
328
|
* @example
|
|
320
329
|
* const tileLayer = new TileLayer(vec2(), vec2(200,100));
|
|
321
330
|
*/
|
|
@@ -325,26 +334,15 @@ class TileLayer extends CanvasLayer
|
|
|
325
334
|
* @param {Vector2} position - World space position
|
|
326
335
|
* @param {Vector2} size - World space size
|
|
327
336
|
* @param {TileInfo} [tileInfo] - Default tile info for layer (used for size and texture)
|
|
328
|
-
* @param {Vector2} [scale=(1,1)] - How much to scale this layer when rendered
|
|
329
337
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
330
|
-
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
331
338
|
*/
|
|
332
|
-
constructor(position, size, tileInfo=tile(),
|
|
339
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
333
340
|
{
|
|
334
|
-
super(position, size, 0, renderOrder, size);
|
|
335
|
-
this.tileInfo = tileInfo;
|
|
336
|
-
|
|
337
341
|
const canvasSize = size.multiply(tileInfo.size);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
this.
|
|
342
|
-
/** @property {WebGLTexture} - Texture if using WebGL for this layer */
|
|
343
|
-
this.glTexture = useWebGL ? glCreateTexture(this.canvas) : undefined;
|
|
344
|
-
// set no friction by default, applied friction is max of both objects
|
|
345
|
-
this.friction = 0;
|
|
346
|
-
// set no restitution by default, applied restitution is max of both objects
|
|
347
|
-
this.restitution = 0;
|
|
342
|
+
super(position, size, 0, renderOrder, canvasSize);
|
|
343
|
+
|
|
344
|
+
// set tile info
|
|
345
|
+
this.tileInfo = tileInfo;
|
|
348
346
|
|
|
349
347
|
// init tile data
|
|
350
348
|
this.data = [];
|
|
@@ -370,6 +368,8 @@ class TileLayer extends CanvasLayer
|
|
|
370
368
|
* @param {boolean} [redraw] - Force the tile to redraw if true */
|
|
371
369
|
setData(layerPos, data, redraw=false)
|
|
372
370
|
{
|
|
371
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
372
|
+
ASSERT(data instanceof TileLayerData, 'data must be a TileLayerData');
|
|
373
373
|
if (layerPos.arrayCheck(this.size))
|
|
374
374
|
{
|
|
375
375
|
this.data[(layerPos.y|0)*this.size.x+layerPos.x|0] = data;
|
|
@@ -381,7 +381,10 @@ class TileLayer extends CanvasLayer
|
|
|
381
381
|
* @param {Vector2} layerPos - Local position in array
|
|
382
382
|
* @return {TileLayerData} */
|
|
383
383
|
getData(layerPos)
|
|
384
|
-
{
|
|
384
|
+
{
|
|
385
|
+
ASSERT(isVector2(layerPos), 'layerPos must be a Vector2');
|
|
386
|
+
return layerPos.arrayCheck(this.size) && this.data[(layerPos.y|0)*this.size.x+layerPos.x|0];
|
|
387
|
+
}
|
|
385
388
|
|
|
386
389
|
// Render the tile layer, called automatically by the engine
|
|
387
390
|
render()
|
|
@@ -389,10 +392,11 @@ class TileLayer extends CanvasLayer
|
|
|
389
392
|
ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
|
|
390
393
|
|
|
391
394
|
// draw the tile layer as a single tile
|
|
392
|
-
const tileInfo = new TileInfo().setFullImage(this.
|
|
393
|
-
const
|
|
394
|
-
const
|
|
395
|
-
|
|
395
|
+
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
396
|
+
const size = this.drawSize || this.size;
|
|
397
|
+
const pos = this.pos.add(size.scale(.5));
|
|
398
|
+
const useWebGL = glEnable && this.textureInfo.hasWebGL();
|
|
399
|
+
drawTile(pos, size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
|
|
396
400
|
}
|
|
397
401
|
|
|
398
402
|
/** Draw all the tile data to an offscreen canvas
|
|
@@ -404,8 +408,7 @@ class TileLayer extends CanvasLayer
|
|
|
404
408
|
for (let y = this.size.y; y--;)
|
|
405
409
|
this.drawTileData(vec2(x,y), false);
|
|
406
410
|
this.redrawEnd();
|
|
407
|
-
|
|
408
|
-
this.useWebGL(); // update WebGL texture
|
|
411
|
+
this.useWebGL();
|
|
409
412
|
}
|
|
410
413
|
|
|
411
414
|
/** Call to start the redraw process
|
|
@@ -413,6 +416,8 @@ class TileLayer extends CanvasLayer
|
|
|
413
416
|
* @param {boolean} [clear] - Should it clear the canvas before drawing */
|
|
414
417
|
redrawStart(clear=false)
|
|
415
418
|
{
|
|
419
|
+
if (!this.context) return;
|
|
420
|
+
|
|
416
421
|
// save current render settings
|
|
417
422
|
/** @type {[HTMLCanvasElement|OffscreenCanvas, CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D, Vector2, Vector2, number]} */
|
|
418
423
|
this.savedRenderSettings = [drawCanvas, drawContext, mainCanvasSize, cameraPos, cameraScale];
|
|
@@ -441,6 +446,8 @@ class TileLayer extends CanvasLayer
|
|
|
441
446
|
/** Call to end the redraw process */
|
|
442
447
|
redrawEnd()
|
|
443
448
|
{
|
|
449
|
+
if (!this.context) return;
|
|
450
|
+
|
|
444
451
|
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
445
452
|
glCopyToContext(drawContext);
|
|
446
453
|
//debugSaveCanvas(this.canvas);
|
|
@@ -457,6 +464,8 @@ class TileLayer extends CanvasLayer
|
|
|
457
464
|
*/
|
|
458
465
|
drawTileData(layerPos, clear=true)
|
|
459
466
|
{
|
|
467
|
+
if (!this.context) return;
|
|
468
|
+
|
|
460
469
|
// clear out where the tile was, for full opaque tiles this can be skipped
|
|
461
470
|
const s = this.tileInfo.size;
|
|
462
471
|
if (clear)
|
|
@@ -484,6 +493,7 @@ class TileLayer extends CanvasLayer
|
|
|
484
493
|
* - there can be multiple tile collision layers
|
|
485
494
|
* - tile collision layers should not overlap each other
|
|
486
495
|
* @extends TileLayer
|
|
496
|
+
* @memberof TileLayers
|
|
487
497
|
*/
|
|
488
498
|
class TileCollisionLayer extends TileLayer
|
|
489
499
|
{
|
|
@@ -492,12 +502,10 @@ class TileCollisionLayer extends TileLayer
|
|
|
492
502
|
* @param {Vector2} size - World space size
|
|
493
503
|
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
494
504
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
495
|
-
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
496
505
|
*/
|
|
497
|
-
constructor(position, size, tileInfo=tile(), renderOrder=0
|
|
506
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
498
507
|
{
|
|
499
|
-
|
|
500
|
-
super(position, size.floor(), tileInfo, scale, renderOrder, useWebGL);
|
|
508
|
+
super(position, size.floor(), tileInfo, renderOrder);
|
|
501
509
|
|
|
502
510
|
/** @property {Array<number>} - The tile collision grid */
|
|
503
511
|
this.collisionData = [];
|
|
@@ -527,6 +535,7 @@ class TileCollisionLayer extends TileLayer
|
|
|
527
535
|
* @param {Vector2} size - width and height of tile collision 2d grid */
|
|
528
536
|
initCollision(size)
|
|
529
537
|
{
|
|
538
|
+
ASSERT(isVector2(size), 'size must be a Vector2');
|
|
530
539
|
this.size = size.floor();
|
|
531
540
|
this.collisionData = [];
|
|
532
541
|
this.collisionData.length = size.area();
|
|
@@ -538,6 +547,7 @@ class TileCollisionLayer extends TileLayer
|
|
|
538
547
|
* @param {number} [data] */
|
|
539
548
|
setCollisionData(gridPos, data=1)
|
|
540
549
|
{
|
|
550
|
+
ASSERT(isVector2(gridPos), 'gridPos must be a Vector2');
|
|
541
551
|
const i = (gridPos.y|0)*this.size.x + gridPos.x|0;
|
|
542
552
|
gridPos.arrayCheck(this.size) && (this.collisionData[i] = data);
|
|
543
553
|
}
|
|
@@ -547,6 +557,7 @@ class TileCollisionLayer extends TileLayer
|
|
|
547
557
|
* @return {number} */
|
|
548
558
|
getCollisionData(gridPos)
|
|
549
559
|
{
|
|
560
|
+
ASSERT(isVector2(gridPos), 'gridPos must be a Vector2');
|
|
550
561
|
const i = (gridPos.y|0)*this.size.x + gridPos.x|0;
|
|
551
562
|
return gridPos.arrayCheck(this.size) ? this.collisionData[i] : 0;
|
|
552
563
|
}
|
|
@@ -558,6 +569,9 @@ class TileCollisionLayer extends TileLayer
|
|
|
558
569
|
* @return {boolean} */
|
|
559
570
|
collisionTest(pos, size=new Vector2, object)
|
|
560
571
|
{
|
|
572
|
+
ASSERT(isVector2(pos) && isVector2(size), 'pos and size must be Vector2s');
|
|
573
|
+
ASSERT(!object || object instanceof EngineObject, 'object must be an EngineObject');
|
|
574
|
+
|
|
561
575
|
// transform to local layer space
|
|
562
576
|
const posX = pos.x - this.pos.x;
|
|
563
577
|
const posY = pos.y - this.pos.y;
|
|
@@ -588,6 +602,9 @@ class TileCollisionLayer extends TileLayer
|
|
|
588
602
|
* @return {Vector2} */
|
|
589
603
|
collisionRaycast(posStart, posEnd, object)
|
|
590
604
|
{
|
|
605
|
+
ASSERT(isVector2(posStart) && isVector2(posEnd), 'positions must be Vector2s');
|
|
606
|
+
ASSERT(!object || object instanceof EngineObject, 'object must be an EngineObject');
|
|
607
|
+
|
|
591
608
|
// transform to local layer space
|
|
592
609
|
const posStartX = posStart.x - this.pos.x;
|
|
593
610
|
const posStartY = posStart.y - this.pos.y;
|
package/src/engineUtilities.js
CHANGED
|
@@ -231,6 +231,8 @@ function formatTime(t)
|
|
|
231
231
|
async function fetchJSON(url)
|
|
232
232
|
{
|
|
233
233
|
const response = await fetch(url);
|
|
234
|
+
if (!response.ok)
|
|
235
|
+
throw new Error(`Failed to fetch JSON from ${url}: ${response.status} ${response.statusText}`);
|
|
234
236
|
return response.json();
|
|
235
237
|
}
|
|
236
238
|
|
|
@@ -241,6 +243,13 @@ async function fetchJSON(url)
|
|
|
241
243
|
* @memberof Utilities */
|
|
242
244
|
function isNumber(n) { return typeof n === 'number' && !isNaN(n); }
|
|
243
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Check if object is a valid string or can be converted to one
|
|
248
|
+
* @param {any} s
|
|
249
|
+
* @return {boolean}
|
|
250
|
+
* @memberof Utilities */
|
|
251
|
+
function isString(s) { return s !== undefined && s !== null && typeof s.toString() === 'string'; }
|
|
252
|
+
|
|
244
253
|
///////////////////////////////////////////////////////////////////////////////
|
|
245
254
|
|
|
246
255
|
/** Random global functions
|
|
@@ -303,6 +312,7 @@ function randColor(colorA=new Color, colorB=new Color(0,0,0,1), linear=false)
|
|
|
303
312
|
/**
|
|
304
313
|
* Seeded random number generator
|
|
305
314
|
* - Can be used to create a deterministic random number sequence
|
|
315
|
+
* @memberof Engine
|
|
306
316
|
* @example
|
|
307
317
|
* let r = new RandomGenerator(123); // random number generator with seed 123
|
|
308
318
|
* let a = r.float(); // random value between 0 and 1
|
|
@@ -399,6 +409,7 @@ function ASSERT_VECTOR2_NORMAL(v)
|
|
|
399
409
|
/**
|
|
400
410
|
* 2D Vector object with vector math library
|
|
401
411
|
* - Functions do not change this so they can be chained together
|
|
412
|
+
* @memberof Engine
|
|
402
413
|
* @example
|
|
403
414
|
* let a = new Vector2(2, 3); // vector with coordinates (2, 3)
|
|
404
415
|
* let b = new Vector2; // vector with coordinates (0, 0)
|
|
@@ -539,9 +550,10 @@ class Vector2
|
|
|
539
550
|
return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
|
|
540
551
|
}
|
|
541
552
|
|
|
542
|
-
/**
|
|
553
|
+
/** Sets this this vector to point in the specified integer direction (0-3), corresponding to multiples of 90 degree rotation
|
|
543
554
|
* @param {number} [direction]
|
|
544
|
-
* @param {number} [length]
|
|
555
|
+
* @param {number} [length]
|
|
556
|
+
* @return {Vector2} */
|
|
545
557
|
setDirection(direction, length=1)
|
|
546
558
|
{
|
|
547
559
|
ASSERT_NUMBER_VALID(direction);
|
|
@@ -549,8 +561,10 @@ class Vector2
|
|
|
549
561
|
direction = mod(direction, 4);
|
|
550
562
|
ASSERT(direction===0 || direction===1 || direction===2 || direction===3,
|
|
551
563
|
'Vector2.setDirection() direction must be an integer between 0 and 3.');
|
|
552
|
-
|
|
553
|
-
|
|
564
|
+
|
|
565
|
+
this.x = direction%2 ? direction-1 ? -length : length : 0;
|
|
566
|
+
this.y = direction%2 ? 0 : direction ? -length : length;
|
|
567
|
+
return this;
|
|
554
568
|
}
|
|
555
569
|
|
|
556
570
|
/** Returns the integer direction of this vector, corresponding to multiples of 90 degree rotation (0-3)
|
|
@@ -646,6 +660,7 @@ function ASSERT_COLOR_VALID(c) { ASSERT(isColor(c), 'Color is invalid.', c); }
|
|
|
646
660
|
|
|
647
661
|
/**
|
|
648
662
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
663
|
+
* @memberof Engine
|
|
649
664
|
* @example
|
|
650
665
|
* let a = new Color; // white
|
|
651
666
|
* let b = new Color(1, 0, 0); // red
|
|
@@ -823,7 +838,8 @@ class Color
|
|
|
823
838
|
* @return {Color} */
|
|
824
839
|
setHex(hex)
|
|
825
840
|
{
|
|
826
|
-
ASSERT(
|
|
841
|
+
ASSERT(isString(hex), 'Color hex code must be a string');
|
|
842
|
+
ASSERT(hex[0] === '#', 'Color hex code must start with #');
|
|
827
843
|
ASSERT([4,5,7,9].includes(hex.length), 'Invalid hex');
|
|
828
844
|
|
|
829
845
|
if (hex.length < 6)
|
|
@@ -865,77 +881,78 @@ class Color
|
|
|
865
881
|
}
|
|
866
882
|
|
|
867
883
|
///////////////////////////////////////////////////////////////////////////////
|
|
868
|
-
//
|
|
884
|
+
// Default Colors
|
|
869
885
|
|
|
870
886
|
/** Color - White #ffffff
|
|
871
887
|
* @type {Color}
|
|
872
888
|
* @memberof Utilities */
|
|
873
|
-
const WHITE = rgb();
|
|
889
|
+
const WHITE = protectEngineConstant(rgb());
|
|
874
890
|
|
|
875
|
-
/** Color - Clear White #
|
|
891
|
+
/** Color - Clear White #757474ff with 0 alpha
|
|
876
892
|
* @type {Color}
|
|
877
893
|
* @memberof Utilities */
|
|
878
|
-
const CLEAR_WHITE = rgb(1,1,1,0);
|
|
894
|
+
const CLEAR_WHITE = protectEngineConstant(rgb(1,1,1,0));
|
|
879
895
|
|
|
880
896
|
/** Color - Black #000000
|
|
881
897
|
* @type {Color}
|
|
882
898
|
* @memberof Utilities */
|
|
883
|
-
const BLACK = rgb(0,0,0);
|
|
899
|
+
const BLACK = protectEngineConstant(rgb(0,0,0));
|
|
884
900
|
|
|
885
901
|
/** Color - Clear Black #000000 with 0 alpha
|
|
886
902
|
* @type {Color}
|
|
887
903
|
* @memberof Utilities */
|
|
888
|
-
const CLEAR_BLACK = rgb(0,0,0,0);
|
|
904
|
+
const CLEAR_BLACK = protectEngineConstant(rgb(0,0,0,0));
|
|
889
905
|
|
|
890
906
|
/** Color - Gray #808080
|
|
891
907
|
* @type {Color}
|
|
892
908
|
* @memberof Utilities */
|
|
893
|
-
const GRAY = rgb(.5,.5,.5);
|
|
909
|
+
const GRAY = protectEngineConstant(rgb(.5,.5,.5));
|
|
894
910
|
|
|
895
911
|
/** Color - Red #ff0000
|
|
896
912
|
* @type {Color}
|
|
897
913
|
* @memberof Utilities */
|
|
898
|
-
const RED = rgb(1,0,0);
|
|
914
|
+
const RED = protectEngineConstant(rgb(1,0,0));
|
|
899
915
|
|
|
900
916
|
/** Color - Orange #ff8000
|
|
901
917
|
* @type {Color}
|
|
902
918
|
* @memberof Utilities */
|
|
903
|
-
const ORANGE = rgb(1,.5,0);
|
|
919
|
+
const ORANGE = protectEngineConstant(rgb(1,.5,0));
|
|
904
920
|
|
|
905
921
|
/** Color - Yellow #ffff00
|
|
906
922
|
* @type {Color}
|
|
907
923
|
* @memberof Utilities */
|
|
908
|
-
const YELLOW = rgb(1,1,0);
|
|
924
|
+
const YELLOW = protectEngineConstant(rgb(1,1,0));
|
|
909
925
|
|
|
910
926
|
/** Color - Green #00ff00
|
|
911
927
|
* @type {Color}
|
|
912
928
|
* @memberof Utilities */
|
|
913
|
-
const GREEN = rgb(0,1,0);
|
|
929
|
+
const GREEN = protectEngineConstant(rgb(0,1,0));
|
|
914
930
|
|
|
915
931
|
/** Color - Cyan #00ffff
|
|
916
932
|
* @type {Color}
|
|
917
933
|
* @memberof Utilities */
|
|
918
|
-
const CYAN = rgb(0,1,1);
|
|
934
|
+
const CYAN = protectEngineConstant(rgb(0,1,1));
|
|
919
935
|
|
|
920
936
|
/** Color - Blue #0000ff
|
|
921
937
|
* @type {Color}
|
|
922
938
|
* @memberof Utilities */
|
|
923
|
-
const BLUE = rgb(0,0,1);
|
|
939
|
+
const BLUE = protectEngineConstant(rgb(0,0,1));
|
|
924
940
|
|
|
925
941
|
/** Color - Purple #8000ff
|
|
926
942
|
* @type {Color}
|
|
927
943
|
* @memberof Utilities */
|
|
928
|
-
const PURPLE = rgb(.5,0,1);
|
|
944
|
+
const PURPLE = protectEngineConstant(rgb(.5,0,1));
|
|
929
945
|
|
|
930
946
|
/** Color - Magenta #ff00ff
|
|
931
947
|
* @type {Color}
|
|
932
948
|
* @memberof Utilities */
|
|
933
|
-
const MAGENTA = rgb(1,0,1);
|
|
949
|
+
const MAGENTA = protectEngineConstant(rgb(1,0,1));
|
|
934
950
|
|
|
935
951
|
///////////////////////////////////////////////////////////////////////////////
|
|
936
952
|
|
|
937
953
|
/**
|
|
938
954
|
* Timer object tracks how long has passed since it was set
|
|
955
|
+
* @memberof Engine
|
|
939
956
|
* @example
|
|
940
957
|
* let a = new Timer; // creates a timer that is not set
|
|
941
958
|
* a.set(3); // sets the timer to 3 seconds
|
|
@@ -997,4 +1014,34 @@ class Timer
|
|
|
997
1014
|
/** Get how long since elapsed, returns 0 if not set (returns negative if currently active)
|
|
998
1015
|
* @return {number} */
|
|
999
1016
|
valueOf() { return this.get(); }
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
1020
|
+
// Helper functions used by the engine
|
|
1021
|
+
|
|
1022
|
+
// make color constants immutable with debug assertions
|
|
1023
|
+
function protectEngineConstant(obj)
|
|
1024
|
+
{
|
|
1025
|
+
if (debug)
|
|
1026
|
+
{
|
|
1027
|
+
// get properties and store original values
|
|
1028
|
+
const props = Object.keys(obj), values = {};
|
|
1029
|
+
props.forEach(prop => values[prop] = obj[prop]);
|
|
1030
|
+
|
|
1031
|
+
// replace with getters/setters that assert
|
|
1032
|
+
props.forEach(prop =>
|
|
1033
|
+
{
|
|
1034
|
+
Object.defineProperty(obj, prop, {
|
|
1035
|
+
get: () => values[prop],
|
|
1036
|
+
set: (value) =>
|
|
1037
|
+
{
|
|
1038
|
+
ASSERT(false, `Cannot modify engine constant. Attempted to set constant (${obj}) property '${prop}' to '${value}'.`);
|
|
1039
|
+
},
|
|
1040
|
+
enumerable: true
|
|
1041
|
+
});
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
// freeze the object to prevent adding new properties
|
|
1046
|
+
return Object.freeze(obj);
|
|
1000
1047
|
}
|