littlejsengine 1.14.16 → 1.14.23
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 +173 -50
- package/dist/littlejs.esm.js +892 -419
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +879 -419
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +854 -420
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/electron/game.js +1 -41
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +69 -55
- package/examples/module/game.js +6 -8
- package/examples/particles/index.html +6 -9
- package/examples/platformer/gameCharacter.js +1 -1
- package/examples/platformer/gameEffects.js +8 -3
- package/examples/platformer/gameObjects.js +3 -3
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/cameraDrag.js +22 -0
- package/examples/shorts/debugDraw.js +38 -0
- package/examples/shorts/fps.js +90 -0
- package/examples/shorts/helloWorld.js +1 -1
- package/examples/shorts/hillGlideGame.js +1 -1
- package/examples/shorts/landerGame.js +1 -1
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/postProcess.js +1 -1
- package/examples/shorts/sequencer.js +5 -5
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/spaceGame.js +1 -1
- package/examples/shorts/spriteAtlas.js +6 -6
- package/examples/shorts/starfield.js +1 -1
- package/examples/shorts/tileLayer.js +1 -1
- package/examples/shorts/tileRaycast.js +39 -0
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +14 -6
- package/examples/shorts/topDown.js +1 -1
- package/examples/starter/game.js +6 -8
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +5 -4
- package/examples/typescript/game.ts +5 -7
- package/examples/uiSystem/game.js +3 -2
- package/package.json +1 -1
- package/plugins/postProcess.js +71 -51
- package/plugins/uiSystem.js +76 -23
- package/src/engine.js +30 -16
- package/src/engineAudio.js +33 -23
- package/src/engineDebug.js +27 -0
- package/src/engineDraw.js +103 -49
- package/src/engineExport.js +13 -0
- package/src/engineInput.js +14 -16
- package/src/engineObject.js +31 -6
- package/src/engineParticles.js +37 -16
- package/src/engineRelease.js +2 -1
- package/src/engineSettings.js +20 -1
- package/src/engineTileLayer.js +89 -94
- package/src/engineUtilities.js +206 -58
- package/src/engineWebGL.js +145 -69
- package/examples/shorts/raycasting.js +0 -79
package/src/engineTileLayer.js
CHANGED
|
@@ -47,23 +47,22 @@ function tileCollisionTest(pos, size=vec2(), object, solidOnly=true)
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
/** Return the
|
|
51
|
-
* This does not return the exact intersection, but the center of the tile hit.
|
|
50
|
+
/** Return the exact position of the boudnary of first tile hit, undefined if nothing was hit.
|
|
52
51
|
* @param {Vector2} posStart
|
|
53
52
|
* @param {Vector2} posEnd
|
|
54
53
|
* @param {EngineObject} [object] - An object or undefined for generic test
|
|
54
|
+
* @param {Vector2} [normal] - Optional normal of the surface hit
|
|
55
55
|
* @param {boolean} [solidOnly=true] - Only check solid layers if true
|
|
56
|
-
* @return {Vector2}
|
|
56
|
+
* @return {Vector2|undefined} - position of the center of the tile hit or undefined if no hit
|
|
57
57
|
* @memberof TileLayers */
|
|
58
|
-
function tileCollisionRaycast(posStart, posEnd, object, solidOnly=true)
|
|
58
|
+
function tileCollisionRaycast(posStart, posEnd, object, normal, solidOnly=true)
|
|
59
59
|
{
|
|
60
60
|
for (const layer of tileCollisionLayers)
|
|
61
61
|
{
|
|
62
62
|
if (!solidOnly || layer.isSolid)
|
|
63
63
|
{
|
|
64
|
-
const hitPos = layer.collisionRaycast(posStart, posEnd, object)
|
|
65
|
-
if (hitPos)
|
|
66
|
-
return hitPos;
|
|
64
|
+
const hitPos = layer.collisionRaycast(posStart, posEnd, object, normal)
|
|
65
|
+
if (hitPos) return hitPos;
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
68
|
}
|
|
@@ -197,10 +196,15 @@ class CanvasLayer extends EngineObject
|
|
|
197
196
|
/** @property {HTMLCanvasElement} - The canvas used by this layer */
|
|
198
197
|
this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
199
198
|
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
|
|
200
|
-
this.context =
|
|
201
|
-
/** @property {
|
|
202
|
-
|
|
203
|
-
this.
|
|
199
|
+
this.context = this.canvas?.getContext('2d');
|
|
200
|
+
/** @property {TextureInfo} - Texture info to use for this object rendering */
|
|
201
|
+
const useWebGL = false; // do not use webgl by default
|
|
202
|
+
this.textureInfo = new TextureInfo(this.canvas, useWebGL);
|
|
203
|
+
/** @property {boolean} - True if WebGL texture needs to be refreshed */
|
|
204
|
+
this.refreshWebGL = false;
|
|
205
|
+
|
|
206
|
+
// disable physics by default
|
|
207
|
+
this.mass = this.gravityScale = this.friction = this.restitution = 0;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
/** Destroy this canvas layer */
|
|
@@ -209,9 +213,7 @@ class CanvasLayer extends EngineObject
|
|
|
209
213
|
if (this.destroyed)
|
|
210
214
|
return;
|
|
211
215
|
|
|
212
|
-
|
|
213
|
-
if (this.glTexture)
|
|
214
|
-
glDeleteTexture(this.glTexture);
|
|
216
|
+
this.textureInfo.destroyWebGLTexture();
|
|
215
217
|
super.destroy();
|
|
216
218
|
}
|
|
217
219
|
|
|
@@ -233,9 +235,16 @@ class CanvasLayer extends EngineObject
|
|
|
233
235
|
* @memberof Draw */
|
|
234
236
|
draw(pos, size, angle=0, color=WHITE, mirror=false, additiveColor, screenSpace=false, context)
|
|
235
237
|
{
|
|
238
|
+
const useWebGL = glEnable && this.textureInfo.hasWebGL();
|
|
239
|
+
if (useWebGL && this.refreshWebGL)
|
|
240
|
+
{
|
|
241
|
+
// update the WebGL texture
|
|
242
|
+
this.textureInfo.createWebGLTexture();
|
|
243
|
+
this.refreshWebGL = false;
|
|
244
|
+
}
|
|
245
|
+
|
|
236
246
|
// draw the canvas layer as a single tile that uses the whole texture
|
|
237
|
-
const
|
|
238
|
-
const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
|
|
247
|
+
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
239
248
|
drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
|
|
240
249
|
}
|
|
241
250
|
|
|
@@ -253,6 +262,8 @@ class CanvasLayer extends EngineObject
|
|
|
253
262
|
* @param {Canvas2DDrawCallback} drawFunction */
|
|
254
263
|
drawCanvas2D(pos, size, angle, mirror, drawFunction)
|
|
255
264
|
{
|
|
265
|
+
if (!this.context) return;
|
|
266
|
+
|
|
256
267
|
const context = this.context;
|
|
257
268
|
context.save();
|
|
258
269
|
pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
|
|
@@ -302,18 +313,22 @@ class CanvasLayer extends EngineObject
|
|
|
302
313
|
{ this.drawTile(pos, size, undefined, color, angle); }
|
|
303
314
|
|
|
304
315
|
/** Create or update the WebGL texture for this layer
|
|
305
|
-
* @param {boolean} [enable] - enable WebGL rendering and update the texture
|
|
306
|
-
|
|
316
|
+
* @param {boolean} [enable] - enable WebGL rendering and update the texture
|
|
317
|
+
* @param {boolean} [immediate] - shoulkd the texture be updated immediately
|
|
318
|
+
*/
|
|
319
|
+
useWebGL(enable=true, immediate=false)
|
|
307
320
|
{
|
|
308
|
-
if (
|
|
321
|
+
if (!immediate && enable && this.textureInfo.hasWebGL())
|
|
309
322
|
{
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
this.glTexture = glCreateTexture(this.canvas);
|
|
323
|
+
// refresh the texture when needed
|
|
324
|
+
this.refreshWebGL = true;
|
|
325
|
+
return;
|
|
314
326
|
}
|
|
327
|
+
|
|
328
|
+
if (enable)
|
|
329
|
+
this.textureInfo.createWebGLTexture();
|
|
315
330
|
else
|
|
316
|
-
this.
|
|
331
|
+
this.textureInfo.destroyWebGLTexture();
|
|
317
332
|
}
|
|
318
333
|
}
|
|
319
334
|
|
|
@@ -337,24 +352,14 @@ class TileLayer extends CanvasLayer
|
|
|
337
352
|
* @param {Vector2} size - World space size
|
|
338
353
|
* @param {TileInfo} [tileInfo] - Default tile info for layer (used for size and texture)
|
|
339
354
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
340
|
-
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
341
355
|
*/
|
|
342
|
-
constructor(position, size, tileInfo=tile(), renderOrder=0
|
|
356
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
343
357
|
{
|
|
344
|
-
|
|
345
|
-
|
|
358
|
+
const canvasSize = tileInfo ? size.multiply(tileInfo.size) : size;
|
|
359
|
+
super(position, size, 0, renderOrder, canvasSize);
|
|
360
|
+
|
|
361
|
+
// set tile info
|
|
346
362
|
this.tileInfo = tileInfo;
|
|
347
|
-
const canvasSize = size.multiply(tileInfo.size);
|
|
348
|
-
/** @property {HTMLCanvasElement} - The canvas used by this tile layer */
|
|
349
|
-
this.canvas = new OffscreenCanvas(canvasSize.x, canvasSize.y);
|
|
350
|
-
/** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this tile layer */
|
|
351
|
-
this.context = this.canvas.getContext('2d');
|
|
352
|
-
/** @property {WebGLTexture} - Texture if using WebGL for this layer */
|
|
353
|
-
this.glTexture = useWebGL ? glCreateTexture(this.canvas) : undefined;
|
|
354
|
-
// set no friction by default, applied friction is max of both objects
|
|
355
|
-
this.friction = 0;
|
|
356
|
-
// set no restitution by default, applied restitution is max of both objects
|
|
357
|
-
this.restitution = 0;
|
|
358
363
|
|
|
359
364
|
// init tile data
|
|
360
365
|
this.data = [];
|
|
@@ -403,11 +408,18 @@ class TileLayer extends CanvasLayer
|
|
|
403
408
|
{
|
|
404
409
|
ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
|
|
405
410
|
|
|
411
|
+
if (this.refreshWebGL)
|
|
412
|
+
{
|
|
413
|
+
// update the WebGL texture
|
|
414
|
+
this.textureInfo.createWebGLTexture();
|
|
415
|
+
this.refreshWebGL = false;
|
|
416
|
+
}
|
|
417
|
+
|
|
406
418
|
// draw the tile layer as a single tile
|
|
407
|
-
const tileInfo = new TileInfo().setFullImage(this.
|
|
419
|
+
const tileInfo = new TileInfo().setFullImage(this.textureInfo);
|
|
408
420
|
const size = this.drawSize || this.size;
|
|
409
421
|
const pos = this.pos.add(size.scale(.5));
|
|
410
|
-
const useWebGL = glEnable && this.
|
|
422
|
+
const useWebGL = glEnable && this.textureInfo.hasWebGL();
|
|
411
423
|
drawTile(pos, size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
|
|
412
424
|
}
|
|
413
425
|
|
|
@@ -420,8 +432,7 @@ class TileLayer extends CanvasLayer
|
|
|
420
432
|
for (let y = this.size.y; y--;)
|
|
421
433
|
this.drawTileData(vec2(x,y), false);
|
|
422
434
|
this.redrawEnd();
|
|
423
|
-
|
|
424
|
-
this.useWebGL(); // update WebGL texture
|
|
435
|
+
this.useWebGL();
|
|
425
436
|
}
|
|
426
437
|
|
|
427
438
|
/** Call to start the redraw process
|
|
@@ -429,6 +440,8 @@ class TileLayer extends CanvasLayer
|
|
|
429
440
|
* @param {boolean} [clear] - Should it clear the canvas before drawing */
|
|
430
441
|
redrawStart(clear=false)
|
|
431
442
|
{
|
|
443
|
+
if (!this.context) return;
|
|
444
|
+
|
|
432
445
|
// save current render settings
|
|
433
446
|
/** @type {[HTMLCanvasElement|OffscreenCanvas, CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D, Vector2, Vector2, number]} */
|
|
434
447
|
this.savedRenderSettings = [drawCanvas, drawContext, mainCanvasSize, cameraPos, cameraScale];
|
|
@@ -438,8 +451,9 @@ class TileLayer extends CanvasLayer
|
|
|
438
451
|
drawCanvas = this.canvas;
|
|
439
452
|
drawContext = this.context;
|
|
440
453
|
cameraPos = this.size.scale(.5);
|
|
441
|
-
|
|
442
|
-
|
|
454
|
+
const tileSize = this.tileInfo ? this.tileInfo.size : vec2(1);
|
|
455
|
+
cameraScale = tileSize.x;
|
|
456
|
+
mainCanvasSize = this.size.multiply(tileSize);
|
|
443
457
|
if (clear)
|
|
444
458
|
{
|
|
445
459
|
// clear and set size
|
|
@@ -457,6 +471,8 @@ class TileLayer extends CanvasLayer
|
|
|
457
471
|
/** Call to end the redraw process */
|
|
458
472
|
redrawEnd()
|
|
459
473
|
{
|
|
474
|
+
if (!this.context) return;
|
|
475
|
+
|
|
460
476
|
ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
|
|
461
477
|
glCopyToContext(drawContext);
|
|
462
478
|
//debugSaveCanvas(this.canvas);
|
|
@@ -473,6 +489,8 @@ class TileLayer extends CanvasLayer
|
|
|
473
489
|
*/
|
|
474
490
|
drawTileData(layerPos, clear=true)
|
|
475
491
|
{
|
|
492
|
+
if (!this.context) return;
|
|
493
|
+
|
|
476
494
|
// clear out where the tile was, for full opaque tiles this can be skipped
|
|
477
495
|
const s = this.tileInfo.size;
|
|
478
496
|
if (clear)
|
|
@@ -509,11 +527,10 @@ class TileCollisionLayer extends TileLayer
|
|
|
509
527
|
* @param {Vector2} size - World space size
|
|
510
528
|
* @param {TileInfo} [tileInfo] - Tile info for layer
|
|
511
529
|
* @param {number} [renderOrder] - Objects are sorted by renderOrder
|
|
512
|
-
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
|
|
513
530
|
*/
|
|
514
|
-
constructor(position, size, tileInfo=tile(), renderOrder=0
|
|
531
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
515
532
|
{
|
|
516
|
-
super(position, size.floor(), tileInfo, renderOrder
|
|
533
|
+
super(position, size.floor(), tileInfo, renderOrder);
|
|
517
534
|
|
|
518
535
|
/** @property {Array<number>} - The tile collision grid */
|
|
519
536
|
this.collisionData = [];
|
|
@@ -596,65 +613,43 @@ class TileCollisionLayer extends TileLayer
|
|
|
596
613
|
// check if the object should collide with this tile
|
|
597
614
|
const tileData = this.collisionData[y*this.size.x+x];
|
|
598
615
|
if (tileData)
|
|
599
|
-
if (!object || object.collideWithTile(tileData,
|
|
616
|
+
if (!object || object.collideWithTile(tileData,
|
|
617
|
+
hitPos.set(x + this.pos.x, y + this.pos.y)))
|
|
600
618
|
return true;
|
|
601
619
|
}
|
|
602
620
|
return false;
|
|
603
621
|
}
|
|
604
622
|
|
|
605
|
-
/** Return the
|
|
606
|
-
* This does not return the exact intersection, but the center of the tile hit.
|
|
623
|
+
/** Return the exact position of the boudnary of first tile hit, undefined if nothing was hit.
|
|
607
624
|
* @param {Vector2} posStart
|
|
608
625
|
* @param {Vector2} posEnd
|
|
609
|
-
* @param {EngineObject} [object]
|
|
610
|
-
* @
|
|
611
|
-
|
|
626
|
+
* @param {EngineObject} [object] - An object or undefined for generic test
|
|
627
|
+
* @param {Vector2} [normal] - Optional normal of the surface hit
|
|
628
|
+
* @return {Vector2|undefined} */
|
|
629
|
+
collisionRaycast(posStart, posEnd, object, normal)
|
|
612
630
|
{
|
|
613
631
|
ASSERT(isVector2(posStart) && isVector2(posEnd), 'positions must be Vector2s');
|
|
614
632
|
ASSERT(!object || object instanceof EngineObject, 'object must be an EngineObject');
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
const posStartY = posStart.y - this.pos.y;
|
|
619
|
-
const posEndX = posEnd.x - this.pos.x;
|
|
620
|
-
const posEndY = posEnd.y - this.pos.y;
|
|
621
|
-
|
|
622
|
-
// test if a ray collides with tiles from start to end
|
|
623
|
-
const deltaX = posEndX - posStartX;
|
|
624
|
-
const deltaY = posEndY - posStartY;
|
|
625
|
-
const totalLength = (deltaX**2 + deltaY**2)**.5;
|
|
626
|
-
const unitX = abs(totalLength/deltaX);
|
|
627
|
-
const unitY = abs(totalLength/deltaY);
|
|
628
|
-
|
|
629
|
-
// setup iteration variables
|
|
630
|
-
const pos = posStart.floor(), signDeltaX = sign(deltaX), signDeltaY = sign(deltaY);
|
|
631
|
-
let xi = unitX * (deltaX < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1) || 0;
|
|
632
|
-
let yi = unitY * (deltaY < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1) || 0;
|
|
633
|
-
|
|
634
|
-
// use line drawing algorithm to test for collisions
|
|
635
|
-
while (true)
|
|
633
|
+
|
|
634
|
+
const localPos = new Vector2;
|
|
635
|
+
const collisionTest = (pos)=>
|
|
636
636
|
{
|
|
637
637
|
// check for tile collision
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
pos.x += .5; pos.y += .5;
|
|
642
|
-
debugRaycast && debugLine(posStart, posEnd, '#f00', .02);
|
|
643
|
-
debugRaycast && debugPoint(pos, '#ff0');
|
|
644
|
-
return pos;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// check if past the end
|
|
648
|
-
if (xi >= totalLength && yi >= totalLength)
|
|
649
|
-
break;
|
|
650
|
-
|
|
651
|
-
// get coordinates of next tile to check
|
|
652
|
-
if (xi > yi)
|
|
653
|
-
pos.y += signDeltaY, yi += unitY;
|
|
654
|
-
else
|
|
655
|
-
pos.x += signDeltaX, xi += unitX;
|
|
638
|
+
localPos.set(pos.x - this.pos.x, pos.y - this.pos.y);
|
|
639
|
+
const tileData = this.getCollisionData(localPos);
|
|
640
|
+
return tileData && (!object || object.collideWithTile(tileData, pos));
|
|
656
641
|
}
|
|
657
|
-
|
|
658
642
|
debugRaycast && debugLine(posStart, posEnd, '#00f', .02);
|
|
643
|
+
const hitPos = lineTest(posStart, posEnd, collisionTest, normal);
|
|
644
|
+
if (hitPos)
|
|
645
|
+
{
|
|
646
|
+
const tilePos = hitPos.floor().add(vec2(.5));
|
|
647
|
+
debugRaycast && debugRect(tilePos, vec2(1), '#f008');
|
|
648
|
+
debugRaycast && debugLine(posStart, hitPos, '#f00', .02);
|
|
649
|
+
debugRaycast && debugPoint(hitPos, '#0f0');
|
|
650
|
+
debugRaycast && normal &&
|
|
651
|
+
debugLine(hitPos, hitPos.add(normal), '#ff0', .02);
|
|
652
|
+
return hitPos;
|
|
653
|
+
}
|
|
659
654
|
}
|
|
660
655
|
}
|