littlejsengine 1.10.4 → 1.11.1
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/LittleJS.zip +0 -0
- package/README.md +8 -78
- package/dist/littlejs.d.ts +60 -25
- package/dist/littlejs.esm.js +164 -63
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +160 -62
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +160 -62
- package/examples/box2d/game.js +15 -4
- package/examples/box2d/gameObjects.js +10 -9
- package/examples/box2d/index.html +5 -5
- package/examples/box2d/scenes.js +4 -4
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/game.js +3 -0
- package/examples/electron/index.html +2 -2
- package/examples/htmlMenu/index.html +3 -3
- package/examples/index.html +10 -3
- package/examples/js13k/game.js +3 -0
- package/examples/js13k/index.html +13 -13
- package/examples/module/game.js +4 -1
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +4 -1
- package/examples/platformer/game.js +19 -15
- package/examples/platformer/gameCharacter.js +3 -3
- package/examples/platformer/gameLevel.js +1 -0
- package/examples/platformer/index.html +8 -8
- package/examples/platformer/tiles.png +0 -0
- package/examples/puzzle/game.js +3 -2
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/game.js +47 -10
- package/examples/starter/index.html +13 -13
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +1 -1
- package/examples/typescript/game.js +2 -0
- package/examples/typescript/game.ts +3 -0
- package/examples/typescript/index.html +1 -1
- package/examples/uiSystem/game.js +23 -16
- package/examples/uiSystem/index.html +3 -14
- package/package.json +7 -2
- package/plugins/postProcess.js +2 -9
- package/plugins/uiSystem.js +85 -25
- package/reference.md +1 -1
- package/shortExamples/engine.html +71 -0
- package/shortExamples/index.html +47 -0
- package/shortExamples/index.js +0 -0
- package/shortExamples/tiles.png +0 -0
- package/src/engine.js +14 -12
- package/src/engineAudio.js +6 -9
- package/src/engineDraw.js +23 -7
- package/src/engineExport.js +4 -1
- package/src/engineInput.js +7 -3
- package/src/engineMedals.js +19 -5
- package/src/engineObject.js +8 -5
- package/src/engineSettings.js +13 -2
- package/src/engineTileLayer.js +9 -8
- package/src/engineUtilities.js +59 -10
- package/src/engineWebGL.js +1 -1
- package/examples/js13k/build/index.html +0 -1
- package/examples/js13k/build/index.js +0 -1
- package/examples/js13k/build/tiles.png +0 -0
- package/examples/js13k/game - Copy.zip +0 -0
- package/examples/js13k/game.zip +0 -0
- package/examples/starter/build/index.html +0 -2
- package/examples/starter/build/index.js +0 -1
- package/examples/starter/build/tiles.png +0 -0
- package/examples/starter/game.zip +0 -0
- package/examples/typescript/build/build/littlejs.esm.js +0 -4327
- package/examples/typescript/build/dist/littlejs.esm.js +0 -4425
- package/examples/typescript/build/examples/typescript/build.js +0 -24
- package/examples/typescript/build/examples/typescript/game.js +0 -100
- package/examples/typescript/build/examples/typescript/test/build/littlejs.esm.js +0 -3934
- package/examples/typescript/build/examples/typescript/test/examples/typescript/build.js +0 -86
- package/examples/typescript/build/examples/typescript/test/examples/typescript/game.js +0 -92
package/dist/littlejs.esm.js
CHANGED
|
@@ -671,7 +671,8 @@ function formatTime(t) { return (t/60|0) + ':' + (t%60<10?'0':'') + (t%60|0); }
|
|
|
671
671
|
* @memberof Random */
|
|
672
672
|
function rand(valueA=1, valueB=0) { return valueB + Math.random() * (valueA-valueB); }
|
|
673
673
|
|
|
674
|
-
/** Returns a floored random value the two values passed in
|
|
674
|
+
/** Returns a floored random value between the two values passed in
|
|
675
|
+
* The upper bound is exclusive. (If 2 is passed in, result will be 0 or 1)
|
|
675
676
|
* @param {Number} valueA
|
|
676
677
|
* @param {Number} [valueB]
|
|
677
678
|
* @return {Number}
|
|
@@ -800,18 +801,24 @@ class Vector2
|
|
|
800
801
|
* @param {Number} [y] - Y axis location */
|
|
801
802
|
constructor(x=0, y=0)
|
|
802
803
|
{
|
|
803
|
-
ASSERT(typeof x == 'number' && typeof y == 'number');
|
|
804
804
|
/** @property {Number} - X axis location */
|
|
805
805
|
this.x = x;
|
|
806
806
|
/** @property {Number} - Y axis location */
|
|
807
807
|
this.y = y;
|
|
808
|
+
ASSERT(this.isValid());
|
|
808
809
|
}
|
|
809
810
|
|
|
810
811
|
/** Sets values of this vector and returns self
|
|
811
812
|
* @param {Number} [x] - X axis location
|
|
812
813
|
* @param {Number} [y] - Y axis location
|
|
813
814
|
* @return {Vector2} */
|
|
814
|
-
set(x=0, y=0)
|
|
815
|
+
set(x=0, y=0)
|
|
816
|
+
{
|
|
817
|
+
this.x = x;
|
|
818
|
+
this.y = y;
|
|
819
|
+
ASSERT(this.isValid());
|
|
820
|
+
return this;
|
|
821
|
+
}
|
|
815
822
|
|
|
816
823
|
/** Returns a new vector that is a copy of this
|
|
817
824
|
* @return {Vector2} */
|
|
@@ -1003,6 +1010,14 @@ class Vector2
|
|
|
1003
1010
|
if (debug)
|
|
1004
1011
|
return `(${(this.x<0?'':' ') + this.x.toFixed(digits)},${(this.y<0?'':' ') + this.y.toFixed(digits)} )`;
|
|
1005
1012
|
}
|
|
1013
|
+
|
|
1014
|
+
/** Checks if this is a valid vector
|
|
1015
|
+
* @return {Boolean} */
|
|
1016
|
+
isValid()
|
|
1017
|
+
{
|
|
1018
|
+
return typeof this.x == 'number' && !isNaN(this.x)
|
|
1019
|
+
&& typeof this.y == 'number' && !isNaN(this.y);
|
|
1020
|
+
}
|
|
1006
1021
|
}
|
|
1007
1022
|
|
|
1008
1023
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1063,6 +1078,7 @@ class Color
|
|
|
1063
1078
|
this.b = b;
|
|
1064
1079
|
/** @property {Number} - Alpha */
|
|
1065
1080
|
this.a = a;
|
|
1081
|
+
ASSERT(this.isValid());
|
|
1066
1082
|
}
|
|
1067
1083
|
|
|
1068
1084
|
/** Sets values of this color and returns self
|
|
@@ -1072,7 +1088,14 @@ class Color
|
|
|
1072
1088
|
* @param {Number} [a] - alpha
|
|
1073
1089
|
* @return {Color} */
|
|
1074
1090
|
set(r=1, g=1, b=1, a=1)
|
|
1075
|
-
{
|
|
1091
|
+
{
|
|
1092
|
+
this.r = r;
|
|
1093
|
+
this.g = g;
|
|
1094
|
+
this.b = b;
|
|
1095
|
+
this.a = a;
|
|
1096
|
+
ASSERT(this.isValid());
|
|
1097
|
+
return this;
|
|
1098
|
+
}
|
|
1076
1099
|
|
|
1077
1100
|
/** Returns a new color that is a copy of this
|
|
1078
1101
|
* @return {Color} */
|
|
@@ -1155,6 +1178,7 @@ class Color
|
|
|
1155
1178
|
this.g = f(p, q, h);
|
|
1156
1179
|
this.b = f(p, q, h - 1/3);
|
|
1157
1180
|
this.a = a;
|
|
1181
|
+
ASSERT(this.isValid());
|
|
1158
1182
|
return this;
|
|
1159
1183
|
}
|
|
1160
1184
|
|
|
@@ -1182,7 +1206,6 @@ class Color
|
|
|
1182
1206
|
else if (b == max)
|
|
1183
1207
|
h = (r - g) / d + 4;
|
|
1184
1208
|
}
|
|
1185
|
-
|
|
1186
1209
|
return [h / 6, s, l, a];
|
|
1187
1210
|
}
|
|
1188
1211
|
|
|
@@ -1215,11 +1238,27 @@ class Color
|
|
|
1215
1238
|
* @return {Color} */
|
|
1216
1239
|
setHex(hex)
|
|
1217
1240
|
{
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1241
|
+
ASSERT(typeof hex == 'string' && hex[0] == '#');
|
|
1242
|
+
ASSERT([4,5,7,9].includes(hex.length), 'Invalid hex');
|
|
1243
|
+
|
|
1244
|
+
if (hex.length < 6)
|
|
1245
|
+
{
|
|
1246
|
+
const fromHex = (c)=> clamp(parseInt(hex[c],16)/15);
|
|
1247
|
+
this.r = fromHex(1);
|
|
1248
|
+
this.g = fromHex(2),
|
|
1249
|
+
this.b = fromHex(3);
|
|
1250
|
+
this.a = hex.length == 5 ? fromHex(4) : 1;
|
|
1251
|
+
}
|
|
1252
|
+
else
|
|
1253
|
+
{
|
|
1254
|
+
const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
|
|
1255
|
+
this.r = fromHex(1);
|
|
1256
|
+
this.g = fromHex(3),
|
|
1257
|
+
this.b = fromHex(5);
|
|
1258
|
+
this.a = hex.length == 9 ? fromHex(7) : 1;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
ASSERT(this.isValid());
|
|
1223
1262
|
return this;
|
|
1224
1263
|
}
|
|
1225
1264
|
|
|
@@ -1233,6 +1272,16 @@ class Color
|
|
|
1233
1272
|
const a = clamp(this.a)*255<<24;
|
|
1234
1273
|
return r + g + b + a;
|
|
1235
1274
|
}
|
|
1275
|
+
|
|
1276
|
+
/** Checks if this is a valid color
|
|
1277
|
+
* @return {Boolean} */
|
|
1278
|
+
isValid()
|
|
1279
|
+
{
|
|
1280
|
+
return typeof this.r == 'number' && !isNaN(this.r)
|
|
1281
|
+
&& typeof this.g == 'number' && !isNaN(this.g)
|
|
1282
|
+
&& typeof this.b == 'number' && !isNaN(this.b)
|
|
1283
|
+
&& typeof this.a == 'number' && !isNaN(this.a);
|
|
1284
|
+
}
|
|
1236
1285
|
}
|
|
1237
1286
|
|
|
1238
1287
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1384,12 +1433,18 @@ let canvasMaxSize = vec2(1920, 1080);
|
|
|
1384
1433
|
* @memberof Settings */
|
|
1385
1434
|
let canvasFixedSize = vec2();
|
|
1386
1435
|
|
|
1387
|
-
/**
|
|
1436
|
+
/** Use nearest neighbor scaling algorithm for canvas for more pixelated look
|
|
1388
1437
|
* @type {Boolean}
|
|
1389
1438
|
* @default
|
|
1390
1439
|
* @memberof Settings */
|
|
1391
1440
|
let canvasPixelated = true;
|
|
1392
1441
|
|
|
1442
|
+
/** Disables texture filtering for crisper pixel art
|
|
1443
|
+
* @type {Boolean}
|
|
1444
|
+
* @default
|
|
1445
|
+
* @memberof Settings */
|
|
1446
|
+
let tilesPixelated = true;
|
|
1447
|
+
|
|
1393
1448
|
/** Default font used for text rendering
|
|
1394
1449
|
* @type {String}
|
|
1395
1450
|
* @default
|
|
@@ -1638,11 +1693,16 @@ function setCanvasMaxSize(size) { canvasMaxSize = size; }
|
|
|
1638
1693
|
* @memberof Settings */
|
|
1639
1694
|
function setCanvasFixedSize(size) { canvasFixedSize = size; }
|
|
1640
1695
|
|
|
1641
|
-
/**
|
|
1696
|
+
/** Use nearest neighbor scaling algorithm for canvas for more pixelated look
|
|
1642
1697
|
* @param {Boolean} pixelated
|
|
1643
1698
|
* @memberof Settings */
|
|
1644
1699
|
function setCanvasPixelated(pixelated) { canvasPixelated = pixelated; }
|
|
1645
1700
|
|
|
1701
|
+
/** Disables texture filtering for crisper pixel art
|
|
1702
|
+
* @param {Boolean} pixelated
|
|
1703
|
+
* @memberof Settings */
|
|
1704
|
+
function setTilesPixelated(pixelated) { tilesPixelated = pixelated; }
|
|
1705
|
+
|
|
1646
1706
|
/** Set default font used for text rendering
|
|
1647
1707
|
* @param {String} font
|
|
1648
1708
|
* @memberof Settings */
|
|
@@ -1868,7 +1928,7 @@ class EngineObject
|
|
|
1868
1928
|
* @param {Color} [color=(1,1,1,1)] - Color to apply to tile when rendered
|
|
1869
1929
|
* @param {Number} [renderOrder] - Objects sorted by renderOrder before being rendered
|
|
1870
1930
|
*/
|
|
1871
|
-
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color, renderOrder=0)
|
|
1931
|
+
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color=new Color, renderOrder=0)
|
|
1872
1932
|
{
|
|
1873
1933
|
// set passed in params
|
|
1874
1934
|
ASSERT(isVector2(pos) && isVector2(size), 'ensure pos and size are vec2s');
|
|
@@ -1982,15 +2042,18 @@ class EngineObject
|
|
|
1982
2042
|
|
|
1983
2043
|
// apply physics
|
|
1984
2044
|
const oldPos = this.pos.copy();
|
|
1985
|
-
this.
|
|
1986
|
-
this.
|
|
1987
|
-
|
|
2045
|
+
this.velocity.x *= this.damping;
|
|
2046
|
+
this.velocity.y *= this.damping;
|
|
2047
|
+
if (this.mass) // dont apply gravity to static objects
|
|
2048
|
+
this.velocity.y += gravity * this.gravityScale;
|
|
2049
|
+
this.pos.x += this.velocity.x;
|
|
2050
|
+
this.pos.y += this.velocity.y;
|
|
1988
2051
|
this.angle += this.angleVelocity *= this.angleDamping;
|
|
1989
2052
|
|
|
1990
2053
|
// physics sanity checks
|
|
1991
2054
|
ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
|
|
1992
2055
|
ASSERT(this.damping >= 0 && this.damping <= 1);
|
|
1993
|
-
if (!enablePhysicsSolver || !this.mass) // dont do collision for
|
|
2056
|
+
if (!enablePhysicsSolver || !this.mass) // dont do collision for static objects
|
|
1994
2057
|
return;
|
|
1995
2058
|
|
|
1996
2059
|
const wasMovingDown = this.velocity.y < 0;
|
|
@@ -2351,7 +2414,7 @@ let drawCount;
|
|
|
2351
2414
|
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
2352
2415
|
* tile(5, 8) // a tile at index 5 using a tile size of 8
|
|
2353
2416
|
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
2354
|
-
* tile(vec2(4,8), vec2(30,10)) // a tile at
|
|
2417
|
+
* tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
|
|
2355
2418
|
* @memberof Draw
|
|
2356
2419
|
*/
|
|
2357
2420
|
function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
@@ -2696,6 +2759,24 @@ function setBlendMode(additive, useWebGL=glEnable, context)
|
|
|
2696
2759
|
}
|
|
2697
2760
|
}
|
|
2698
2761
|
|
|
2762
|
+
/** Draw text on main canvas in world space
|
|
2763
|
+
* Automatically splits new lines into rows
|
|
2764
|
+
* @param {String} text
|
|
2765
|
+
* @param {Vector2} pos
|
|
2766
|
+
* @param {Number} [size]
|
|
2767
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
2768
|
+
* @param {Number} [lineWidth]
|
|
2769
|
+
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2770
|
+
* @param {CanvasTextAlign} [textAlign='center']
|
|
2771
|
+
* @param {String} [font=fontDefault]
|
|
2772
|
+
* @param {Number} [maxWidth]
|
|
2773
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=mainContext]
|
|
2774
|
+
* @memberof Draw */
|
|
2775
|
+
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, maxWidth, context=mainContext)
|
|
2776
|
+
{
|
|
2777
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, maxWidth, context);
|
|
2778
|
+
}
|
|
2779
|
+
|
|
2699
2780
|
/** Draw text on overlay canvas in world space
|
|
2700
2781
|
* Automatically splits new lines into rows
|
|
2701
2782
|
* @param {String} text
|
|
@@ -2706,12 +2787,11 @@ function setBlendMode(additive, useWebGL=glEnable, context)
|
|
|
2706
2787
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2707
2788
|
* @param {CanvasTextAlign} [textAlign='center']
|
|
2708
2789
|
* @param {String} [font=fontDefault]
|
|
2709
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2710
2790
|
* @param {Number} [maxWidth]
|
|
2711
2791
|
* @memberof Draw */
|
|
2712
|
-
function
|
|
2792
|
+
function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, maxWidth)
|
|
2713
2793
|
{
|
|
2714
|
-
|
|
2794
|
+
drawText(text, pos, size, color, lineWidth, lineColor, textAlign, font, maxWidth, overlayContext);
|
|
2715
2795
|
}
|
|
2716
2796
|
|
|
2717
2797
|
/** Draw text on overlay canvas in screen space
|
|
@@ -2724,10 +2804,10 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
2724
2804
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2725
2805
|
* @param {CanvasTextAlign} [textAlign]
|
|
2726
2806
|
* @param {String} [font=fontDefault]
|
|
2727
|
-
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2728
2807
|
* @param {Number} [maxWidth]
|
|
2808
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
2729
2809
|
* @memberof Draw */
|
|
2730
|
-
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault,
|
|
2810
|
+
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, maxWidth=undefined, context=overlayContext)
|
|
2731
2811
|
{
|
|
2732
2812
|
context.fillStyle = color.toString();
|
|
2733
2813
|
context.lineWidth = lineWidth;
|
|
@@ -2803,7 +2883,6 @@ class FontImage
|
|
|
2803
2883
|
{
|
|
2804
2884
|
const context = this.context;
|
|
2805
2885
|
context.save();
|
|
2806
|
-
context.imageSmoothingEnabled = !canvasPixelated;
|
|
2807
2886
|
|
|
2808
2887
|
const size = this.tileSize;
|
|
2809
2888
|
const drawSize = size.add(this.paddingSize).scale(scale);
|
|
@@ -2900,7 +2979,7 @@ function keyWasReleased(key, device=0)
|
|
|
2900
2979
|
|
|
2901
2980
|
/** Clears all input
|
|
2902
2981
|
* @memberof Input */
|
|
2903
|
-
function clearInput() { inputData = [[]]; }
|
|
2982
|
+
function clearInput() { inputData = [[]]; touchGamepadButtons = []; }
|
|
2904
2983
|
|
|
2905
2984
|
/** Returns true if mouse button is down
|
|
2906
2985
|
* @function
|
|
@@ -3065,6 +3144,7 @@ function inputInit()
|
|
|
3065
3144
|
onmousemove = (e)=> mousePosScreen = mouseToScreen(e);
|
|
3066
3145
|
onwheel = (e)=> mouseWheel = e.ctrlKey ? 0 : sign(e.deltaY);
|
|
3067
3146
|
oncontextmenu = (e)=> false; // prevent right click menu
|
|
3147
|
+
onblur = (e) => clearInput(); // reset input when focus is lost
|
|
3068
3148
|
|
|
3069
3149
|
// init touch input
|
|
3070
3150
|
if (isTouchDevice && touchInputEnable)
|
|
@@ -3263,10 +3343,13 @@ function touchInputInit()
|
|
|
3263
3343
|
if (touching)
|
|
3264
3344
|
{
|
|
3265
3345
|
touchGamepadTimer.set();
|
|
3266
|
-
if (paused)
|
|
3346
|
+
if (paused && !wasTouching)
|
|
3267
3347
|
{
|
|
3268
3348
|
// touch anywhere to press start when paused
|
|
3269
3349
|
touchGamepadButtons[9] = 1;
|
|
3350
|
+
|
|
3351
|
+
// call default touch handler so normal touch events still work
|
|
3352
|
+
handleTouchDefault(e);
|
|
3270
3353
|
return;
|
|
3271
3354
|
}
|
|
3272
3355
|
}
|
|
@@ -3291,7 +3374,7 @@ function touchInputInit()
|
|
|
3291
3374
|
const button = touchPos.subtract(buttonCenter).direction();
|
|
3292
3375
|
touchGamepadButtons[button] = 1;
|
|
3293
3376
|
}
|
|
3294
|
-
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
3377
|
+
else if (touchPos.distance(startCenter) < touchGamepadSize && !wasTouching)
|
|
3295
3378
|
{
|
|
3296
3379
|
// virtual start button in center
|
|
3297
3380
|
touchGamepadButtons[9] = 1;
|
|
@@ -3379,7 +3462,7 @@ function touchGamepadRender()
|
|
|
3379
3462
|
/** Audio context used by the engine
|
|
3380
3463
|
* @type {AudioContext}
|
|
3381
3464
|
* @memberof Audio */
|
|
3382
|
-
let audioContext;
|
|
3465
|
+
let audioContext = new AudioContext;
|
|
3383
3466
|
|
|
3384
3467
|
/** Master gain node for all audio to pass through
|
|
3385
3468
|
* @type {GainNode}
|
|
@@ -3390,14 +3473,10 @@ function audioInit()
|
|
|
3390
3473
|
{
|
|
3391
3474
|
if (!soundEnable || headlessMode) return;
|
|
3392
3475
|
|
|
3393
|
-
// create audio context
|
|
3394
|
-
audioContext = new AudioContext;
|
|
3395
|
-
|
|
3396
|
-
// create and connect gain node
|
|
3397
3476
|
// (createGain is more widely spported then GainNode construtor)
|
|
3398
3477
|
audioGainNode = audioContext.createGain();
|
|
3399
3478
|
audioGainNode.connect(audioContext.destination);
|
|
3400
|
-
|
|
3479
|
+
audioGainNode.gain.value = soundVolume; // set starting value
|
|
3401
3480
|
}
|
|
3402
3481
|
|
|
3403
3482
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -3437,7 +3516,7 @@ class Sound
|
|
|
3437
3516
|
{
|
|
3438
3517
|
// generate zzfx sound now for fast playback
|
|
3439
3518
|
const defaultRandomness = .05;
|
|
3440
|
-
this.randomness = zzfxSound[1]
|
|
3519
|
+
this.randomness = zzfxSound[1] != undefined ? zzfxSound[1] : defaultRandomness;
|
|
3441
3520
|
zzfxSound[1] = 0; // generate without randomness
|
|
3442
3521
|
this.sampleChannels = [zzfxG(...zzfxSound)];
|
|
3443
3522
|
this.sampleRate = zzfxR;
|
|
@@ -3479,10 +3558,11 @@ class Sound
|
|
|
3479
3558
|
// play the sound
|
|
3480
3559
|
const playbackRate = pitch + pitch * this.randomness*randomnessScale*rand(-1,1);
|
|
3481
3560
|
this.gainNode = audioContext.createGain();
|
|
3482
|
-
|
|
3561
|
+
this.source = playSamples(this.sampleChannels, volume, playbackRate, pan, loop, this.sampleRate, this.gainNode);
|
|
3562
|
+
return this.source;
|
|
3483
3563
|
}
|
|
3484
3564
|
|
|
3485
|
-
/** Set the sound volume
|
|
3565
|
+
/** Set the sound volume of the most recently played instance of this sound
|
|
3486
3566
|
* @param {Number} [volume] - How much to scale volume by
|
|
3487
3567
|
*/
|
|
3488
3568
|
setVolume(volume=1)
|
|
@@ -3973,18 +4053,18 @@ function zzfxM(instruments, patterns, sequence, BPM = 125)
|
|
|
3973
4053
|
|
|
3974
4054
|
|
|
3975
4055
|
|
|
3976
|
-
/** The tile collision layer
|
|
4056
|
+
/** The tile collision layer grid, use setTileCollisionData and getTileCollisionData to access
|
|
3977
4057
|
* @type {Array}
|
|
3978
4058
|
* @memberof TileCollision */
|
|
3979
4059
|
let tileCollision = [];
|
|
3980
4060
|
|
|
3981
|
-
/** Size of the tile collision layer
|
|
4061
|
+
/** Size of the tile collision layer 2d grid
|
|
3982
4062
|
* @type {Vector2}
|
|
3983
4063
|
* @memberof TileCollision */
|
|
3984
4064
|
let tileCollisionSize = vec2();
|
|
3985
4065
|
|
|
3986
4066
|
/** Clear and initialize tile collision
|
|
3987
|
-
* @param {Vector2} size
|
|
4067
|
+
* @param {Vector2} size - width and height of tile collision 2d grid
|
|
3988
4068
|
* @memberof TileCollision */
|
|
3989
4069
|
function initTileCollision(size)
|
|
3990
4070
|
{
|
|
@@ -3994,7 +4074,7 @@ function initTileCollision(size)
|
|
|
3994
4074
|
tileCollision[i] = 0;
|
|
3995
4075
|
}
|
|
3996
4076
|
|
|
3997
|
-
/** Set tile collision data
|
|
4077
|
+
/** Set tile collision data for a given cell in the grid
|
|
3998
4078
|
* @param {Vector2} pos
|
|
3999
4079
|
* @param {Number} [data]
|
|
4000
4080
|
* @memberof TileCollision */
|
|
@@ -4003,7 +4083,7 @@ function setTileCollisionData(pos, data=0)
|
|
|
4003
4083
|
pos.arrayCheck(tileCollisionSize) && (tileCollision[(pos.y|0)*tileCollisionSize.x+pos.x|0] = data);
|
|
4004
4084
|
}
|
|
4005
4085
|
|
|
4006
|
-
/** Get tile collision data
|
|
4086
|
+
/** Get tile collision data for a given cell in the grid
|
|
4007
4087
|
* @param {Vector2} pos
|
|
4008
4088
|
* @return {Number}
|
|
4009
4089
|
* @memberof TileCollision */
|
|
@@ -4034,7 +4114,8 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
4034
4114
|
return false;
|
|
4035
4115
|
}
|
|
4036
4116
|
|
|
4037
|
-
/** Return the center of first tile hit
|
|
4117
|
+
/** Return the center of first tile hit, undefined if nothing was hit.
|
|
4118
|
+
* This does not return the exact intersection, but the center of the tile hit.
|
|
4038
4119
|
* @param {Vector2} posStart
|
|
4039
4120
|
* @param {Vector2} posEnd
|
|
4040
4121
|
* @param {EngineObject} [object]
|
|
@@ -4242,7 +4323,7 @@ class TileLayer extends EngineObject
|
|
|
4242
4323
|
}
|
|
4243
4324
|
|
|
4244
4325
|
// disable smoothing for pixel art
|
|
4245
|
-
this.context.imageSmoothingEnabled = !
|
|
4326
|
+
this.context.imageSmoothingEnabled = !tilesPixelated;
|
|
4246
4327
|
|
|
4247
4328
|
// setup gl rendering if enabled
|
|
4248
4329
|
glPreRender();
|
|
@@ -4279,8 +4360,8 @@ class TileLayer extends EngineObject
|
|
|
4279
4360
|
const d = this.getData(layerPos);
|
|
4280
4361
|
if (d.tile != undefined)
|
|
4281
4362
|
{
|
|
4282
|
-
const pos = this.pos.add(layerPos).add(vec2(.5));
|
|
4283
4363
|
ASSERT(mainContext == this.context, 'must call redrawStart() before drawing tiles');
|
|
4364
|
+
const pos = layerPos.add(vec2(.5));
|
|
4284
4365
|
const tileInfo = tile(d.tile, s, this.tileInfo.textureIndex);
|
|
4285
4366
|
drawTile(pos, vec2(1), tileInfo, d.color, d.direction*PI/2, d.mirror);
|
|
4286
4367
|
}
|
|
@@ -4709,7 +4790,7 @@ function medalsInit(saveName)
|
|
|
4709
4790
|
// check if medals are unlocked
|
|
4710
4791
|
medalsSaveName = saveName;
|
|
4711
4792
|
if (!debugMedals)
|
|
4712
|
-
medalsForEach(medal=> medal.unlocked =
|
|
4793
|
+
medalsForEach(medal=> medal.unlocked = !!localStorage[medal.storageKey()]);
|
|
4713
4794
|
|
|
4714
4795
|
// engine automatically renders medals
|
|
4715
4796
|
engineAddPlugin(undefined, medalsRender);
|
|
@@ -4772,14 +4853,28 @@ class Medal
|
|
|
4772
4853
|
constructor(id, name, description='', icon='🏆', src)
|
|
4773
4854
|
{
|
|
4774
4855
|
ASSERT(id >= 0 && !medals[id]);
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4856
|
+
|
|
4857
|
+
/** @property {Number} - The unique identifier of the medal */
|
|
4858
|
+
this.id = id;
|
|
4859
|
+
|
|
4860
|
+
/** @property {String} - Name of the medal */
|
|
4778
4861
|
this.name = name;
|
|
4862
|
+
|
|
4863
|
+
/** @property {String} - Description of the medal */
|
|
4779
4864
|
this.description = description;
|
|
4865
|
+
|
|
4866
|
+
/** @property {String} - Icon for the medal */
|
|
4780
4867
|
this.icon = icon;
|
|
4868
|
+
|
|
4869
|
+
/** @property {Boolean} - Is the medal unlocked? */
|
|
4870
|
+
this.unlocked = false;
|
|
4871
|
+
|
|
4872
|
+
// load the source image if provided
|
|
4781
4873
|
if (src)
|
|
4782
4874
|
(this.image = new Image).src = src;
|
|
4875
|
+
|
|
4876
|
+
// add this to list of medals
|
|
4877
|
+
medals[id] = this;
|
|
4783
4878
|
}
|
|
4784
4879
|
|
|
4785
4880
|
/** Unlocks a medal if not already unlocked */
|
|
@@ -4790,7 +4885,7 @@ class Medal
|
|
|
4790
4885
|
|
|
4791
4886
|
// save the medal
|
|
4792
4887
|
ASSERT(medalsSaveName, 'save name must be set');
|
|
4793
|
-
localStorage[this.storageKey()] = this.unlocked =
|
|
4888
|
+
localStorage[this.storageKey()] = this.unlocked = true;
|
|
4794
4889
|
medalsDisplayQueue.push(this);
|
|
4795
4890
|
}
|
|
4796
4891
|
|
|
@@ -5049,7 +5144,7 @@ function glCreateTexture(image)
|
|
|
5049
5144
|
}
|
|
5050
5145
|
|
|
5051
5146
|
// use point filtering for pixelated rendering
|
|
5052
|
-
const filter =
|
|
5147
|
+
const filter = tilesPixelated ? gl_NEAREST : gl_LINEAR;
|
|
5053
5148
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
|
|
5054
5149
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
|
|
5055
5150
|
return texture;
|
|
@@ -5198,7 +5293,7 @@ const engineName = 'LittleJS';
|
|
|
5198
5293
|
* @type {String}
|
|
5199
5294
|
* @default
|
|
5200
5295
|
* @memberof Engine */
|
|
5201
|
-
const engineVersion = '1.
|
|
5296
|
+
const engineVersion = '1.11.1';
|
|
5202
5297
|
|
|
5203
5298
|
/** Frames per second to update
|
|
5204
5299
|
* @type {Number}
|
|
@@ -5261,6 +5356,8 @@ const pluginUpdateList = [], pluginRenderList = [];
|
|
|
5261
5356
|
* @memberof Engine */
|
|
5262
5357
|
function engineAddPlugin(updateFunction, renderFunction)
|
|
5263
5358
|
{
|
|
5359
|
+
ASSERT(!pluginUpdateList.includes(updateFunction));
|
|
5360
|
+
ASSERT(!pluginRenderList.includes(renderFunction));
|
|
5264
5361
|
updateFunction && pluginUpdateList.push(updateFunction);
|
|
5265
5362
|
renderFunction && pluginRenderList.push(renderFunction);
|
|
5266
5363
|
}
|
|
@@ -5269,12 +5366,12 @@ function engineAddPlugin(updateFunction, renderFunction)
|
|
|
5269
5366
|
// Main engine functions
|
|
5270
5367
|
|
|
5271
5368
|
/** Startup LittleJS engine with your callback functions
|
|
5272
|
-
* @param {Function} gameInit
|
|
5273
|
-
* @param {Function} gameUpdate
|
|
5274
|
-
* @param {Function} gameUpdatePost - Called after physics and objects are updated,
|
|
5275
|
-
* @param {Function} gameRender
|
|
5276
|
-
* @param {Function} gameRenderPost - Called after objects are rendered,
|
|
5277
|
-
* @param {Array} [imageSources=[]] -
|
|
5369
|
+
* @param {Function|function():Promise} gameInit - Called once after the engine starts up
|
|
5370
|
+
* @param {Function} gameUpdate - Called every frame before objects are updated
|
|
5371
|
+
* @param {Function} gameUpdatePost - Called after physics and objects are updated, even when paused
|
|
5372
|
+
* @param {Function} gameRender - Called before objects are rendered, for drawing the background
|
|
5373
|
+
* @param {Function} gameRenderPost - Called after objects are rendered, useful for drawing UI
|
|
5374
|
+
* @param {Array} [imageSources=[]] - List of images to load
|
|
5278
5375
|
* @param {HTMLElement} [rootElement] - Root element to attach to, the document body by default
|
|
5279
5376
|
* @memberof Engine */
|
|
5280
5377
|
function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=[], rootElement=document.body)
|
|
@@ -5288,7 +5385,8 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5288
5385
|
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
5289
5386
|
|
|
5290
5387
|
// disable smoothing for pixel art
|
|
5291
|
-
|
|
5388
|
+
overlayContext.imageSmoothingEnabled =
|
|
5389
|
+
mainContext.imageSmoothingEnabled = !tilesPixelated;
|
|
5292
5390
|
|
|
5293
5391
|
// setup gl rendering if enabled
|
|
5294
5392
|
glPreRender();
|
|
@@ -5424,8 +5522,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5424
5522
|
|
|
5425
5523
|
function startEngine()
|
|
5426
5524
|
{
|
|
5427
|
-
gameInit();
|
|
5428
|
-
engineUpdate();
|
|
5525
|
+
new Promise((resolve) => resolve(gameInit())).then(engineUpdate);
|
|
5429
5526
|
}
|
|
5430
5527
|
|
|
5431
5528
|
if (headlessMode)
|
|
@@ -5440,9 +5537,9 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5440
5537
|
'width:100vw;height:100vh;' + // fill the window
|
|
5441
5538
|
'display:flex;' + // use flexbox
|
|
5442
5539
|
'align-items:center;' + // horizontal center
|
|
5443
|
-
(canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
|
|
5444
5540
|
'justify-content:center;' + // vertical center
|
|
5445
5541
|
'background:#000;' + // set background color
|
|
5542
|
+
(canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
|
|
5446
5543
|
'user-select:none;' + // prevent hold to select
|
|
5447
5544
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
5448
5545
|
(!touchInputEnable ? '' : // no touch css setttings
|
|
@@ -5778,7 +5875,8 @@ function drawEngineSplashScreen(t)
|
|
|
5778
5875
|
}
|
|
5779
5876
|
|
|
5780
5877
|
x.restore();
|
|
5781
|
-
}
|
|
5878
|
+
}
|
|
5879
|
+
|
|
5782
5880
|
|
|
5783
5881
|
/**
|
|
5784
5882
|
* LittleJS Module Export
|
|
@@ -5830,6 +5928,7 @@ export {
|
|
|
5830
5928
|
canvasMaxSize,
|
|
5831
5929
|
canvasFixedSize,
|
|
5832
5930
|
canvasPixelated,
|
|
5931
|
+
tilesPixelated,
|
|
5833
5932
|
fontDefault,
|
|
5834
5933
|
showSplashScreen,
|
|
5835
5934
|
headlessMode,
|
|
@@ -5869,6 +5968,7 @@ export {
|
|
|
5869
5968
|
setCanvasMaxSize,
|
|
5870
5969
|
setCanvasFixedSize,
|
|
5871
5970
|
setCanvasPixelated,
|
|
5971
|
+
setTilesPixelated,
|
|
5872
5972
|
setFontDefault,
|
|
5873
5973
|
setShowSplashScreen,
|
|
5874
5974
|
setHeadlessMode,
|
|
@@ -5978,8 +6078,9 @@ export {
|
|
|
5978
6078
|
drawCircle,
|
|
5979
6079
|
drawCanvas2D,
|
|
5980
6080
|
setBlendMode,
|
|
5981
|
-
drawTextScreen,
|
|
5982
6081
|
drawText,
|
|
6082
|
+
drawTextOverlay,
|
|
6083
|
+
drawTextScreen,
|
|
5983
6084
|
engineFontImage,
|
|
5984
6085
|
FontImage,
|
|
5985
6086
|
isFullscreen,
|