littlejsengine 1.9.11 → 1.10.4
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 +9 -13
- package/dist/littlejs.d.ts +129 -10
- package/dist/littlejs.esm.js +220 -75
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +188 -73
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +187 -72
- package/examples/box2d/game.js +4 -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/README.md +9 -7
- package/examples/breakoutTutorial/game.js +6 -6
- 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/build/index.html +1 -0
- package/examples/js13k/build/index.js +1 -0
- package/examples/js13k/build/tiles.png +0 -0
- package/examples/js13k/game - Copy.zip +0 -0
- package/examples/js13k/game.js +1 -1
- package/examples/js13k/game.zip +0 -0
- 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 +7 -5
- package/examples/platformer/gameCharacter.js +12 -11
- package/examples/platformer/gameEffects.js +3 -4
- package/examples/platformer/gameLevel.js +18 -34
- package/examples/platformer/gameObjects.js +9 -15
- package/examples/platformer/index.html +10 -9
- package/examples/puzzle/game.js +1 -1
- package/examples/puzzle/index.html +4 -3
- package/examples/starter/build/index.html +2 -0
- package/examples/starter/build/index.js +1 -0
- package/examples/starter/build/tiles.png +0 -0
- package/examples/starter/game.js +4 -4
- package/examples/starter/game.zip +0 -0
- package/examples/starter/index.html +15 -14
- package/examples/stress/index.html +3 -2
- package/examples/typescript/build/build/littlejs.esm.js +4327 -0
- package/examples/typescript/build/dist/littlejs.esm.js +4425 -0
- package/examples/typescript/build/examples/typescript/build.js +24 -0
- package/examples/typescript/build/examples/typescript/game.js +100 -0
- package/examples/typescript/build/examples/typescript/test/build/littlejs.esm.js +3934 -0
- package/examples/typescript/build/examples/typescript/test/examples/typescript/build.js +86 -0
- package/examples/typescript/build/examples/typescript/test/examples/typescript/game.js +92 -0
- package/examples/typescript/game.js +1 -1
- package/examples/typescript/game.ts +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 +14 -8
- package/plugins/uiSystem.js +243 -0
- package/src/engine.js +42 -22
- package/src/engineAudio.js +10 -13
- package/src/engineDebug.js +1 -1
- package/src/engineDraw.js +102 -27
- package/src/engineExport.js +32 -2
- package/src/engineInput.js +1 -3
- package/src/engineObject.js +1 -0
- package/src/engineSettings.js +1 -1
- package/src/engineTileLayer.js +2 -1
- package/src/engineUtilities.js +2 -1
- package/src/engineWebGL.js +26 -4
package/dist/littlejs.esm.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
|
}
|
|
@@ -953,6 +953,7 @@ class Vector2
|
|
|
953
953
|
* @param {Number} [length] */
|
|
954
954
|
setDirection(direction, length=1)
|
|
955
955
|
{
|
|
956
|
+
direction = mod(direction, 4);
|
|
956
957
|
ASSERT(direction==0 || direction==1 || direction==2 || direction==3);
|
|
957
958
|
return vec2(direction%2 ? direction-1 ? -length : length : 0,
|
|
958
959
|
direction%2 ? 0 : direction ? -length : length);
|
|
@@ -1205,7 +1206,7 @@ class Color
|
|
|
1205
1206
|
* @return {String} */
|
|
1206
1207
|
toString(useAlpha = true)
|
|
1207
1208
|
{
|
|
1208
|
-
const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
|
|
1209
|
+
const toHex = (c)=> ((c=clamp(c)*255|0)<16 ? '0' : '') + c.toString(16);
|
|
1209
1210
|
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
1210
1211
|
}
|
|
1211
1212
|
|
|
@@ -1435,7 +1436,7 @@ let tileSizeDefault = vec2(16);
|
|
|
1435
1436
|
* @type {Number}
|
|
1436
1437
|
* @default
|
|
1437
1438
|
* @memberof Settings */
|
|
1438
|
-
let tileFixBleedScale =
|
|
1439
|
+
let tileFixBleedScale = 0;
|
|
1439
1440
|
|
|
1440
1441
|
///////////////////////////////////////////////////////////////////////////////
|
|
1441
1442
|
// Object settings
|
|
@@ -2135,6 +2136,7 @@ class EngineObject
|
|
|
2135
2136
|
this.pos.x = oldPos.x;
|
|
2136
2137
|
this.velocity.x *= -this.elasticity;
|
|
2137
2138
|
}
|
|
2139
|
+
debugOverlay && debugPhysics && debugRect(this.pos, this.size, '#f00');
|
|
2138
2140
|
}
|
|
2139
2141
|
}
|
|
2140
2142
|
}
|
|
@@ -2337,12 +2339,13 @@ let drawCount;
|
|
|
2337
2339
|
///////////////////////////////////////////////////////////////////////////////
|
|
2338
2340
|
|
|
2339
2341
|
/**
|
|
2340
|
-
* Create a tile info object
|
|
2342
|
+
* Create a tile info object using a grid based system
|
|
2341
2343
|
* - This can take vecs or floats for easier use and conversion
|
|
2342
2344
|
* - If an index is passed in, the tile size and index will determine the position
|
|
2343
|
-
* @param {(Number|Vector2)} [pos=
|
|
2345
|
+
* @param {(Number|Vector2)} [pos=0] - Index of tile in sheet
|
|
2344
2346
|
* @param {(Number|Vector2)} [size=tileSizeDefault] - Size of tile in pixels
|
|
2345
2347
|
* @param {Number} [textureIndex] - Texture index to use
|
|
2348
|
+
* @param {Number} [padding] - How many pixels padding around tiles
|
|
2346
2349
|
* @return {TileInfo}
|
|
2347
2350
|
* @example
|
|
2348
2351
|
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
@@ -2351,7 +2354,7 @@ let drawCount;
|
|
|
2351
2354
|
* tile(vec2(4,8), vec2(30,10)) // a tile at pixel location (4,8) with a size of (30,10)
|
|
2352
2355
|
* @memberof Draw
|
|
2353
2356
|
*/
|
|
2354
|
-
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
2357
|
+
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
2355
2358
|
{
|
|
2356
2359
|
if (headlessMode)
|
|
2357
2360
|
return new TileInfo;
|
|
@@ -2363,17 +2366,17 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
|
2363
2366
|
size = vec2(size);
|
|
2364
2367
|
}
|
|
2365
2368
|
|
|
2366
|
-
//
|
|
2369
|
+
// use pos as a tile index
|
|
2370
|
+
const textureInfo = textureInfos[textureIndex];
|
|
2371
|
+
ASSERT(textureInfo, 'Texture not loaded');
|
|
2372
|
+
const sizePadded = size.add(vec2(padding*2));
|
|
2373
|
+
const cols = textureInfo.size.x / sizePadded.x |0;
|
|
2367
2374
|
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
|
-
}
|
|
2375
|
+
pos = vec2(pos%cols, pos/cols|0);
|
|
2376
|
+
pos = vec2(pos.x*sizePadded.x+padding, pos.y*sizePadded.y+padding);
|
|
2374
2377
|
|
|
2375
2378
|
// return a tile info object
|
|
2376
|
-
return new TileInfo(pos, size, textureIndex);
|
|
2379
|
+
return new TileInfo(pos, size, textureIndex, padding);
|
|
2377
2380
|
}
|
|
2378
2381
|
|
|
2379
2382
|
/**
|
|
@@ -2385,8 +2388,9 @@ class TileInfo
|
|
|
2385
2388
|
* @param {Vector2} [pos=(0,0)] - Top left corner of tile in pixels
|
|
2386
2389
|
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
2387
2390
|
* @param {Number} [textureIndex] - Texture index to use
|
|
2391
|
+
* @param {Number} [padding] - How many pixels padding around tiles
|
|
2388
2392
|
*/
|
|
2389
|
-
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0)
|
|
2393
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
2390
2394
|
{
|
|
2391
2395
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
2392
2396
|
this.pos = pos.copy();
|
|
@@ -2394,6 +2398,8 @@ class TileInfo
|
|
|
2394
2398
|
this.size = size.copy();
|
|
2395
2399
|
/** @property {Number} - Texture index to use */
|
|
2396
2400
|
this.textureIndex = textureIndex;
|
|
2401
|
+
/** @property {Number} - How many pixels padding around tiles */
|
|
2402
|
+
this.padding = padding;
|
|
2397
2403
|
}
|
|
2398
2404
|
|
|
2399
2405
|
/** Returns a copy of this tile offset by a vector
|
|
@@ -2410,7 +2416,7 @@ class TileInfo
|
|
|
2410
2416
|
frame(frame)
|
|
2411
2417
|
{
|
|
2412
2418
|
ASSERT(typeof frame == 'number');
|
|
2413
|
-
return this.offset(vec2(frame*this.size.x, 0));
|
|
2419
|
+
return this.offset(vec2(frame*(this.size.x+this.padding*2), 0));
|
|
2414
2420
|
}
|
|
2415
2421
|
|
|
2416
2422
|
/** Returns the texture info for this tile
|
|
@@ -2435,8 +2441,6 @@ class TextureInfo
|
|
|
2435
2441
|
this.size = vec2(image.width, image.height);
|
|
2436
2442
|
/** @property {WebGLTexture} - webgl texture */
|
|
2437
2443
|
this.glTexture = glEnable && glCreateTexture(image);
|
|
2438
|
-
/** @property {Vector2} - size to adjust tile to fix bleeding */
|
|
2439
|
-
this.fixBleedSize = vec2(tileFixBleedScale).divide(this.size);
|
|
2440
2444
|
}
|
|
2441
2445
|
}
|
|
2442
2446
|
|
|
@@ -2505,11 +2509,12 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
|
2505
2509
|
if (textureInfo)
|
|
2506
2510
|
{
|
|
2507
2511
|
// calculate uvs and render
|
|
2508
|
-
const
|
|
2509
|
-
const
|
|
2510
|
-
const
|
|
2511
|
-
const
|
|
2512
|
-
const
|
|
2512
|
+
const sizeInverse = vec2(1).divide(textureInfo.size);
|
|
2513
|
+
const x = tileInfo.pos.x * sizeInverse.x;
|
|
2514
|
+
const y = tileInfo.pos.y * sizeInverse.y;
|
|
2515
|
+
const w = tileInfo.size.x * sizeInverse.x;
|
|
2516
|
+
const h = tileInfo.size.y * sizeInverse.y;
|
|
2517
|
+
const tileImageFixBleed = sizeInverse.scale(tileFixBleedScale);
|
|
2513
2518
|
glSetTexture(textureInfo.glTexture);
|
|
2514
2519
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
2515
2520
|
x + tileImageFixBleed.x, y + tileImageFixBleed.y,
|
|
@@ -2526,6 +2531,7 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
|
|
|
2526
2531
|
{
|
|
2527
2532
|
// normal canvas 2D rendering method (slower)
|
|
2528
2533
|
showWatermark && ++drawCount;
|
|
2534
|
+
size = vec2(size.x, -size.y); // fix upside down sprites
|
|
2529
2535
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
2530
2536
|
{
|
|
2531
2537
|
if (textureInfo)
|
|
@@ -2579,6 +2585,74 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, contex
|
|
|
2579
2585
|
drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace, context);
|
|
2580
2586
|
}
|
|
2581
2587
|
|
|
2588
|
+
/** Draw colored polygon using passed in points
|
|
2589
|
+
* @param {Array} points - Array of Vector2 points
|
|
2590
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2591
|
+
* @param {Number} [lineWidth=0]
|
|
2592
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2593
|
+
* @param {Boolean} [screenSpace=false]
|
|
2594
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2595
|
+
* @memberof Draw */
|
|
2596
|
+
function drawPoly(points, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2597
|
+
{
|
|
2598
|
+
context.fillStyle = color.toString();
|
|
2599
|
+
context.beginPath();
|
|
2600
|
+
for (const point of screenSpace ? points : points.map(worldToScreen))
|
|
2601
|
+
context.lineTo(point.x, point.y);
|
|
2602
|
+
context.closePath();
|
|
2603
|
+
context.fill();
|
|
2604
|
+
if (lineWidth)
|
|
2605
|
+
{
|
|
2606
|
+
context.strokeStyle = lineColor.toString();
|
|
2607
|
+
context.lineWidth = screenSpace ? lineWidth : lineWidth*cameraScale;
|
|
2608
|
+
context.stroke();
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
|
|
2612
|
+
/** Draw colored ellipse using passed in point
|
|
2613
|
+
* @param {Vector2} pos
|
|
2614
|
+
* @param {Number} [width=1]
|
|
2615
|
+
* @param {Number} [height=1]
|
|
2616
|
+
* @param {Number} [angle=0]
|
|
2617
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2618
|
+
* @param {Number} [lineWidth=0]
|
|
2619
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2620
|
+
* @param {Boolean} [screenSpace=false]
|
|
2621
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2622
|
+
* @memberof Draw */
|
|
2623
|
+
function drawEllipse(pos, width=1, height=1, angle=0, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2624
|
+
{
|
|
2625
|
+
if (!screenSpace)
|
|
2626
|
+
{
|
|
2627
|
+
pos = worldToScreen(pos);
|
|
2628
|
+
width *= cameraScale;
|
|
2629
|
+
height *= cameraScale;
|
|
2630
|
+
lineWidth *= cameraScale;
|
|
2631
|
+
}
|
|
2632
|
+
context.fillStyle = color.toString();
|
|
2633
|
+
context.beginPath();
|
|
2634
|
+
context.ellipse(pos.x, pos.y, width, height, angle, 0, 9);
|
|
2635
|
+
context.fill();
|
|
2636
|
+
if (lineWidth)
|
|
2637
|
+
{
|
|
2638
|
+
context.strokeStyle = lineColor.toString();
|
|
2639
|
+
context.lineWidth = lineWidth;
|
|
2640
|
+
context.stroke();
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2644
|
+
/** Draw colored circle using passed in point
|
|
2645
|
+
* @param {Vector2} pos
|
|
2646
|
+
* @param {Number} [radius=1]
|
|
2647
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2648
|
+
* @param {Number} [lineWidth=0]
|
|
2649
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2650
|
+
* @param {Boolean} [screenSpace=false]
|
|
2651
|
+
* @param {CanvasRenderingContext2D} [context=mainContext]
|
|
2652
|
+
* @memberof Draw */
|
|
2653
|
+
function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), screenSpace, context=mainContext)
|
|
2654
|
+
{ drawEllipse(pos, radius, radius, 0, color, lineWidth, lineColor, screenSpace, context); }
|
|
2655
|
+
|
|
2582
2656
|
/** Draw directly to a 2d canvas context in world space
|
|
2583
2657
|
* @param {Vector2} pos
|
|
2584
2658
|
* @param {Vector2} size
|
|
@@ -2633,10 +2707,11 @@ function setBlendMode(additive, useWebGL=glEnable, context)
|
|
|
2633
2707
|
* @param {CanvasTextAlign} [textAlign='center']
|
|
2634
2708
|
* @param {String} [font=fontDefault]
|
|
2635
2709
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2710
|
+
* @param {Number} [maxWidth]
|
|
2636
2711
|
* @memberof Draw */
|
|
2637
|
-
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, context)
|
|
2712
|
+
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, context, maxWidth)
|
|
2638
2713
|
{
|
|
2639
|
-
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, context);
|
|
2714
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, context, maxWidth);
|
|
2640
2715
|
}
|
|
2641
2716
|
|
|
2642
2717
|
/** Draw text on overlay canvas in screen space
|
|
@@ -2650,8 +2725,9 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
2650
2725
|
* @param {CanvasTextAlign} [textAlign]
|
|
2651
2726
|
* @param {String} [font=fontDefault]
|
|
2652
2727
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2728
|
+
* @param {Number} [maxWidth]
|
|
2653
2729
|
* @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)
|
|
2730
|
+
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
2731
|
{
|
|
2656
2732
|
context.fillStyle = color.toString();
|
|
2657
2733
|
context.lineWidth = lineWidth;
|
|
@@ -2664,8 +2740,8 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
2664
2740
|
pos = pos.copy();
|
|
2665
2741
|
(text+'').split('\n').forEach(line=>
|
|
2666
2742
|
{
|
|
2667
|
-
lineWidth && context.strokeText(line, pos.x, pos.y);
|
|
2668
|
-
context.fillText(line, pos.x, pos.y);
|
|
2743
|
+
lineWidth && context.strokeText(line, pos.x, pos.y, maxWidth);
|
|
2744
|
+
context.fillText(line, pos.x, pos.y, maxWidth);
|
|
2669
2745
|
pos.y += size;
|
|
2670
2746
|
});
|
|
2671
2747
|
}
|
|
@@ -2768,13 +2844,14 @@ function isFullscreen() { return !!document.fullscreenElement; }
|
|
|
2768
2844
|
* @memberof Draw */
|
|
2769
2845
|
function toggleFullscreen()
|
|
2770
2846
|
{
|
|
2847
|
+
const rootElement = mainCanvas.parentElement;
|
|
2771
2848
|
if (isFullscreen())
|
|
2772
2849
|
{
|
|
2773
2850
|
if (document.exitFullscreen)
|
|
2774
2851
|
document.exitFullscreen();
|
|
2775
2852
|
}
|
|
2776
|
-
else if (
|
|
2777
|
-
|
|
2853
|
+
else if (rootElement.requestFullscreen)
|
|
2854
|
+
rootElement.requestFullscreen();
|
|
2778
2855
|
}
|
|
2779
2856
|
/**
|
|
2780
2857
|
* LittleJS Input System
|
|
@@ -2945,7 +3022,6 @@ function inputInit()
|
|
|
2945
3022
|
|
|
2946
3023
|
onkeydown = (e)=>
|
|
2947
3024
|
{
|
|
2948
|
-
if (debug && e.target != document.body) return;
|
|
2949
3025
|
if (!e.repeat)
|
|
2950
3026
|
{
|
|
2951
3027
|
isUsingGamepad = false;
|
|
@@ -2958,7 +3034,6 @@ function inputInit()
|
|
|
2958
3034
|
|
|
2959
3035
|
onkeyup = (e)=>
|
|
2960
3036
|
{
|
|
2961
|
-
if (debug && e.target != document.body) return;
|
|
2962
3037
|
inputData[0][e.code] = 4;
|
|
2963
3038
|
if (inputWASDEmulateDirection)
|
|
2964
3039
|
inputData[0][remapKey(e.code)] = 4;
|
|
@@ -3160,7 +3235,7 @@ function touchInputInit()
|
|
|
3160
3235
|
// set event pos and pass it along
|
|
3161
3236
|
const p = vec2(e.touches[0].clientX, e.touches[0].clientY);
|
|
3162
3237
|
mousePosScreen = mouseToScreen(p);
|
|
3163
|
-
wasTouching ? isUsingGamepad =
|
|
3238
|
+
wasTouching ? isUsingGamepad = touchGamepadEnable : inputData[0][button] = 3;
|
|
3164
3239
|
}
|
|
3165
3240
|
else if (wasTouching)
|
|
3166
3241
|
inputData[0][button] = inputData[0][button] & 2 | 4;
|
|
@@ -3610,17 +3685,6 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3610
3685
|
{
|
|
3611
3686
|
if (!soundEnable || headlessMode) return;
|
|
3612
3687
|
|
|
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
3688
|
// create buffer and source
|
|
3625
3689
|
const channelCount = sampleChannels.length;
|
|
3626
3690
|
const sampleLength = sampleChannels[0].length;
|
|
@@ -3642,8 +3706,16 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=false, sample
|
|
|
3642
3706
|
const pannerNode = new StereoPannerNode(audioContext, {'pan':clamp(pan, -1, 1)});
|
|
3643
3707
|
source.connect(pannerNode).connect(gainNode);
|
|
3644
3708
|
|
|
3645
|
-
// play
|
|
3646
|
-
|
|
3709
|
+
// play the sound
|
|
3710
|
+
if (audioContext.state != 'running')
|
|
3711
|
+
{
|
|
3712
|
+
// fix stalled audio and play
|
|
3713
|
+
audioContext.resume().then(()=>source.start());
|
|
3714
|
+
}
|
|
3715
|
+
else
|
|
3716
|
+
source.start();
|
|
3717
|
+
|
|
3718
|
+
// return sound
|
|
3647
3719
|
return source;
|
|
3648
3720
|
}
|
|
3649
3721
|
|
|
@@ -3959,6 +4031,7 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
3959
4031
|
if (tileData && (!object || object.collideWithTile(tileData, vec2(x, y))))
|
|
3960
4032
|
return true;
|
|
3961
4033
|
}
|
|
4034
|
+
return false;
|
|
3962
4035
|
}
|
|
3963
4036
|
|
|
3964
4037
|
/** Return the center of first tile hit (does not return the exact intersection)
|
|
@@ -3982,7 +4055,7 @@ function tileCollisionRaycast(posStart, posEnd, object)
|
|
|
3982
4055
|
let xi = unit.x * (delta.x < 0 ? posStart.x - pos.x : pos.x - posStart.x + 1);
|
|
3983
4056
|
let yi = unit.y * (delta.y < 0 ? posStart.y - pos.y : pos.y - posStart.y + 1);
|
|
3984
4057
|
|
|
3985
|
-
while (
|
|
4058
|
+
while (true)
|
|
3986
4059
|
{
|
|
3987
4060
|
// check for tile collision
|
|
3988
4061
|
const tileData = getTileCollisionData(pos);
|
|
@@ -4791,6 +4864,11 @@ let glCanvas;
|
|
|
4791
4864
|
* @memberof WebGL */
|
|
4792
4865
|
let glContext;
|
|
4793
4866
|
|
|
4867
|
+
/** Shoule webgl be setup with antialiasing, must be set before calling engineInit
|
|
4868
|
+
* @type {Boolean}
|
|
4869
|
+
* @memberof WebGL */
|
|
4870
|
+
let glAntialias = true;
|
|
4871
|
+
|
|
4794
4872
|
// WebGL internal variables not exposed to documentation
|
|
4795
4873
|
let glShader, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glInstanceCount, glAdditive, glBatchAdditive;
|
|
4796
4874
|
|
|
@@ -4803,10 +4881,11 @@ function glInit()
|
|
|
4803
4881
|
|
|
4804
4882
|
// create the canvas and textures
|
|
4805
4883
|
glCanvas = document.createElement('canvas');
|
|
4806
|
-
glContext = glCanvas.getContext('webgl2');
|
|
4884
|
+
glContext = glCanvas.getContext('webgl2', {antialias:glAntialias});
|
|
4807
4885
|
|
|
4808
4886
|
// some browsers are much faster without copying the gl buffer so we just overlay it instead
|
|
4809
|
-
|
|
4887
|
+
const rootElement = mainCanvas.parentElement;
|
|
4888
|
+
glOverlay && rootElement.appendChild(glCanvas);
|
|
4810
4889
|
|
|
4811
4890
|
// setup vertex and fragment shaders
|
|
4812
4891
|
glShader = glCreateProgram(
|
|
@@ -4861,7 +4940,8 @@ function glPreRender()
|
|
|
4861
4940
|
// set up the shader
|
|
4862
4941
|
glContext.useProgram(glShader);
|
|
4863
4942
|
glContext.activeTexture(gl_TEXTURE0);
|
|
4864
|
-
|
|
4943
|
+
if (textureInfos[0])
|
|
4944
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
|
|
4865
4945
|
|
|
4866
4946
|
// set vertex attributes
|
|
4867
4947
|
let offset = glAdditive = glBatchAdditive = 0;
|
|
@@ -4959,8 +5039,14 @@ function glCreateTexture(image)
|
|
|
4959
5039
|
// build the texture
|
|
4960
5040
|
const texture = glContext.createTexture();
|
|
4961
5041
|
glContext.bindTexture(gl_TEXTURE_2D, texture);
|
|
4962
|
-
if (image)
|
|
5042
|
+
if (image && image.width)
|
|
4963
5043
|
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
5044
|
+
else
|
|
5045
|
+
{
|
|
5046
|
+
// create a white texture
|
|
5047
|
+
const whitePixel = new Uint8Array([255, 255, 255, 255]);
|
|
5048
|
+
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, 1, 1, 0, gl_RGBA, gl_UNSIGNED_BYTE, whitePixel);
|
|
5049
|
+
}
|
|
4964
5050
|
|
|
4965
5051
|
// use point filtering for pixelated rendering
|
|
4966
5052
|
const filter = canvasPixelated ? gl_NEAREST : gl_LINEAR;
|
|
@@ -5003,6 +5089,15 @@ function glCopyToContext(context, forceDraw=false)
|
|
|
5003
5089
|
context.drawImage(glCanvas, 0, 0);
|
|
5004
5090
|
}
|
|
5005
5091
|
|
|
5092
|
+
/** Set antialiasing for webgl canvas
|
|
5093
|
+
* @param {Boolean} [antialias]
|
|
5094
|
+
* @memberof WebGL */
|
|
5095
|
+
function glSetAntialias(antialias=true)
|
|
5096
|
+
{
|
|
5097
|
+
ASSERT(!glCanvas, 'must be called before engineInit');
|
|
5098
|
+
glAntialias = antialias;
|
|
5099
|
+
}
|
|
5100
|
+
|
|
5006
5101
|
/** Add a sprite to the gl draw list, used by all gl draw functions
|
|
5007
5102
|
* @param {Number} x
|
|
5008
5103
|
* @param {Number} y
|
|
@@ -5103,7 +5198,7 @@ const engineName = 'LittleJS';
|
|
|
5103
5198
|
* @type {String}
|
|
5104
5199
|
* @default
|
|
5105
5200
|
* @memberof Engine */
|
|
5106
|
-
const engineVersion = '1.
|
|
5201
|
+
const engineVersion = '1.10.4';
|
|
5107
5202
|
|
|
5108
5203
|
/** Frames per second to update
|
|
5109
5204
|
* @type {Number}
|
|
@@ -5147,7 +5242,6 @@ let timeReal = 0;
|
|
|
5147
5242
|
* @default false
|
|
5148
5243
|
* @memberof Engine */
|
|
5149
5244
|
let paused = false;
|
|
5150
|
-
|
|
5151
5245
|
/** Set if game is paused
|
|
5152
5246
|
* @param {Boolean} isPaused
|
|
5153
5247
|
* @memberof Engine */
|
|
@@ -5180,9 +5274,10 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
5180
5274
|
* @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
|
|
5181
5275
|
* @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
|
|
5182
5276
|
* @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
|
|
5183
|
-
* @param {Array} [imageSources=[
|
|
5277
|
+
* @param {Array} [imageSources=[]] - Image to load
|
|
5278
|
+
* @param {HTMLElement} [rootElement] - Root element to attach to, the document body by default
|
|
5184
5279
|
* @memberof Engine */
|
|
5185
|
-
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[
|
|
5280
|
+
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
5186
5281
|
{
|
|
5187
5282
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
5188
5283
|
|
|
@@ -5224,6 +5319,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5224
5319
|
for (const o of engineObjects)
|
|
5225
5320
|
o.parent || o.updateTransforms();
|
|
5226
5321
|
inputUpdate();
|
|
5322
|
+
pluginUpdateList.forEach(f=>f());
|
|
5227
5323
|
debugUpdate();
|
|
5228
5324
|
gameUpdatePost();
|
|
5229
5325
|
inputUpdatePost();
|
|
@@ -5339,16 +5435,21 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5339
5435
|
}
|
|
5340
5436
|
|
|
5341
5437
|
// setup html
|
|
5342
|
-
const
|
|
5438
|
+
const styleRoot =
|
|
5343
5439
|
'margin:0;overflow:hidden;' + // fill the window
|
|
5440
|
+
'width:100vw;height:100vh;' + // fill the window
|
|
5441
|
+
'display:flex;' + // use flexbox
|
|
5442
|
+
'align-items:center;' + // horizontal center
|
|
5443
|
+
(canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
|
|
5444
|
+
'justify-content:center;' + // vertical center
|
|
5344
5445
|
'background:#000;' + // set background color
|
|
5345
5446
|
'user-select:none;' + // prevent hold to select
|
|
5346
5447
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
5347
5448
|
(!touchInputEnable ? '' : // no touch css setttings
|
|
5348
5449
|
'touch-action:none;' + // prevent mobile pinch to resize
|
|
5349
5450
|
'-webkit-touch-callout:none');// compatibility for ios
|
|
5350
|
-
|
|
5351
|
-
|
|
5451
|
+
rootElement.style.cssText = styleRoot;
|
|
5452
|
+
rootElement.appendChild(mainCanvas = document.createElement('canvas'));
|
|
5352
5453
|
mainContext = mainCanvas.getContext('2d');
|
|
5353
5454
|
|
|
5354
5455
|
// init stuff and start engine
|
|
@@ -5358,13 +5459,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5358
5459
|
glInit();
|
|
5359
5460
|
|
|
5360
5461
|
// create overlay canvas for hud to appear above gl canvas
|
|
5361
|
-
|
|
5462
|
+
rootElement.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
5362
5463
|
overlayContext = overlayCanvas.getContext('2d');
|
|
5363
5464
|
|
|
5364
5465
|
// set canvas style
|
|
5365
|
-
const styleCanvas = 'position:absolute;
|
|
5366
|
-
|
|
5367
|
-
(glCanvas
|
|
5466
|
+
const styleCanvas = 'position:absolute'; // allow canvases to overlap
|
|
5467
|
+
mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
5468
|
+
if (glCanvas)
|
|
5469
|
+
glCanvas.style.cssText = styleCanvas;
|
|
5368
5470
|
updateCanvas();
|
|
5369
5471
|
|
|
5370
5472
|
// create promises for loading images
|
|
@@ -5381,19 +5483,32 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5381
5483
|
})
|
|
5382
5484
|
);
|
|
5383
5485
|
|
|
5384
|
-
|
|
5385
|
-
showSplashScreen && promises.push(new Promise(resolve =>
|
|
5486
|
+
if (!imageSources.length)
|
|
5386
5487
|
{
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
updateSplash();
|
|
5390
|
-
function updateSplash()
|
|
5488
|
+
// no images to load
|
|
5489
|
+
promises.push(new Promise(resolve =>
|
|
5391
5490
|
{
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5491
|
+
textureInfos[0] = new TextureInfo(new Image);
|
|
5492
|
+
resolve();
|
|
5493
|
+
}));
|
|
5494
|
+
}
|
|
5495
|
+
|
|
5496
|
+
if (showSplashScreen)
|
|
5497
|
+
{
|
|
5498
|
+
// draw splash screen
|
|
5499
|
+
promises.push(new Promise(resolve =>
|
|
5500
|
+
{
|
|
5501
|
+
let t = 0;
|
|
5502
|
+
console.log(`${engineName} Engine v${engineVersion}`);
|
|
5503
|
+
updateSplash();
|
|
5504
|
+
function updateSplash()
|
|
5505
|
+
{
|
|
5506
|
+
clearInput();
|
|
5507
|
+
drawEngineSplashScreen(t+=.01);
|
|
5508
|
+
t>1 ? resolve() : setTimeout(updateSplash, 16);
|
|
5509
|
+
}
|
|
5510
|
+
}));
|
|
5511
|
+
}
|
|
5397
5512
|
|
|
5398
5513
|
// load all of the images
|
|
5399
5514
|
Promise.all(promises).then(startEngine);
|
|
@@ -5665,7 +5780,7 @@ function drawEngineSplashScreen(t)
|
|
|
5665
5780
|
x.restore();
|
|
5666
5781
|
}
|
|
5667
5782
|
|
|
5668
|
-
/**
|
|
5783
|
+
/**
|
|
5669
5784
|
* LittleJS Module Export
|
|
5670
5785
|
* - Export engine as a module
|
|
5671
5786
|
*/
|
|
@@ -5687,8 +5802,9 @@ export {
|
|
|
5687
5802
|
engineObjectsUpdate,
|
|
5688
5803
|
engineObjectsDestroy,
|
|
5689
5804
|
engineObjectsCallback,
|
|
5805
|
+
engineObjectsRaycast,
|
|
5690
5806
|
engineAddPlugin,
|
|
5691
|
-
|
|
5807
|
+
|
|
5692
5808
|
// Globals
|
|
5693
5809
|
debug,
|
|
5694
5810
|
debugOverlay,
|
|
@@ -5807,6 +5923,7 @@ export {
|
|
|
5807
5923
|
smoothStep,
|
|
5808
5924
|
nearestPowerOfTwo,
|
|
5809
5925
|
isOverlapping,
|
|
5926
|
+
isIntersecting,
|
|
5810
5927
|
wave,
|
|
5811
5928
|
formatTime,
|
|
5812
5929
|
|
|
@@ -5826,6 +5943,20 @@ export {
|
|
|
5826
5943
|
vec2,
|
|
5827
5944
|
rgb,
|
|
5828
5945
|
hsl,
|
|
5946
|
+
isColor,
|
|
5947
|
+
|
|
5948
|
+
// Default Colors
|
|
5949
|
+
WHITE,
|
|
5950
|
+
BLACK,
|
|
5951
|
+
GRAY,
|
|
5952
|
+
RED,
|
|
5953
|
+
ORANGE,
|
|
5954
|
+
YELLOW,
|
|
5955
|
+
GREEN,
|
|
5956
|
+
CYAN,
|
|
5957
|
+
BLUE,
|
|
5958
|
+
PURPLE,
|
|
5959
|
+
MAGENTA,
|
|
5829
5960
|
|
|
5830
5961
|
// Draw
|
|
5831
5962
|
textureInfos,
|
|
@@ -5842,6 +5973,9 @@ export {
|
|
|
5842
5973
|
drawTile,
|
|
5843
5974
|
drawRect,
|
|
5844
5975
|
drawLine,
|
|
5976
|
+
drawPoly,
|
|
5977
|
+
drawEllipse,
|
|
5978
|
+
drawCircle,
|
|
5845
5979
|
drawCanvas2D,
|
|
5846
5980
|
setBlendMode,
|
|
5847
5981
|
drawTextScreen,
|
|
@@ -5862,6 +5996,17 @@ export {
|
|
|
5862
5996
|
glDraw,
|
|
5863
5997
|
glFlush,
|
|
5864
5998
|
glSetTexture,
|
|
5999
|
+
glSetAntialias,
|
|
6000
|
+
glAntialias,
|
|
6001
|
+
glShader,
|
|
6002
|
+
glActiveTexture,
|
|
6003
|
+
glArrayBuffer,
|
|
6004
|
+
glGeometryBuffer,
|
|
6005
|
+
glPositionData,
|
|
6006
|
+
glColorData,
|
|
6007
|
+
glInstanceCount,
|
|
6008
|
+
glAdditive,
|
|
6009
|
+
glBatchAdditive,
|
|
5865
6010
|
|
|
5866
6011
|
// Input
|
|
5867
6012
|
keyIsDown,
|