littlejsengine 1.9.11 → 1.10.2
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 +4 -0
- package/dist/littlejs.d.ts +80 -9
- package/dist/littlejs.esm.js +193 -71
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +175 -69
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +174 -68
- package/examples/box2d/game.js +1 -1
- package/examples/box2d/index.html +7 -6
- package/examples/breakout/game.js +1 -1
- package/examples/breakout/index.html +5 -4
- package/examples/breakoutTutorial/index.html +4 -3
- package/examples/electron/game.js +1 -1
- package/examples/electron/index.html +4 -3
- package/examples/empty/game.js +1 -1
- package/examples/empty/index.html +2 -1
- package/examples/htmlMenu/game.js +67 -0
- package/examples/htmlMenu/index.html +56 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +33 -0
- package/examples/js13k/game.js +1 -1
- package/examples/js13k/index.html +17 -14
- package/examples/module/game.js +1 -1
- package/examples/module/index.html +3 -2
- package/examples/particles/index.html +4 -3
- package/examples/platformer/game.js +1 -1
- package/examples/platformer/gameLevel.js +2 -2
- package/examples/platformer/gameObjects.js +0 -1
- package/examples/platformer/index.html +10 -9
- package/examples/puzzle/game.js +1 -1
- package/examples/puzzle/index.html +4 -3
- package/examples/starter/game.js +4 -4
- package/examples/starter/index.html +15 -14
- package/examples/stress/index.html +3 -2
- package/examples/typescript/game.js +1 -1
- package/examples/typescript/index.html +3 -2
- package/examples/uiSystem/game.js +134 -0
- package/examples/uiSystem/index.html +25 -0
- package/examples/uiSystem/tiles.png +0 -0
- package/jsconfig.json +11 -0
- package/package.json +1 -1
- package/plugins/box2d.js +2 -1
- package/plugins/postProcess.js +6 -7
- package/plugins/uiSystem.js +243 -0
- package/src/engine.js +48 -20
- package/src/engineAudio.js +10 -13
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +101 -27
- package/src/engineExport.js +18 -2
- package/src/engineInput.js +2 -2
- package/src/engineSettings.js +1 -1
- package/src/engineUtilities.js +1 -1
- package/src/engineWebGL.js +11 -4
package/dist/littlejs.js
CHANGED
|
@@ -128,7 +128,6 @@ function debugPoint(pos, color, time, angle)
|
|
|
128
128
|
* @memberof Debug */
|
|
129
129
|
function debugLine(posA, posB, color, thickness=.1, time)
|
|
130
130
|
{
|
|
131
|
-
ASSERT(typeof color == 'string', 'pass in css color strings');
|
|
132
131
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
133
132
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
134
133
|
debugRect(posA.add(halfDelta), size, color, time, halfDelta.angle(), true);
|
|
@@ -204,6 +203,7 @@ function debugShowErrors()
|
|
|
204
203
|
|
|
205
204
|
const showError = (message)=>
|
|
206
205
|
{
|
|
206
|
+
// replace entire page with error message
|
|
207
207
|
document.body.style.backgroundColor = '#111';
|
|
208
208
|
document.body.innerHTML = `<pre style=color:#f00;font-size:50px>` + message;
|
|
209
209
|
}
|
|
@@ -1205,7 +1205,7 @@ class Color
|
|
|
1205
1205
|
* @return {String} */
|
|
1206
1206
|
toString(useAlpha = true)
|
|
1207
1207
|
{
|
|
1208
|
-
const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
|
|
1208
|
+
const toHex = (c)=> ((c=clamp(c)*255|0)<16 ? '0' : '') + c.toString(16);
|
|
1209
1209
|
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
1210
1210
|
}
|
|
1211
1211
|
|
|
@@ -1435,7 +1435,7 @@ let tileSizeDefault = vec2(16);
|
|
|
1435
1435
|
* @type {Number}
|
|
1436
1436
|
* @default
|
|
1437
1437
|
* @memberof Settings */
|
|
1438
|
-
let tileFixBleedScale =
|
|
1438
|
+
let tileFixBleedScale = 0;
|
|
1439
1439
|
|
|
1440
1440
|
///////////////////////////////////////////////////////////////////////////////
|
|
1441
1441
|
// Object settings
|
|
@@ -2337,12 +2337,13 @@ let drawCount;
|
|
|
2337
2337
|
///////////////////////////////////////////////////////////////////////////////
|
|
2338
2338
|
|
|
2339
2339
|
/**
|
|
2340
|
-
* Create a tile info object
|
|
2340
|
+
* Create a tile info object using a grid based system
|
|
2341
2341
|
* - This can take vecs or floats for easier use and conversion
|
|
2342
2342
|
* - If an index is passed in, the tile size and index will determine the position
|
|
2343
|
-
* @param {(Number|Vector2)} [pos=
|
|
2343
|
+
* @param {(Number|Vector2)} [pos=0] - Index of tile in sheet
|
|
2344
2344
|
* @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
|
|
2345
2345
|
* @param {Number} [textureIndex] - Texture index to use
|
|
2346
|
+
* @param {Number} [padding] - How many pixels padding around tiles
|
|
2346
2347
|
* @return {TileInfo}
|
|
2347
2348
|
* @example
|
|
2348
2349
|
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
@@ -2351,7 +2352,7 @@ let drawCount;
|
|
|
2351
2352
|
* tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
|
|
2352
2353
|
* @memberof Draw
|
|
2353
2354
|
*/
|
|
2354
|
-
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
2355
|
+
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
2355
2356
|
{
|
|
2356
2357
|
if (headlessMode)
|
|
2357
2358
|
return new TileInfo;
|
|
@@ -2363,17 +2364,17 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
|
2363
2364
|
size = vec2(size);
|
|
2364
2365
|
}
|
|
2365
2366
|
|
|
2366
|
-
//
|
|
2367
|
+
// use pos as a tile index
|
|
2368
|
+
const textureInfo = textureInfos[textureIndex];
|
|
2369
|
+
ASSERT(textureInfo, 'Texture not loaded');
|
|
2370
|
+
const sizePadded = size.add(vec2(padding*2));
|
|
2371
|
+
const cols = textureInfo.size.x / sizePadded.x |0;
|
|
2367
2372
|
if (typeof pos === 'number')
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
ASSERT(textureInfo, 'Texture not loaded');
|
|
2371
|
-
const cols = textureInfo.size.x / size.x |0;
|
|
2372
|
-
pos = vec2((pos%cols)*size.x, (pos/cols|0)*size.y);
|
|
2373
|
-
}
|
|
2373
|
+
pos = vec2(pos%cols, pos/cols|0);
|
|
2374
|
+
pos = vec2(pos.x*sizePadded.x+padding, pos.y*sizePadded.y+padding);
|
|
2374
2375
|
|
|
2375
2376
|
// return a tile info object
|
|
2376
|
-
return new TileInfo(pos, size, textureIndex);
|
|
2377
|
+
return new TileInfo(pos, size, textureIndex, padding);
|
|
2377
2378
|
}
|
|
2378
2379
|
|
|
2379
2380
|
/**
|
|
@@ -2385,8 +2386,9 @@ class TileInfo
|
|
|
2385
2386
|
* @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
|
|
2386
2387
|
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
2387
2388
|
* @param {Number} [textureIndex] - Texture index to use
|
|
2389
|
+
* @param {Number} [padding] - How many pixels padding around tiles
|
|
2388
2390
|
*/
|
|
2389
|
-
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
2391
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
2390
2392
|
{
|
|
2391
2393
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
2392
2394
|
this.pos = pos.copy();
|
|
@@ -2394,6 +2396,8 @@ class TileInfo
|
|
|
2394
2396
|
this.size = size.copy();
|
|
2395
2397
|
/** @property {Number} - Texture index to use */
|
|
2396
2398
|
this.textureIndex = textureIndex;
|
|
2399
|
+
/** @property {Number} - How many pixels padding around tiles */
|
|
2400
|
+
this.padding = padding;
|
|
2397
2401
|
}
|
|
2398
2402
|
|
|
2399
2403
|
/** Returns a copy of this tile offset by a vector
|
|
@@ -2410,7 +2414,7 @@ class TileInfo
|
|
|
2410
2414
|
frame(frame)
|
|
2411
2415
|
{
|
|
2412
2416
|
ASSERT(typeof frame == 'number');
|
|
2413
|
-
return this.offset(vec2(frame*this.size.x, 0));
|
|
2417
|
+
return this.offset(vec2(frame*(this.size.x+this.padding*2), 0));
|
|
2414
2418
|
}
|
|
2415
2419
|
|
|
2416
2420
|
/** Returns the texture info for this tile
|
|
@@ -2435,8 +2439,6 @@ class TextureInfo
|
|
|
2435
2439
|
this.size = vec2(image.width, image.height);
|
|
2436
2440
|
/** @property {WebGLTexture} - webgl texture */
|
|
2437
2441
|
this.glTexture = glEnable && glCreateTexture(image);
|
|
2438
|
-
/** @property {Vector2} - size to adjust tile to fix bleeding */
|
|
2439
|
-
this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
|
|
2440
2442
|
}
|
|
2441
2443
|
}
|
|
2442
2444
|
|
|
@@ -2505,11 +2507,12 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
|
2505
2507
|
if (textureInfo)
|
|
2506
2508
|
{
|
|
2507
2509
|
// calculate uvs and render
|
|
2508
|
-
const
|
|
2509
|
-
const
|
|
2510
|
-
const
|
|
2511
|
-
const
|
|
2512
|
-
const
|
|
2510
|
+
const sizeInverse = vec2(1).divide(textureInfo.size);
|
|
2511
|
+
const x = tileInfo.pos.x * sizeInverse.x;
|
|
2512
|
+
const y = tileInfo.pos.y * sizeInverse.y;
|
|
2513
|
+
const w = tileInfo.size.x * sizeInverse.x;
|
|
2514
|
+
const h = tileInfo.size.y * sizeInverse.y;
|
|
2515
|
+
const tileImageFixBleed = sizeInverse.scale(tileFixBleedScale);
|
|
2513
2516
|
glSetTexture(textureInfo.glTexture);
|
|
2514
2517
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
2515
2518
|
x + tileImageFixBleed.x, y + tileImageFixBleed.y,
|
|
@@ -2526,6 +2529,7 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
|
2526
2529
|
{
|
|
2527
2530
|
// normal canvas 2D rendering method (slower)
|
|
2528
2531
|
showWatermark && ++drawCount;
|
|
2532
|
+
size = vec2(size.x, -size.y); // fix upside down sprites
|
|
2529
2533
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
2530
2534
|
{
|
|
2531
2535
|
if (textureInfo)
|
|
@@ -2563,6 +2567,74 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
2563
2567
|
drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
|
|
2564
2568
|
}
|
|
2565
2569
|
|
|
2570
|
+
/** Draw colored polygon using passed in points
|
|
2571
|
+
* @param {Array} points - Array of Vector2 points
|
|
2572
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2573
|
+
* @param {Number} [lineWidth=0]
|
|
2574
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2575
|
+
* @param {Boolean} [screenSpace=false]
|
|
2576
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2577
|
+
* @memberof Draw */
|
|
2578
|
+
function drawPoly(points, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2579
|
+
{
|
|
2580
|
+
context.fillStyle = color.toString();
|
|
2581
|
+
context.beginPath();
|
|
2582
|
+
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
2583
|
+
context.lineTo(point.x, point.y);
|
|
2584
|
+
context.closePath();
|
|
2585
|
+
context.fill();
|
|
2586
|
+
if (lineWidth)
|
|
2587
|
+
{
|
|
2588
|
+
context.strokeStyle = lineColor.toString();
|
|
2589
|
+
context.lineWidth = screenSpace ? lineWidth : lineWidth*cameraScale;
|
|
2590
|
+
context.stroke();
|
|
2591
|
+
}
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
/** Draw colored ellipse using passed in point
|
|
2595
|
+
* @param {Vector2} pos
|
|
2596
|
+
* @param {Number} [width=1]
|
|
2597
|
+
* @param {Number} [height=1]
|
|
2598
|
+
* @param {Number} [angle=0]
|
|
2599
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2600
|
+
* @param {Number} [lineWidth=0]
|
|
2601
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2602
|
+
* @param {Boolean} [screenSpace=false]
|
|
2603
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2604
|
+
* @memberof Draw */
|
|
2605
|
+
function drawEllipse(pos, width=1, height=1, angle=0, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2606
|
+
{
|
|
2607
|
+
if (!screenSpace)
|
|
2608
|
+
{
|
|
2609
|
+
pos = worldToScreen(pos);
|
|
2610
|
+
width *= cameraScale;
|
|
2611
|
+
height *= cameraScale;
|
|
2612
|
+
lineWidth *= cameraScale;
|
|
2613
|
+
}
|
|
2614
|
+
context.fillStyle = color.toString();
|
|
2615
|
+
context.beginPath();
|
|
2616
|
+
context.ellipse(pos.x, pos.y, width, height, angle, 0, 9);
|
|
2617
|
+
context.fill();
|
|
2618
|
+
if (lineWidth)
|
|
2619
|
+
{
|
|
2620
|
+
context.strokeStyle = lineColor.toString();
|
|
2621
|
+
context.lineWidth = lineWidth;
|
|
2622
|
+
context.stroke();
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
/** Draw colored circle using passed in point
|
|
2627
|
+
* @param {Vector2} pos
|
|
2628
|
+
* @param {Number} [radius=1]
|
|
2629
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2630
|
+
* @param {Number} [lineWidth=0]
|
|
2631
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2632
|
+
* @param {Boolean} [screenSpace=false]
|
|
2633
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2634
|
+
* @memberof Draw */
|
|
2635
|
+
function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2636
|
+
{ drawEllipse(pos, radius, radius, 0, color, lineWidth, lineColor, screenSpace, context); }
|
|
2637
|
+
|
|
2566
2638
|
/** Draw colored line between two points
|
|
2567
2639
|
* @param {Vector2} posA
|
|
2568
2640
|
* @param {Vector2} posB
|
|
@@ -2633,10 +2705,11 @@ function setBlendMode(additive, useWebGL=glEnable, context)
|
|
|
2633
2705
|
* @param {CanvasTextAlign} [textAlign='center']
|
|
2634
2706
|
* @param {String} [font=fontDefault]
|
|
2635
2707
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2708
|
+
* @param {Number} [maxWidth]
|
|
2636
2709
|
* @memberof Draw */
|
|
2637
|
-
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, context)
|
|
2710
|
+
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, context, maxWidth)
|
|
2638
2711
|
{
|
|
2639
|
-
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, context);
|
|
2712
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, context, maxWidth);
|
|
2640
2713
|
}
|
|
2641
2714
|
|
|
2642
2715
|
/** Draw text on overlay canvas in screen space
|
|
@@ -2650,8 +2723,9 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
2650
2723
|
* @param {CanvasTextAlign} [textAlign]
|
|
2651
2724
|
* @param {String} [font=fontDefault]
|
|
2652
2725
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2726
|
+
* @param {Number} [maxWidth]
|
|
2653
2727
|
* @memberof Draw */
|
|
2654
|
-
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, context=overlayContext)
|
|
2728
|
+
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, context=overlayContext, maxWidth=undefined)
|
|
2655
2729
|
{
|
|
2656
2730
|
context.fillStyle = color.toString();
|
|
2657
2731
|
context.lineWidth = lineWidth;
|
|
@@ -2664,8 +2738,8 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
2664
2738
|
pos = pos.copy();
|
|
2665
2739
|
(text+'').split('\n').forEach(line=>
|
|
2666
2740
|
{
|
|
2667
|
-
lineWidth && context.strokeText(line, pos.x, pos.y);
|
|
2668
|
-
context.fillText(line, pos.x, pos.y);
|
|
2741
|
+
lineWidth && context.strokeText(line, pos.x, pos.y, maxWidth);
|
|
2742
|
+
context.fillText(line, pos.x, pos.y, maxWidth);
|
|
2669
2743
|
pos.y += size;
|
|
2670
2744
|
});
|
|
2671
2745
|
}
|
|
@@ -2773,8 +2847,8 @@ function toggleFullscreen()
|
|
|
2773
2847
|
if (document.exitFullscreen)
|
|
2774
2848
|
document.exitFullscreen();
|
|
2775
2849
|
}
|
|
2776
|
-
else if (
|
|
2777
|
-
|
|
2850
|
+
else if (engineRoot.requestFullscreen)
|
|
2851
|
+
engineRoot.requestFullscreen();
|
|
2778
2852
|
}
|
|
2779
2853
|
/**
|
|
2780
2854
|
* LittleJS Input System
|
|
@@ -2945,7 +3019,7 @@ function inputInit()
|
|
|
2945
3019
|
|
|
2946
3020
|
onkeydown = (e)=>
|
|
2947
3021
|
{
|
|
2948
|
-
if (debug && e.target !=
|
|
3022
|
+
if (debug && e.target != engineRoot) return;
|
|
2949
3023
|
if (!e.repeat)
|
|
2950
3024
|
{
|
|
2951
3025
|
isUsingGamepad = false;
|
|
@@ -2958,7 +3032,7 @@ function inputInit()
|
|
|
2958
3032
|
|
|
2959
3033
|
onkeyup = (e)=>
|
|
2960
3034
|
{
|
|
2961
|
-
if (debug && e.target !=
|
|
3035
|
+
if (debug && e.target != engineRoot) return;
|
|
2962
3036
|
inputData[0][e.code] = 4;
|
|
2963
3037
|
if (inputWASDEmulateDirection)
|
|
2964
3038
|
inputData[0][remapKey(e.code)] = 4;
|
|
@@ -3610,17 +3684,6 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3610
3684
|
{
|
|
3611
3685
|
if (!soundEnable || headlessMode) return;
|
|
3612
3686
|
|
|
3613
|
-
// prevent sounds from building up if they can't be played
|
|
3614
|
-
if (audioContext.state != 'running')
|
|
3615
|
-
{
|
|
3616
|
-
// fix stalled audio
|
|
3617
|
-
audioContext.resume().then(()=>
|
|
3618
|
-
playSamples(sampleChannels, volume, rate, pan, loop, sampleRate, gainNode));
|
|
3619
|
-
|
|
3620
|
-
// prevent suspended sounds from building up
|
|
3621
|
-
return;
|
|
3622
|
-
}
|
|
3623
|
-
|
|
3624
3687
|
// create buffer and source
|
|
3625
3688
|
const channelCount = sampleChannels.length;
|
|
3626
3689
|
const sampleLength = sampleChannels[0].length;
|
|
@@ -3642,8 +3705,16 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3642
3705
|
const pannerNode = new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)});
|
|
3643
3706
|
source.connect(pannerNode).connect(gainNode);
|
|
3644
3707
|
|
|
3645
|
-
// play
|
|
3646
|
-
|
|
3708
|
+
// play the sound
|
|
3709
|
+
if (audioContext.state != 'running')
|
|
3710
|
+
{
|
|
3711
|
+
// fix stalled audio and play
|
|
3712
|
+
audioContext.resume().then(()=>source.start());
|
|
3713
|
+
}
|
|
3714
|
+
else
|
|
3715
|
+
source.start();
|
|
3716
|
+
|
|
3717
|
+
// return sound
|
|
3647
3718
|
return source;
|
|
3648
3719
|
}
|
|
3649
3720
|
|
|
@@ -4803,10 +4874,10 @@ function glInit()
|
|
|
4803
4874
|
|
|
4804
4875
|
// create the canvas and textures
|
|
4805
4876
|
glCanvas = document.createElement('canvas');
|
|
4806
|
-
glContext = glCanvas.getContext('webgl2');
|
|
4877
|
+
glContext = glCanvas.getContext('webgl2', {antialias:!canvasPixelated});
|
|
4807
4878
|
|
|
4808
4879
|
// some browsers are much faster without copying the gl buffer so we just overlay it instead
|
|
4809
|
-
glOverlay &&
|
|
4880
|
+
glOverlay && engineRoot.appendChild(glCanvas);
|
|
4810
4881
|
|
|
4811
4882
|
// setup vertex and fragment shaders
|
|
4812
4883
|
glShader = glCreateProgram(
|
|
@@ -4861,7 +4932,8 @@ function glPreRender()
|
|
|
4861
4932
|
// set up the shader
|
|
4862
4933
|
glContext.useProgram(glShader);
|
|
4863
4934
|
glContext.activeTexture(gl_TEXTURE0);
|
|
4864
|
-
|
|
4935
|
+
if (textureInfos[0])
|
|
4936
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
|
|
4865
4937
|
|
|
4866
4938
|
// set vertex attributes
|
|
4867
4939
|
let offset = glAdditive = glBatchAdditive = 0;
|
|
@@ -4959,8 +5031,14 @@ function glCreateTexture(image)
|
|
|
4959
5031
|
// build the texture
|
|
4960
5032
|
const texture = glContext.createTexture();
|
|
4961
5033
|
glContext.bindTexture(gl_TEXTURE_2D, texture);
|
|
4962
|
-
if (image)
|
|
5034
|
+
if (image && image.width)
|
|
4963
5035
|
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
5036
|
+
else
|
|
5037
|
+
{
|
|
5038
|
+
// create a white texture
|
|
5039
|
+
const whitePixel = new Uint8Array([255, 255, 255, 255]);
|
|
5040
|
+
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, 1, 1, 0, gl_RGBA, gl_UNSIGNED_BYTE, whitePixel);
|
|
5041
|
+
}
|
|
4964
5042
|
|
|
4965
5043
|
// use point filtering for pixelated rendering
|
|
4966
5044
|
const filter = canvasPixelated ? gl_NEAREST : gl_LINEAR;
|
|
@@ -5103,7 +5181,7 @@ const engineName = 'LittleJS';
|
|
|
5103
5181
|
* @type {String}
|
|
5104
5182
|
* @default
|
|
5105
5183
|
* @memberof Engine */
|
|
5106
|
-
const engineVersion = '1.
|
|
5184
|
+
const engineVersion = '1.10.2';
|
|
5107
5185
|
|
|
5108
5186
|
/** Frames per second to update
|
|
5109
5187
|
* @type {Number}
|
|
@@ -5148,6 +5226,12 @@ let timeReal = 0;
|
|
|
5148
5226
|
* @memberof Engine */
|
|
5149
5227
|
let paused = false;
|
|
5150
5228
|
|
|
5229
|
+
/** The root element that engine is attached to
|
|
5230
|
+
* @type {HTMLElement}
|
|
5231
|
+
* @default document.body
|
|
5232
|
+
* @memberof Engine */
|
|
5233
|
+
let engineRoot;
|
|
5234
|
+
|
|
5151
5235
|
/** Set if game is paused
|
|
5152
5236
|
* @param {Boolean} isPaused
|
|
5153
5237
|
* @memberof Engine */
|
|
@@ -5181,8 +5265,9 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
5181
5265
|
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
5182
5266
|
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
5183
5267
|
* @param {Array} [imageSources=['tiles.png']] - Image to load
|
|
5268
|
+
* @param {HTMLElement} [rootElement] - Root element to attach to, the document body by default
|
|
5184
5269
|
* @memberof Engine */
|
|
5185
|
-
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[
|
|
5270
|
+
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
5186
5271
|
{
|
|
5187
5272
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
5188
5273
|
|
|
@@ -5224,6 +5309,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5224
5309
|
for (const o of engineObjects)
|
|
5225
5310
|
o.parent || o.updateTransforms();
|
|
5226
5311
|
inputUpdate();
|
|
5312
|
+
pluginUpdateList.forEach(f=>f());
|
|
5227
5313
|
debugUpdate();
|
|
5228
5314
|
gameUpdatePost();
|
|
5229
5315
|
inputUpdatePost();
|
|
@@ -5339,16 +5425,22 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5339
5425
|
}
|
|
5340
5426
|
|
|
5341
5427
|
// setup html
|
|
5342
|
-
const
|
|
5428
|
+
const styleRoot =
|
|
5343
5429
|
'margin:0;overflow:hidden;' + // fill the window
|
|
5430
|
+
'width:100vw;height:100vh;' + // fill the window
|
|
5431
|
+
'display:flex;' + // use flexbox
|
|
5432
|
+
'align-items:center;' + // horizontal center
|
|
5433
|
+
(canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
|
|
5434
|
+
'justify-content:center;' + // vertical center
|
|
5344
5435
|
'background:#000;' + // set background color
|
|
5345
5436
|
'user-select:none;' + // prevent hold to select
|
|
5346
5437
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
5347
5438
|
(!touchInputEnable ? '' : // no touch css setttings
|
|
5348
5439
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
5349
5440
|
'-webkit-touch-callout:none');// compatibility for ios
|
|
5350
|
-
|
|
5351
|
-
|
|
5441
|
+
engineRoot = rootElement;
|
|
5442
|
+
engineRoot.style.cssText = styleRoot;
|
|
5443
|
+
engineRoot.appendChild(mainCanvas = document.createElement('canvas'));
|
|
5352
5444
|
mainContext = mainCanvas.getContext('2d');
|
|
5353
5445
|
|
|
5354
5446
|
// init stuff and start engine
|
|
@@ -5358,13 +5450,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5358
5450
|
glInit();
|
|
5359
5451
|
|
|
5360
5452
|
// create overlay canvas for hud to appear above gl canvas
|
|
5361
|
-
|
|
5453
|
+
engineRoot.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
5362
5454
|
overlayContext = overlayCanvas.getContext('2d');
|
|
5363
5455
|
|
|
5364
5456
|
// set canvas style
|
|
5365
|
-
const styleCanvas = 'position:absolute;
|
|
5366
|
-
|
|
5367
|
-
(glCanvas
|
|
5457
|
+
const styleCanvas = 'position:absolute'; // allow canvases to overlap
|
|
5458
|
+
mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
5459
|
+
if (glCanvas)
|
|
5460
|
+
glCanvas.style.cssText = styleCanvas;
|
|
5368
5461
|
updateCanvas();
|
|
5369
5462
|
|
|
5370
5463
|
// create promises for loading images
|
|
@@ -5381,19 +5474,32 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5381
5474
|
})
|
|
5382
5475
|
);
|
|
5383
5476
|
|
|
5384
|
-
|
|
5385
|
-
showSplashScreen && promises.push(new Promise(resolve =>
|
|
5477
|
+
if (!imageSources.length)
|
|
5386
5478
|
{
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
updateSplash();
|
|
5390
|
-
function updateSplash()
|
|
5479
|
+
// no images to load
|
|
5480
|
+
promises.push(new Promise(resolve =>
|
|
5391
5481
|
{
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5482
|
+
textureInfos[0] = new TextureInfo(new Image);
|
|
5483
|
+
resolve();
|
|
5484
|
+
}));
|
|
5485
|
+
}
|
|
5486
|
+
|
|
5487
|
+
if (showSplashScreen)
|
|
5488
|
+
{
|
|
5489
|
+
// draw splash screen
|
|
5490
|
+
promises.push(new Promise(resolve =>
|
|
5491
|
+
{
|
|
5492
|
+
let t = 0;
|
|
5493
|
+
console.log(`${engineName} Engine v${engineVersion}`);
|
|
5494
|
+
updateSplash();
|
|
5495
|
+
function updateSplash()
|
|
5496
|
+
{
|
|
5497
|
+
clearInput();
|
|
5498
|
+
drawEngineSplashScreen(t+=.01);
|
|
5499
|
+
t>1 ? resolve() : setTimeout(updateSplash, 16);
|
|
5500
|
+
}
|
|
5501
|
+
}));
|
|
5502
|
+
}
|
|
5397
5503
|
|
|
5398
5504
|
// load all of the images
|
|
5399
5505
|
Promise.all(promises).then(startEngine);
|