littlejsengine 1.5.2 → 1.6.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 +155 -33
- package/{engine/index.d.ts → build/littlejs.d.ts} +14 -6
- package/{engine/engine.all.module.js → build/littlejs.esm.js} +110 -99
- package/build/littlejs.esm.min.js +1 -0
- package/{engine/engine.all.js → build/littlejs.js} +102 -97
- package/build/littlejs.min.js +1 -0
- package/{engine/engine.all.release.js → build/littlejs.release.js} +95 -95
- package/examples/breakout/game.js +5 -0
- package/examples/breakout/gameObjects.js +41 -48
- package/examples/breakout/index.html +5 -4
- package/examples/breakoutTutorial/README.md +514 -0
- package/examples/breakoutTutorial/game.js +181 -0
- package/examples/breakoutTutorial/images/1.png +0 -0
- package/examples/breakoutTutorial/images/10.png +0 -0
- package/examples/breakoutTutorial/images/11.png +0 -0
- package/examples/breakoutTutorial/images/2.png +0 -0
- package/examples/breakoutTutorial/images/3.png +0 -0
- package/examples/breakoutTutorial/images/4.png +0 -0
- package/examples/breakoutTutorial/images/5.png +0 -0
- package/examples/breakoutTutorial/images/6.png +0 -0
- package/examples/breakoutTutorial/images/7.png +0 -0
- package/examples/breakoutTutorial/images/8.png +0 -0
- package/examples/breakoutTutorial/images/9.png +0 -0
- package/examples/breakoutTutorial/index.html +10 -0
- package/examples/electron/build.bat +52 -0
- package/{electron → examples/electron}/electron.js +18 -21
- package/{game.js → examples/electron/game.js} +1 -1
- package/examples/electron/index.html +2 -0
- package/examples/electron/package.json +20 -0
- package/examples/empty/game.js +11 -1
- package/examples/empty/index.html +2 -2
- package/examples/module/game.js +1 -1
- package/examples/module/index.html +3 -2
- package/examples/particles/index.html +3 -2
- package/examples/platformer/gameLevel.js +1 -1
- package/examples/platformer/gamePlayer.js +1 -1
- package/examples/platformer/index.html +8 -7
- package/examples/puzzle/index.html +4 -3
- package/{build.bat → examples/starter/build.bat} +17 -17
- package/examples/starter/game.js +111 -0
- package/examples/starter/index.html +27 -0
- package/examples/starter/tiles.png +0 -0
- package/examples/stress/index.html +3 -2
- package/examples/typescript/game.js +89 -89
- package/examples/typescript/game.ts +11 -11
- package/examples/typescript/index.html +3 -2
- package/package.json +4 -4
- package/{engine → src}/engine.js +1 -2
- package/{engine → src}/engineAudio.js +11 -11
- package/src/engineBuild.bat +132 -0
- package/{engine → src}/engineDebug.js +8 -2
- package/{engine → src}/engineDraw.js +19 -15
- package/{engine → src}/engineExport.js +8 -2
- package/{engine → src}/engineInput.js +54 -58
- package/{engine → src}/engineMedals.js +1 -1
- package/{engine → src}/engineObject.js +4 -4
- package/{engine → src}/engineRelease.js +1 -0
- package/{engine → src}/engineUtilities.js +4 -4
- package/electron/electronBuild.bat +0 -32
- package/electron/electronSetup.bat +0 -2
- package/electron/package.json +0 -21
- package/engine/engine.all.min.js +0 -1
- package/engine/engine.all.module.min.js +0 -1
- package/engine/engineBuild.bat +0 -127
- package/index.html +0 -26
- /package/{tiles.png → examples/electron/tiles.png} +0 -0
- /package/{favicon.png → examples/favicon.png} +0 -0
- /package/{engine → src}/engineFont.png +0 -0
- /package/{engine → src}/engineParticles.js +0 -0
- /package/{engine → src}/engineSettings.js +0 -0
- /package/{engine → src}/engineTileLayer.js +0 -0
- /package/{engine → src}/engineWebGL.js +0 -0
|
@@ -45,6 +45,12 @@ let showWatermark = 1;
|
|
|
45
45
|
* @memberof Debug */
|
|
46
46
|
let godMode = 0;
|
|
47
47
|
|
|
48
|
+
/** Key code used to toggle debug mode, Esc by default
|
|
49
|
+
* @type {Boolean}
|
|
50
|
+
* @default
|
|
51
|
+
* @memberof Debug */
|
|
52
|
+
let debugKey = 27;
|
|
53
|
+
|
|
48
54
|
// Engine internal variables not exposed to documentation
|
|
49
55
|
let debugPrimitives = [], debugOverlay = 0, debugPhysics = 0, debugRaycast = 0,
|
|
50
56
|
debugParticles = 0, debugGamepads = 0, debugMedals = 0, debugTakeScreenshot, downloadLink;
|
|
@@ -166,7 +172,7 @@ const debugUpdate = ()=>
|
|
|
166
172
|
if (!debug)
|
|
167
173
|
return;
|
|
168
174
|
|
|
169
|
-
if (keyWasPressed(
|
|
175
|
+
if (keyWasPressed(debugKey)) // Esc
|
|
170
176
|
debugOverlay = !debugOverlay;
|
|
171
177
|
if (debugOverlay)
|
|
172
178
|
{
|
|
@@ -351,7 +357,7 @@ const debugRender = ()=>
|
|
|
351
357
|
overlayContext.fillText('Time: ' + formatTime(time), x, y += h);
|
|
352
358
|
overlayContext.fillText('---------', x, y += h);
|
|
353
359
|
overlayContext.fillStyle = '#f00';
|
|
354
|
-
overlayContext.fillText('
|
|
360
|
+
overlayContext.fillText('ESC: Debug Overlay', x, y += h);
|
|
355
361
|
overlayContext.fillStyle = debugPhysics ? '#f00' : '#fff';
|
|
356
362
|
overlayContext.fillText('1: Debug Physics', x, y += h);
|
|
357
363
|
overlayContext.fillStyle = debugParticles ? '#f00' : '#fff';
|
|
@@ -741,7 +747,7 @@ class Vector2
|
|
|
741
747
|
* @return {Color}
|
|
742
748
|
* @memberof Utilities
|
|
743
749
|
*/
|
|
744
|
-
const
|
|
750
|
+
const rgb = (r, g, b, a)=> new Color(r, g, b, a);
|
|
745
751
|
|
|
746
752
|
/**
|
|
747
753
|
* Create a color object with HSLA values
|
|
@@ -752,7 +758,7 @@ const colorRGBA = (r, g, b, a)=> new Color(r, g, b, a);
|
|
|
752
758
|
* @return {Color}
|
|
753
759
|
* @memberof Utilities
|
|
754
760
|
*/
|
|
755
|
-
const
|
|
761
|
+
const hsl = (h, s, l, a)=> new Color().setHSLA(h, s, l, a);
|
|
756
762
|
|
|
757
763
|
/**
|
|
758
764
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
@@ -760,8 +766,8 @@ const colorHSLA = (h, s, l, a)=> new Color().setHSLA(h, s, l, a);
|
|
|
760
766
|
* let a = new Color; // white
|
|
761
767
|
* let b = new Color(1, 0, 0); // red
|
|
762
768
|
* let c = new Color(0, 0, 0, 0); // transparent black
|
|
763
|
-
* let d =
|
|
764
|
-
* let e =
|
|
769
|
+
* let d = RGB(0, 0, 1); // blue using rgb color
|
|
770
|
+
* let e = HSL(.3, 1, .5); // green using hsl color
|
|
765
771
|
*/
|
|
766
772
|
class Color
|
|
767
773
|
{
|
|
@@ -1336,6 +1342,7 @@ class EngineObject
|
|
|
1336
1342
|
this.velocity.y += gravity * this.gravityScale;
|
|
1337
1343
|
this.pos.x += this.velocity.x *= this.damping;
|
|
1338
1344
|
this.pos.y += this.velocity.y *= this.damping;
|
|
1345
|
+
this.angle += this.angleVelocity *= this.angleDamping;
|
|
1339
1346
|
|
|
1340
1347
|
// physics sanity checks
|
|
1341
1348
|
ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
|
|
@@ -1392,6 +1399,7 @@ class EngineObject
|
|
|
1392
1399
|
const smallStepUp = (oldPos.y - o.pos.y)*2 > sizeBoth.y + gravity; // prefer to push up if small delta
|
|
1393
1400
|
const isBlockedX = abs(oldPos.y - o.pos.y)*2 < sizeBoth.y;
|
|
1394
1401
|
const isBlockedY = abs(oldPos.x - o.pos.x)*2 < sizeBoth.x;
|
|
1402
|
+
const elasticity = max(this.elasticity, o.elasticity);
|
|
1395
1403
|
|
|
1396
1404
|
if (smallStepUp | isBlockedY | !isBlockedX) // resolve y collision
|
|
1397
1405
|
{
|
|
@@ -1404,7 +1412,7 @@ class EngineObject
|
|
|
1404
1412
|
this.groundObject = o;
|
|
1405
1413
|
|
|
1406
1414
|
// bounce if other object is fixed or grounded
|
|
1407
|
-
this.velocity.y *= -
|
|
1415
|
+
this.velocity.y *= -elasticity;
|
|
1408
1416
|
}
|
|
1409
1417
|
else if (o.mass)
|
|
1410
1418
|
{
|
|
@@ -1418,7 +1426,6 @@ class EngineObject
|
|
|
1418
1426
|
+ this.velocity.y * 2 * this.mass / (this.mass + o.mass);
|
|
1419
1427
|
|
|
1420
1428
|
// lerp betwen elastic or inelastic based on elasticity
|
|
1421
|
-
const elasticity = max(this.elasticity, o.elasticity);
|
|
1422
1429
|
this.velocity.y = lerp(elasticity, inelastic, elastic0);
|
|
1423
1430
|
o.velocity.y = lerp(elasticity, inelastic, elastic1);
|
|
1424
1431
|
}
|
|
@@ -1439,12 +1446,11 @@ class EngineObject
|
|
|
1439
1446
|
+ this.velocity.x * 2 * this.mass / (this.mass + o.mass);
|
|
1440
1447
|
|
|
1441
1448
|
// lerp betwen elastic or inelastic based on elasticity
|
|
1442
|
-
const elasticity = max(this.elasticity, o.elasticity);
|
|
1443
1449
|
this.velocity.x = lerp(elasticity, inelastic, elastic0);
|
|
1444
1450
|
o.velocity.x = lerp(elasticity, inelastic, elastic1);
|
|
1445
1451
|
}
|
|
1446
1452
|
else // bounce if other object is fixed
|
|
1447
|
-
this.velocity.x *= -
|
|
1453
|
+
this.velocity.x *= -elasticity;
|
|
1448
1454
|
}
|
|
1449
1455
|
debugOverlay && debugPhysics && debugAABB(this.pos, this.size, o.pos, o.size, '#f0f');
|
|
1450
1456
|
}
|
|
@@ -1826,6 +1832,23 @@ function setBlendMode(additive, useWebGL=glEnable)
|
|
|
1826
1832
|
mainContext.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
1827
1833
|
}
|
|
1828
1834
|
|
|
1835
|
+
/** Draw text on overlay canvas in world space
|
|
1836
|
+
* Automatically splits new lines into rows
|
|
1837
|
+
* @param {String} text
|
|
1838
|
+
* @param {Vector2} pos
|
|
1839
|
+
* @param {Number} [size=1]
|
|
1840
|
+
* @param {Color} [color=Color()]
|
|
1841
|
+
* @param {Number} [lineWidth=0]
|
|
1842
|
+
* @param {Color} [lineColor=Color(0,0,0)]
|
|
1843
|
+
* @param {String} [textAlign='center']
|
|
1844
|
+
* @param {String} [font=fontDefault]
|
|
1845
|
+
* @param {CanvasRenderingContext2D} [context=overlayContext]
|
|
1846
|
+
* @memberof Draw */
|
|
1847
|
+
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, context)
|
|
1848
|
+
{
|
|
1849
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, context);
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1829
1852
|
/** Draw text on overlay canvas in screen space
|
|
1830
1853
|
* Automatically splits new lines into rows
|
|
1831
1854
|
* @param {String} text
|
|
@@ -1835,6 +1858,8 @@ function setBlendMode(additive, useWebGL=glEnable)
|
|
|
1835
1858
|
* @param {Number} [lineWidth=0]
|
|
1836
1859
|
* @param {Color} [lineColor=Color(0,0,0)]
|
|
1837
1860
|
* @param {String} [textAlign='center']
|
|
1861
|
+
* @param {String} [font=fontDefault]
|
|
1862
|
+
* @param {CanvasRenderingContext2D} [context=overlayContext]
|
|
1838
1863
|
* @memberof Draw */
|
|
1839
1864
|
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, context=overlayContext)
|
|
1840
1865
|
{
|
|
@@ -1855,21 +1880,6 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
1855
1880
|
});
|
|
1856
1881
|
}
|
|
1857
1882
|
|
|
1858
|
-
/** Draw text on overlay canvas in world space
|
|
1859
|
-
* Automatically splits new lines into rows
|
|
1860
|
-
* @param {String} text
|
|
1861
|
-
* @param {Vector2} pos
|
|
1862
|
-
* @param {Number} [size=1]
|
|
1863
|
-
* @param {Color} [color=Color()]
|
|
1864
|
-
* @param {Number} [lineWidth=0]
|
|
1865
|
-
* @param {Color} [lineColor=Color(0,0,0)]
|
|
1866
|
-
* @param {String} [textAlign='center']
|
|
1867
|
-
* @memberof Draw */
|
|
1868
|
-
function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font)
|
|
1869
|
-
{
|
|
1870
|
-
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, mainContext);
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
1883
|
///////////////////////////////////////////////////////////////////////////////
|
|
1874
1884
|
|
|
1875
1885
|
let engineFontImage;
|
|
@@ -2123,15 +2133,15 @@ function inputUpdatePost()
|
|
|
2123
2133
|
onkeydown = (e)=>
|
|
2124
2134
|
{
|
|
2125
2135
|
if (debug && e.target != document.body) return;
|
|
2126
|
-
e.repeat || (inputData[isUsingGamepad = 0][
|
|
2136
|
+
e.repeat || (inputData[isUsingGamepad = 0][remapKey(e.which)] = 3);
|
|
2127
2137
|
preventDefaultInput && e.preventDefault();
|
|
2128
2138
|
}
|
|
2129
2139
|
onkeyup = (e)=>
|
|
2130
2140
|
{
|
|
2131
2141
|
if (debug && e.target != document.body) return;
|
|
2132
|
-
inputData[0][
|
|
2142
|
+
inputData[0][remapKey(e.which)] = 4;
|
|
2133
2143
|
}
|
|
2134
|
-
const
|
|
2144
|
+
const remapKey = (c)=> inputWASDEmulateDirection ? c==87?38 : c==83?40 : c==65?37 : c==68?39 : c : c;
|
|
2135
2145
|
|
|
2136
2146
|
///////////////////////////////////////////////////////////////////////////////
|
|
2137
2147
|
// Mouse event handlers
|
|
@@ -2273,6 +2283,9 @@ if (isTouchDevice)
|
|
|
2273
2283
|
return true;
|
|
2274
2284
|
}
|
|
2275
2285
|
|
|
2286
|
+
// try to create touch game pad
|
|
2287
|
+
touchGamepadEnable && touchGamepadCreate();
|
|
2288
|
+
|
|
2276
2289
|
return ontouchstart(e);
|
|
2277
2290
|
}
|
|
2278
2291
|
}
|
|
@@ -2286,76 +2299,69 @@ let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
|
|
|
2286
2299
|
// create the touch gamepad, called automatically by the engine
|
|
2287
2300
|
function touchGamepadCreate()
|
|
2288
2301
|
{
|
|
2289
|
-
if (!touchGamepadEnable || !isTouchDevice)
|
|
2290
|
-
return;
|
|
2291
|
-
|
|
2292
2302
|
// touch input internal variables
|
|
2293
2303
|
touchGamepadButtons = [];
|
|
2294
2304
|
touchGamepadStick = vec2();
|
|
2295
2305
|
|
|
2296
|
-
|
|
2297
|
-
ontouchstart = (e)=>
|
|
2306
|
+
let touchHandler = ontouchstart;
|
|
2307
|
+
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2298
2308
|
{
|
|
2299
|
-
//
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2309
|
+
// clear touch gamepad input
|
|
2310
|
+
touchGamepadStick = vec2();
|
|
2311
|
+
touchGamepadButtons = [];
|
|
2312
|
+
|
|
2313
|
+
const touching = e.touches.length;
|
|
2314
|
+
if (touching)
|
|
2303
2315
|
{
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
touchGamepadButtons = [];
|
|
2307
|
-
|
|
2308
|
-
const touching = e.touches.length;
|
|
2309
|
-
if (touching)
|
|
2316
|
+
touchGamepadTimer.set();
|
|
2317
|
+
if (paused)
|
|
2310
2318
|
{
|
|
2311
|
-
//
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
if (paused)
|
|
2316
|
-
{
|
|
2317
|
-
// touch anywhere to press start when paused
|
|
2318
|
-
touchGamepadButtons[9] = 1;
|
|
2319
|
-
return;
|
|
2320
|
-
}
|
|
2319
|
+
// touch anywhere to press start when paused
|
|
2320
|
+
touchGamepadButtons[9] = 1;
|
|
2321
|
+
return;
|
|
2321
2322
|
}
|
|
2323
|
+
}
|
|
2322
2324
|
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2325
|
+
// get center of left and right sides
|
|
2326
|
+
const stickCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
2327
|
+
const buttonCenter = mainCanvasSize.subtract(vec2(touchGamepadSize, touchGamepadSize));
|
|
2328
|
+
const startCenter = mainCanvasSize.scale(.5);
|
|
2327
2329
|
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
+
// check each touch point
|
|
2331
|
+
for (const touch of e.touches)
|
|
2332
|
+
{
|
|
2333
|
+
const touchPos = mouseToScreen(vec2(touch.clientX, touch.clientY));
|
|
2334
|
+
if (touchPos.distance(stickCenter) < touchGamepadSize)
|
|
2330
2335
|
{
|
|
2331
|
-
|
|
2332
|
-
if (
|
|
2336
|
+
// virtual analog stick
|
|
2337
|
+
if (touchGamepadAnalog)
|
|
2338
|
+
touchGamepadStick = touchPos.subtract(stickCenter).scale(2/touchGamepadSize).clampLength();
|
|
2339
|
+
else
|
|
2333
2340
|
{
|
|
2334
|
-
//
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
else
|
|
2338
|
-
{
|
|
2339
|
-
// 8 way dpad
|
|
2340
|
-
const angle = touchPos.subtract(stickCenter).angle();
|
|
2341
|
-
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
2342
|
-
}
|
|
2343
|
-
}
|
|
2344
|
-
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
2345
|
-
{
|
|
2346
|
-
// virtual face buttons
|
|
2347
|
-
const button = touchPos.subtract(buttonCenter).direction();
|
|
2348
|
-
touchGamepadButtons[button] = 1;
|
|
2349
|
-
}
|
|
2350
|
-
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
2351
|
-
{
|
|
2352
|
-
// virtual start button in center
|
|
2353
|
-
touchGamepadButtons[9] = 1;
|
|
2341
|
+
// 8 way dpad
|
|
2342
|
+
const angle = touchPos.subtract(stickCenter).angle();
|
|
2343
|
+
touchGamepadStick.setAngle((angle * 4 / PI + 8.5 | 0) * PI / 4);
|
|
2354
2344
|
}
|
|
2355
2345
|
}
|
|
2346
|
+
else if (touchPos.distance(buttonCenter) < touchGamepadSize)
|
|
2347
|
+
{
|
|
2348
|
+
// virtual face buttons
|
|
2349
|
+
const button = touchPos.subtract(buttonCenter).direction();
|
|
2350
|
+
touchGamepadButtons[button] = 1;
|
|
2351
|
+
}
|
|
2352
|
+
else if (touchPos.distance(startCenter) < touchGamepadSize)
|
|
2353
|
+
{
|
|
2354
|
+
// virtual start button in center
|
|
2355
|
+
touchGamepadButtons[9] = 1;
|
|
2356
|
+
}
|
|
2356
2357
|
}
|
|
2357
2358
|
|
|
2358
|
-
|
|
2359
|
+
// call default touch handler and set to using gamepad
|
|
2360
|
+
touchHandler(e);
|
|
2361
|
+
isUsingGamepad = 1;
|
|
2362
|
+
|
|
2363
|
+
// must return true so the document will get focus
|
|
2364
|
+
return true;
|
|
2359
2365
|
}
|
|
2360
2366
|
}
|
|
2361
2367
|
|
|
@@ -2381,7 +2387,7 @@ function touchGamepadRender()
|
|
|
2381
2387
|
overlayContext.beginPath();
|
|
2382
2388
|
|
|
2383
2389
|
const leftCenter = vec2(touchGamepadSize, mainCanvasSize.y-touchGamepadSize);
|
|
2384
|
-
if (touchGamepadAnalog)
|
|
2390
|
+
if (touchGamepadAnalog) // draw circle shaped gamepad
|
|
2385
2391
|
{
|
|
2386
2392
|
overlayContext.arc(leftCenter.x, leftCenter.y, touchGamepadSize/2, 0, 9);
|
|
2387
2393
|
overlayContext.fill();
|
|
@@ -2686,7 +2692,7 @@ function playSamples(sampleChannels, volume=1, rate=1, pan=0, loop=0)
|
|
|
2686
2692
|
}
|
|
2687
2693
|
|
|
2688
2694
|
///////////////////////////////////////////////////////////////////////////////
|
|
2689
|
-
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.
|
|
2695
|
+
// ZzFXMicro - Zuper Zmall Zound Zynth - v1.2.0 by Frank Force
|
|
2690
2696
|
|
|
2691
2697
|
/** Generate and play a ZzFX sound
|
|
2692
2698
|
* <br>
|
|
@@ -2712,11 +2718,11 @@ function zzfxG
|
|
|
2712
2718
|
bitCrush = 0, delay = 0, sustainVolume = 1, decay = 0, tremolo = 0
|
|
2713
2719
|
)
|
|
2714
2720
|
{
|
|
2715
|
-
//
|
|
2721
|
+
// locals
|
|
2716
2722
|
let PI2 = PI*2, startSlide = slide *= 500 * PI2 / zzfxR / zzfxR, b=[],
|
|
2717
2723
|
startFrequency = frequency *= (1 + randomness*rand(-1,1)) * PI2 / zzfxR,
|
|
2718
|
-
t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length
|
|
2719
|
-
|
|
2724
|
+
t=0, tm=0, i=0, j=1, r=0, c=0, s=0, f, length
|
|
2725
|
+
|
|
2720
2726
|
// scale by sample rate
|
|
2721
2727
|
attack = attack * zzfxR + 9; // minimum attack to prevent pop
|
|
2722
2728
|
decay *= zzfxR;
|
|
@@ -2766,18 +2772,18 @@ function zzfxG
|
|
|
2766
2772
|
Math.cos(modulation*tm++); // modulation
|
|
2767
2773
|
t += f - f*noise*(1 - (Math.sin(i)+1)*1e9%2); // noise
|
|
2768
2774
|
|
|
2769
|
-
if (j && ++j > pitchJumpTime)
|
|
2775
|
+
if (j && ++j > pitchJumpTime) // pitch jump
|
|
2770
2776
|
{
|
|
2771
|
-
frequency += pitchJump;
|
|
2772
|
-
startFrequency += pitchJump;
|
|
2773
|
-
j = 0;
|
|
2777
|
+
frequency += pitchJump; // apply pitch jump
|
|
2778
|
+
startFrequency += pitchJump; // also apply to start
|
|
2779
|
+
j = 0; // reset pitch jump time
|
|
2774
2780
|
}
|
|
2775
2781
|
|
|
2776
2782
|
if (repeatTime && !(++r % repeatTime)) // repeat
|
|
2777
2783
|
{
|
|
2778
|
-
frequency = startFrequency;
|
|
2779
|
-
slide = startSlide;
|
|
2780
|
-
j
|
|
2784
|
+
frequency = startFrequency; // reset frequency
|
|
2785
|
+
slide = startSlide; // reset slide
|
|
2786
|
+
j ||= 1; // reset pitch jump time
|
|
2781
2787
|
}
|
|
2782
2788
|
}
|
|
2783
2789
|
|
|
@@ -3545,7 +3551,7 @@ class Particle extends EngineObject
|
|
|
3545
3551
|
* LittleJS Medal System
|
|
3546
3552
|
* <br> - Tracks and displays medals
|
|
3547
3553
|
* <br> - Saves medals to local storage
|
|
3548
|
-
* <br> - Newgrounds
|
|
3554
|
+
* <br> - Newgrounds integration
|
|
3549
3555
|
* @namespace Medals
|
|
3550
3556
|
*/
|
|
3551
3557
|
|
|
@@ -4269,7 +4275,7 @@ const engineName = 'LittleJS';
|
|
|
4269
4275
|
* @type {String}
|
|
4270
4276
|
* @default
|
|
4271
4277
|
* @memberof Engine */
|
|
4272
|
-
const engineVersion = '1.
|
|
4278
|
+
const engineVersion = '1.6.4';
|
|
4273
4279
|
|
|
4274
4280
|
/** Frames per second to update objects
|
|
4275
4281
|
* @type {Number}
|
|
@@ -4360,7 +4366,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4360
4366
|
(glCanvas||mainCanvas).style = mainCanvas.style = overlayCanvas.style = styleCanvas;
|
|
4361
4367
|
|
|
4362
4368
|
gameInit();
|
|
4363
|
-
touchGamepadCreate();
|
|
4364
4369
|
engineUpdate();
|
|
4365
4370
|
};
|
|
4366
4371
|
|
|
@@ -4756,6 +4761,11 @@ const setShowWatermark = (show)=> showWatermark = show;
|
|
|
4756
4761
|
* @memberof Debug */
|
|
4757
4762
|
const setGodMode = (enable)=> godMode = enable;
|
|
4758
4763
|
|
|
4764
|
+
/** Set key code used to toggle debug mode, Esc by default
|
|
4765
|
+
* @param {Number} key
|
|
4766
|
+
* @memberof Debug */
|
|
4767
|
+
const setDebugKey = (key)=> debugKey = key;
|
|
4768
|
+
|
|
4759
4769
|
export {
|
|
4760
4770
|
// Setters for global variables
|
|
4761
4771
|
setCameraPos,
|
|
@@ -4796,6 +4806,7 @@ export {
|
|
|
4796
4806
|
setMedalsPreventUnlock,
|
|
4797
4807
|
setShowWatermark,
|
|
4798
4808
|
setGodMode,
|
|
4809
|
+
setDebugKey,
|
|
4799
4810
|
|
|
4800
4811
|
// Settings
|
|
4801
4812
|
canvasMaxSize,
|
|
@@ -4882,8 +4893,8 @@ export {
|
|
|
4882
4893
|
Color,
|
|
4883
4894
|
Timer,
|
|
4884
4895
|
vec2,
|
|
4885
|
-
|
|
4886
|
-
|
|
4896
|
+
rgb,
|
|
4897
|
+
hsl,
|
|
4887
4898
|
|
|
4888
4899
|
// Base
|
|
4889
4900
|
EngineObject,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
let showWatermark=0,godMode=0,debugKeyCode=0;const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0,ASSERT=()=>{},debugInit=()=>{},debugUpdate=()=>{},debugRender=()=>{},debugRect=()=>{},debugCircle=()=>{},debugPoint=()=>{},debugLine=()=>{},debugAABB=()=>{},debugText=()=>{},debugClear=()=>{},debugSaveCanvas=()=>{};"use strict";const PI=Math.PI,abs=a=>0>a?-a:a,min=(a,b)=>a<b?a:b,max=(a,b)=>a>b?a:b,sign=a=>0>a?-1:1,mod=(a,b=1)=>(a%b+b)%b,clamp=(a,b=0,c=1)=>a<b?b:a>c?c:a,percent=(a,b=0,c=1)=>c-b?clamp((a-b)/(c-b)):0,lerp=(a,b=0,c=1)=>b+clamp(a)*(c-b),smoothStep=a=>a*a*(3-2*a),nearestPowerOfTwo=a=>2**Math.ceil(Math.log2(a)),isOverlapping=(a,b,c,d)=>2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y,wave=(a=1,b=1,c=time)=>b/2*(1-Math.cos(c*a*2*PI)),formatTime=a=>(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0),rand=(a=1,b=0)=>b+(a-b)*Math.random(),randInt=(a=1,b=0)=>rand(a,b)|0,randSign=()=>2*randInt(2)-1,randInCircle=(a=1,b=0)=>0<a?randVector(a*rand(b/a,1)**.5):new Vector2,randVector=(a=1)=>(new Vector2).setAngle(rand(2*PI),a),randColor=(a=new Color,b=new Color(0,0,0,1),c)=>c?a.lerp(b,rand()):new Color(rand(a.r,b.r),rand(a.g,b.g),rand(a.b,b.b),rand(a.a,b.a));let randSeed=1;const setRandSeed=a=>randSeed=a,randSeeded=(a=1,b=0)=>{randSeed^=randSeed<<13;randSeed^=randSeed>>>17;randSeed^=randSeed<<5;return b+(a-b)*abs(randSeed%1e9)/1e9},vec2=(a=0,b)=>void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y),isVector2=a=>!isNaN(a.x)&&!isNaN(a.y);class Vector2{constructor(a=0,b=0){this.x=a;this.y=b}copy(){return new Vector2(this.x,this.y)}add(a){ASSERT(isVector2(a));return new Vector2(this.x+a.x,this.y+a.y)}subtract(a){ASSERT(isVector2(a));return new Vector2(this.x-a.x,this.y-a.y)}multiply(a){ASSERT(isVector2(a));return new Vector2(this.x*a.x,this.y*a.y)}divide(a){ASSERT(isVector2(a));return new Vector2(this.x/a.x,this.y/a.y)}scale(a){ASSERT(!isVector2(a));return new Vector2(this.x*a,this.y*a)}length(){return this.lengthSquared()**.5}lengthSquared(){return this.x**2+this.y**2}distance(a){return this.distanceSquared(a)**.5}distanceSquared(a){return(this.x-a.x)**2+(this.y-a.y)**2}normalize(a=1){const b=this.length();return b?this.scale(a/b):new Vector2(0,a)}clampLength(a=1){const b=this.length();return b>a?this.scale(a/b):this}dot(a){ASSERT(isVector2(a));return this.x*a.x+this.y*a.y}cross(a){ASSERT(isVector2(a));return this.x*a.y-this.y*a.x}angle(){return Math.atan2(this.x,this.y)}setAngle(a=0,b=1){this.x=b*Math.sin(a);this.y=b*Math.cos(a);return this}rotate(a){const b=Math.cos(a);a=Math.sin(a);return new Vector2(this.x*b-this.y*a,this.x*a+this.y*b)}direction(){return abs(this.x)>abs(this.y)?0>this.x?3:1:0>this.y?2:0}invert(){return new Vector2(this.y,-this.x)}floor(){return new Vector2(Math.floor(this.x),Math.floor(this.y))}area(){return abs(this.x*this.y)}lerp(a,b){ASSERT(isVector2(a));return this.add(a.subtract(this).scale(clamp(b)))}arrayCheck(a){return 0<=this.x&&0<=this.y&&this.x<a.x&&this.y<a.y}toString(a=3){if(debug)return`(${(0>this.x?"":" ")+this.x.toFixed(a)},${(0>this.y?"":" ")+this.y.toFixed(a)} )`}}const rgb=(a,b,c,d)=>new Color(a,b,c,d),hsl=(a,b,c,d)=>(new Color).setHSLA(a,b,c,d);class Color{constructor(a=1,b=1,c=1,d=1){this.r=a;this.g=b;this.b=c;this.a=d}copy(){return new Color(this.r,this.g,this.b,this.a)}add(a){return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){return new Color(this.r/a.r,this.g/a.g,this.b/a.b,this.a/a.a)}scale(a,b=a){return new Color(this.r*a,this.g*a,this.b*a,this.a*b)}clamp(){return new Color(clamp(this.r),clamp(this.g),clamp(this.b),clamp(this.a))}lerp(a,b){return this.add(a.subtract(this).scale(clamp(b)))}setHSLA(a=0,b=0,c=1,d=1){b=.5>c?c*(1+b):c+b-c*b;c=2*c-b;const e=(f,h,k)=>(k=(k%1+1)%1)<1/6?f+6*(h-f)*k:.5>k?h:k<2/3?f+(h-f)*(2/3-k)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}getHSLA(){const a=clamp(this.r),b=clamp(this.g),c=clamp(this.b),d=clamp(this.a),e=Math.max(a,b,c),f=Math.min(a,b,c),h=(e+f)/2;let k=0,g=0;if(e!=f){let l=e-f;g=.5<h?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,g,h,d]}mutate(a=.05,b=0){return new Color(this.r+rand(a,-a),this.g+rand(a,-a),this.b+rand(a,-a),this.a+rand(b,-b)).clamp()}toString(a=1){const b=c=>(16>(c=255*c|0)?"0":"")+c.toString(16);return"#"+b(this.r)+b(this.g)+b(this.b)+(a?b(this.a):"")}setHex(a){this.r=clamp(parseInt(a.slice(1,3),16)/255);this.g=clamp(parseInt(a.slice(3,5),16)/255);this.b=clamp(parseInt(a.slice(5,7),16)/255);this.a=7<a.length?clamp(parseInt(a.slice(7,9),16)/255):1;return this}rgbaInt(){const a=255*clamp(this.r)|0,b=(255*clamp(this.g)|0)<<8,c=(255*clamp(this.b)|0)<<16,d=(255*clamp(this.a)|0)<<24;return a+b+c+d}}class Timer{constructor(a){this.time=void 0==a?void 0:time+a;this.setTime=a}set(a=0){this.time=time+a;this.setTime=a}unset(){this.time=void 0}isSet(){return void 0!=this.time}active(){return time<=this.time}elapsed(){return time>this.time}get(){return this.isSet()?time-this.time:0}getPercent(){return this.isSet()?percent(this.time-time,this.setTime,0):0}toString(){if(debug)return this.unset()?"unset":Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after")}valueOf(){return this.get()}}"use strict";let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),cavasPixelated=1,fontDefault="arial",glEnable=1,glOverlay=1,tileSizeDefault=vec2(16),tileFixBleedScale=.3,enablePhysicsSolver=1,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=1,gamepadDirectionEmulateStick=1,inputWASDEmulateDirection=1,touchGamepadEnable=0,touchGamepadAnalog=1,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=1,soundEnable=1,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock;"use strict";const engineName="LittleJS",engineVersion="1.6.4",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0;function setPaused(a){paused=a}function engineInit(a,b,c,d,e,f){function h(m=0){var n=m-k;k=m;if(debug||showWatermark)l=lerp(.05,l,1e3/(n||1));m=debug&&keyIsDown(107);const p=debug&&keyIsDown(109);debug&&(n*=m?5:p?.2:1);timeReal+=n/1e3;g+=!paused*n;m||(g=min(g,50));canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,n=innerWidth/innerHeight,m=mainCanvas.width/mainCanvas.height,(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=n<m?"100%":"",(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=n<m?"":"100%"):(mainCanvas.width=min(innerWidth,canvasMaxSize.x),mainCanvas.height=min(innerHeight,canvasMaxSize.y));overlayCanvas.width=mainCanvas.width;overlayCanvas.height=mainCanvas.height;mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{n=0;0>g&&-9<g&&(n=g,g=0);for(;0<=g;g-=1e3/frameRate)inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();g+=n}enginePreRender();d();engineObjects.sort((r,w)=>r.renderOrder-w.renderOrder);for(var q of engineObjects)q.destroyed||q.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",q=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+l.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(q,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(q,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(h)}tileImage.onerror=tileImage.onload=()=>{tileImageFixBleed=vec2(tileFixBleedScale).divide(tileImageSize=vec2(tileImage.width,tileImage.height));debug&&(tileImage.onload=()=>ASSERT(1));document.body.style="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none";document.body.appendChild(mainCanvas=document.createElement("canvas"));mainContext=mainCanvas.getContext("2d");debugInit();glEnable&&glInit();document.body.appendChild(overlayCanvas=document.createElement("canvas"));overlayContext=overlayCanvas.getContext("2d");(glCanvas||mainCanvas).style=mainCanvas.style=overlayCanvas.style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";a();h()};let k=0,g,l;f?tileImage.src=f:tileImage.onload()}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!cavasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);const a=b=>{if(!b.destroyed){b.update();for(const c of b.children)a(c)}};for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed);time=++frame/frameRate}function engineObjectsDestroy(){for(const a of engineObjects)a.parent||a.destroy();engineObjects=engineObjects.filter(a=>!a.destroyed)}function engineObjectsCallback(a,b,c,d=engineObjects){if(a)if(void 0!=b.x)for(const e of d)isOverlapping(a,b,e.pos,e.size)&&c(e);else{b*=b;for(const e of d)a.distanceSquared(e.pos)<b&&c(e)}else for(const e of d)c(e)}"use strict";class EngineObject{constructor(a=vec2(),b=vec2(1),c=-1,d=tileSizeDefault,e=0,f,h=0){ASSERT(isVector2(a)&&isVector2(b));this.pos=a.copy();this.size=b;this.drawSize;this.tileIndex=c;this.tileSize=d;this.angle=e;this.color=f;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=h;this.velocity=new Vector2;this.angleVelocity=0;this.spawnTime=time;this.children=[];this.collideTiles=1;engineObjects.push(this)}update(){var a=this.parent;if(a)this.pos=this.localPos.multiply(vec2(a.getMirrorSign(),1)).rotate(-a.angle).add(a.pos),this.angle=a.getMirrorSign()*this.localAngle+a.angle;else if(this.velocity.x=clamp(this.velocity.x,-objectMaxSpeed,objectMaxSpeed),this.velocity.y=clamp(this.velocity.y,-objectMaxSpeed,objectMaxSpeed),a=this.pos.copy(),this.velocity.y+=gravity*this.gravityScale,this.pos.x+=this.velocity.x*=this.damping,this.pos.y+=this.velocity.y*=this.damping,this.angle+=this.angleVelocity*=this.angleDamping,ASSERT(0<=this.angleDamping&&1>=this.angleDamping),ASSERT(0<=this.damping&&1>=this.damping),enablePhysicsSolver&&this.mass){var b=0>this.velocity.y;if(this.groundObject){var c=this.groundObject.velocity?this.groundObject.velocity.x:0;this.velocity.x=c+(this.velocity.x-c)*this.friction;this.groundObject=0}if(this.collideSolidObjects)for(var d of engineObjectsCollide){if(!this.isSolid&!d.isSolid||d.destroyed||d.parent||d==this)continue;if(!isOverlapping(this.pos,this.size,d.pos,d.size))continue;if(!this.collideWithObject(d)|!d.collideWithObject(this))continue;if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);var e=c.length();c=.01>e?randVector(.001):c.scale(.001/e);this.velocity=this.velocity.add(c);d.mass&&(d.velocity=d.velocity.subtract(c));debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f00");continue}e=this.size.add(d.size);var f=2*(a.y-d.pos.y)>e.y+gravity;const k=2*abs(a.y-d.pos.y)<e.y;var h=2*abs(a.x-d.pos.x)<e.x;c=max(this.elasticity,d.elasticity);if(f|h|!k)if(this.pos.y=d.pos.y+(e.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-c;else if(d.mass){h=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const g=d.velocity.y*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.y*this.mass/(this.mass+d.mass);this.velocity.y=lerp(c,h,this.velocity.y*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.y*d.mass/(this.mass+d.mass));d.velocity.y=lerp(c,h,g)}!f&k&&(this.pos.x=d.pos.x+(e.x/2+.001)*sign(a.x-d.pos.x),d.mass?(e=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),this.velocity.x=lerp(c,e,this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass)),d.velocity.x=lerp(c,e,f)):this.velocity.x*=-c);debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)&&(c=tileCollisionTest(new Vector2(a.x,this.pos.y),this.size,this),d=tileCollisionTest(new Vector2(this.pos.x,a.y),this.size,this),c|!d&&(this.groundObject=b,this.velocity.y*=-this.elasticity,b=(a.y-this.size.y/2|0)-(a.y-this.size.y/2),0>b&&b>this.damping*this.velocity.y+gravity*this.gravityScale&&(this.velocity.y=this.damping?(b-gravity*this.gravityScale)/this.damping:0),this.pos.y=a.y),d&&(this.pos.x=a.x,this.velocity.x*=-this.elasticity))}}render(){drawTile(this.pos,this.drawSize||this.size,this.tileIndex,this.tileSize,this.color,this.angle,this.mirror,this.additiveColor)}destroy(){if(!this.destroyed){this.destroyed=1;this.parent&&this.parent.removeChild(this);for(const a of this.children)a.destroy(a.parent=0)}}collideWithTile(a,b){return 0<a}collideWithTileRaycast(a,b){return 0<a}collideWithObject(a){return 1}getAliveTime(){return time-this.spawnTime}applyAcceleration(a){this.mass&&(this.velocity=this.velocity.add(a))}applyForce(a){this.applyAcceleration(a.scale(1/this.mass))}getMirrorSign(){return this.mirror?-1:1}addChild(a,b=vec2(),c=0){ASSERT(!a.parent&&!this.children.includes(a));this.children.push(a);a.parent=this;a.localPos=b.copy();a.localAngle=c}removeChild(a){ASSERT(a.parent==this&&this.children.includes(a));this.children.splice(this.children.indexOf(a),1);a.parent=0}setCollision(a=1,b=1,c=1){ASSERT(a||!b);this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c}toString(){if(debug){let a="type = "+this.constructor.name;if(this.pos.x||this.pos.y)a+="\npos = "+this.pos;if(this.velocity.x||this.velocity.y)a+="\nvelocity = "+this.velocity;if(this.size.x||this.size.y)a+="\nsize = "+this.size;this.angle&&(a+="\nangle = "+this.angle.toFixed(3));this.color&&(a+="\ncolor = "+this.color);return a}}}"use strict";let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2();const tileImage=new Image;let tileImageSize,tileImageFixBleed,drawCount;const screenToWorld=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.add(vec2(.5)).subtract(mainCanvasSize.scale(.5)).multiply(vec2(1/cameraScale,-1/cameraScale)).add(cameraPos)},worldToScreen=a=>{ASSERT(mainCanvasSize.x&&mainCanvasSize.y,"mainCanvasSize is invalid");return a.subtract(cameraPos).multiply(vec2(cameraScale,-cameraScale)).add(mainCanvasSize.scale(.5)).subtract(vec2(.5))};function drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f=0,h,k=new Color(0,0,0,0),g=glEnable){showWatermark&&++drawCount;if(glEnable&&g)if(0>c||!tileImage.width)glDraw(a.x,a.y,b.x,b.y,f,0,0,0,0,0,e.rgbaInt());else{var l=tileImageSize.x/d.x|0;g=d.x/tileImageSize.x;const m=d.y/tileImageSize.y,n=c%l*g;l=(c/l|0)*m;glDraw(a.x,a.y,h?-b.x:b.x,b.y,f,n+tileImageFixBleed.x,l+tileImageFixBleed.y,n-tileImageFixBleed.x+g,l-tileImageFixBleed.y+m,e.rgbaInt(),k.rgbaInt())}else drawCanvas2D(a,b,f,h,m=>{if(0>c)m.fillStyle=e,m.fillRect(-.5,-.5,1,1);else{var n=tileImageSize.x/d.x|0;const p=c%n*d.x+tileFixBleedScale;n=(c/n|0)*d.y+tileFixBleedScale;const q=d.x-2*tileFixBleedScale,r=d.y-2*tileFixBleedScale;m.globalAlpha=e.a;m.drawImage(tileImage,p,n,q,r,-.5,-.5,1,1)}})}function drawRect(a,b,c,d,e){drawTile(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawTileScreenSpace(a,b=vec2(1),c,d,e,f,h,k,g){drawTile(screenToWorld(a),b.scale(1/cameraScale),c,d,e,f,h,k,g)}function drawRectScreenSpace(a,b,c,d,e){drawTileScreenSpace(a,b,-1,tileSizeDefault,c,d,0,0,e)}function drawLine(a,b,c=.1,d,e){b=vec2((b.x-a.x)/2,(b.y-a.y)/2);c=vec2(c,2*b.length());drawRect(a.add(b),c,d,b.angle(),e)}function drawCanvas2D(a,b,c,d,e,f=mainContext){a=worldToScreen(a);b=b.scale(cameraScale);f.save();f.translate(a.x+.5|0,a.y+.5|0);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}function setBlendMode(a,b=glEnable){glEnable&&b?glSetBlendMode(a):mainContext.globalCompositeOperation=a?"lighter":"source-over"}function drawText(a,b,c=1,d,e=0,f,h,k,g){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,h,k,g)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),h="center",k=fontDefault,g=overlayContext){g.fillStyle=d;g.lineWidth=e;g.strokeStyle=f;g.textAlign=h;g.font=c+"px "+k;g.textBaseline="middle";g.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&g.strokeText(l,b.x,b.y);g.fillText(l,b.x,b.y);b.y+=c})}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=0,e=overlayContext){engineFontImage||((engineFontImage=new Image).src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC");this.image=a||engineFontImage;this.tileSize=b;this.paddingSize=c;this.startTileIndex=d;this.context=e}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!cavasPixelated;const f=this.tileSize,h=f.add(this.paddingSize).scale(c),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((g,l)=>{const m=d?g.length*f.x*c/2|0:0;for(let q=g.length;q--;){var n=g[q].charCodeAt();if(32>n||127<n)n=127;var p=this.startTileIndex+n-32;n=p%k;p=p/k|0;const r=b.add(vec2(q,l).multiply(h));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,r.x-m,r.y,f.x*c,f.y*c)}});e.restore()}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}}const isFullscreen=()=>document.fullscreenElement;function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}"use strict";const keyIsDown=(a,b=0)=>inputData[b]&&inputData[b][a]&1,keyWasPressed=(a,b=0)=>inputData[b]&&inputData[b][a]&2?1:0,keyWasReleased=(a,b=0)=>inputData[b]&&inputData[b][a]&4?1:0,clearInput=()=>inputData=[[]],mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0,preventDefaultInput=0;const gamepadIsDown=(a,b=0)=>keyIsDown(a,b+1),gamepadWasPressed=(a,b=0)=>keyWasPressed(a,b+1),gamepadWasReleased=(a,b=0)=>keyWasReleased(a,b+1),gamepadStick=(a,b=0)=>stickData[b]?stickData[b][a]||vec2():vec2();let inputData=[[]];function inputUpdate(){isTouchDevice||document.hasFocus()||clearInput();mousePos=screenToWorld(mousePosScreen);gamepadsUpdate()}function inputUpdatePost(){for(const a of inputData)for(const b in a)a[b]&=1;mouseWheel=0}onkeydown=a=>{debug&&a.target!=document.body||(a.repeat||(inputData[isUsingGamepad=0][remapKey(a.which)]=3),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][remapKey(a.which)]=4)};const remapKey=a=>inputWASDEmulateDirection?87==a?38:83==a?40:65==a?37:68==a?39:a:a;onmousedown=a=>{inputData[isUsingGamepad=0][a.button]=3;onmousemove(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>a.ctrlKey||(mouseWheel=sign(a.deltaY));oncontextmenu=a=>!1;const mouseToScreen=a=>{if(!mainCanvas)return vec2();const b=mainCanvas.getBoundingClientRect();return vec2(mainCanvas.width,mainCanvas.height).multiply(vec2(percent(a.x,b.left,b.right),percent(a.y,b.top,b.bottom)))},stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){(stickData[0]||(stickData[0]=[]))[0]=vec2(touchGamepadStick.x,-touchGamepadStick.y);var a=inputData[1]||(inputData[1]=[]);for(var b=10;b--;){var c=3==b?2:2==b?3:b;a[c]=touchGamepadButtons[b]?1+2*!gamepadIsDown(c,0):4*gamepadIsDown(c,0)}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(document.hasFocus()||debug))for(a=navigator.getGamepads(),b=a.length;b--;){var d=a[b];const h=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=k=>.3<k?percent(k,.3,.8):-.3>k?-percent(-k,.3,.8):0;for(var f=0;f<d.axes.length-1;f+=2)c[f>>1]=vec2(e(d.axes[f]),e(-d.axes[f+1])).clampLength();for(e=d.buttons.length;e--;)f=d.buttons[e],h[e]=f.pressed?1+2*!gamepadIsDown(e,b):4*gamepadIsDown(e,b),isUsingGamepad|=!b&&f.pressed,touchGamepadEnable&&touchGamepadTimer.unset();gamepadDirectionEmulateStick&&(d=vec2(gamepadIsDown(15,b)-gamepadIsDown(14,b),gamepadIsDown(12,b)-gamepadIsDown(13,b)),d.lengthSquared()&&(c[0]=d.clampLength()))}}}const vibrate=a=>vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a),vibrateStop=()=>vibrate(0),isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b=onmousedown,c=onmouseup;onmousedown=onmouseup=()=>0;ontouchstart=d=>{zzfx(0);ontouchstart=ontouchmove=ontouchend=e=>{e.button=0;const f=e.touches.length;f?(e.x=e.touches[0].clientX,e.y=e.touches[0].clientY,a?onmousemove(e):b(e)):a&&c(e);a=f;return!0};touchGamepadEnable&&touchGamepadCreate();return ontouchstart(d)}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function touchGamepadCreate(){touchGamepadButtons=[];touchGamepadStick=vec2();let a=ontouchstart;ontouchstart=ontouchmove=ontouchend=b=>{touchGamepadStick=vec2();touchGamepadButtons=[];if(b.touches.length&&(touchGamepadTimer.set(),paused)){touchGamepadButtons[9]=1;return}const c=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize),d=mainCanvasSize.subtract(vec2(touchGamepadSize,touchGamepadSize)),e=mainCanvasSize.scale(.5);for(const h of b.touches){var f=mouseToScreen(vec2(h.clientX,h.clientY));f.distance(c)<touchGamepadSize?touchGamepadAnalog?touchGamepadStick=f.subtract(c).scale(2/touchGamepadSize).clampLength():(f=f.subtract(c).angle(),touchGamepadStick.setAngle((4*f/PI+8.5|0)*PI/4)):f.distance(d)<touchGamepadSize?(f=f.subtract(d).direction(),touchGamepadButtons[f]=1):f.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)}a(b);isUsingGamepad=1;return!0}}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer,4,3);if(a&&!paused){overlayContext.save();overlayContext.globalAlpha=a*touchGamepadAlpha;overlayContext.strokeStyle="#fff";overlayContext.lineWidth=3;overlayContext.fillStyle=0<touchGamepadStick.lengthSquared()?"#fff":"#000";overlayContext.beginPath();a=vec2(touchGamepadSize,mainCanvasSize.y-touchGamepadSize);if(touchGamepadAnalog)overlayContext.arc(a.x,a.y,touchGamepadSize/2,0,9),overlayContext.fill();else for(var b=10;b--;){var c=b*PI/4;overlayContext.arc(a.x,a.y,.6*touchGamepadSize,c+PI/8,c+PI/8);b%2&&overlayContext.arc(a.x,a.y,.33*touchGamepadSize,c,c);1==b&&overlayContext.fill()}overlayContext.stroke();a=vec2(mainCanvasSize.x-touchGamepadSize,mainCanvasSize.y-touchGamepadSize);for(b=4;b--;)c=a.add((new Vector2).setAngle(b*PI/2,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}"use strict";class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=a[1]||0,a[1]=0,this.cachedSamples=zzfxG(...a))}play(a,b=1,c=1,d=1){if(soundEnable){var e;if(a){if(e=this.range){const f=cameraPos.distanceSquared(a);if(f>e*e)return;b*=percent(f**.5,e,e*this.taper)}e=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return playSamples([this.cachedSamples],b,a,e)}}playNote(a,b,c){if(soundEnable)return this.play(b,c,2**(a/12),0)}}class Music{constructor(a){soundEnable&&(this.cachedSamples=zzfxM(...a))}play(a,b=1){if(soundEnable)return this.source=playSamples(this.cachedSamples,a,1,0,b)}stop(){this.source&&this.source.stop();this.source=0}isPlaying(){return this.source}}function playAudioFile(a,b=1,c=1){if(soundEnable)return a=new Audio(a),a.volume=soundVolume*b,a.loop=c,a.play(),a}function speak(a,b="",c=1,d=1,e=1){if(soundEnable&&speechSynthesis)return a=new SpeechSynthesisUtterance(a),a.lang=b,a.volume=2*c*soundVolume,a.rate=d,a.pitch=e,speechSynthesis.speak(a),a}const speakStop=()=>speechSynthesis&&speechSynthesis.cancel(),getNoteFrequency=(a,b=220)=>b*2**(a/12);let audioContext;function playSamples(a,b=1,c=1,d=0,e=0){if(soundEnable&&(audioContext||=new AudioContext,audioContext.resume(),"running"==audioContext.state)){var f=audioContext.createBuffer(a.length,a[0].length,zzfxR),h=audioContext.createBufferSource();a.forEach((k,g)=>f.getChannelData(g).set(k));h.buffer=f;h.playbackRate.value=c;h.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);h.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);h.start();return h}}const zzfx=(...a)=>playSamples([zzfxG(...a)]),zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,h=0,k=1,g=0,l=0,m=0,n=0,p=0,q=0,r=0,w=0,u=0,B=1,y=0,C=0){let v=2*PI,F=g*=500*v/zzfxR/zzfxR,A=[];b=c*=(1+b*rand(-1,1))*v/zzfxR;let x=0,D=0,t=0,z=1,G=0,I=0,E=0,J,H;d=d*zzfxR+9;y*=zzfxR;e*=zzfxR;f*=zzfxR;u*=zzfxR;l*=500*v/zzfxR**3;r*=v/zzfxR;m*=v/zzfxR;n*=zzfxR;p=p*zzfxR|0;for(H=d+y+e+f+u|0;t<H;A[t++]=E)++I%(100*w|0)||(E=h?1<h?2<h?3<h?Math.sin((x%v)**3):max(min(Math.tan(x),1),-1):1-(2*x/v%2+2)%2:1-4*abs(Math.round(x/v)-x/v):Math.sin(x),E=(p?1-C+C*Math.sin(v*t/p):1)*sign(E)*abs(E)**k*a*soundVolume*(t<d?t/d:t<d+y?1-(t-d)/y*(1-B):t<d+y+e?B:t<H-u?(H-t-u)/f*B:0),E=u?E/2+(u>t?0:(t<H-u?1:(H-t)/u)*A[t-u|0]/2):E),J=(c+=g+=l)*Math.cos(r*D++),x+=J-J*q*(1-1e9*(Math.sin(t)+1)%2),z&&++z>n&&(c+=m,b+=m,z=0),!p||++G%p||(c=b,g=F,z||=1);return A}function zzfxM(a,b,c,d=125){let e,f,h,k,g,l,m,n,p,q,r,w,u,B=0,y,C=[],v=[],F=[],A=0,x=0,D=1,t={},z=zzfxR/d*60>>2;for(;D;A++)C=[D=n=w=0],c.forEach((G,I)=>{m=b[G][A]||[0,0,0];D|=!!b[G][A];y=w+(b[G][0].length-2-!n)*z;u=I==c.length-1;e=2;for(h=w;e<m.length+u;n=++e){g=m[e];p=e==m.length+u-1&&u||q!=(m[0]||0)|g|0;for(f=0;f<z&&n;f++>z-99&&p?r+=(1>r)/99:0)l=(1-r)*C[B++]/2||0,v[h]=(v[h]||0)-l*x+l,F[h]=(F[h++]||0)+l*x+l;g&&(r=g%1,x=m[1]||0,g|=0)&&(C=t[[q=m[B=0]||0,g]]=t[[q,g]]||(k=[...a[q]],k[2]*=2**((g-12)/12),0<g?zzfxG(...k):[]))}w=y});return[v,F]}"use strict";let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}const setTileCollisionData=(a,b=0)=>a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b),getTileCollisionData=a=>a.arrayCheck(tileCollisionSize)?tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]:0;function tileCollisionTest(a,b=vec2(),c){const d=max(a.x-b.x/2|0,0);var e=max(a.y-b.y/2|0,0);const f=min(a.x+b.x/2,tileCollisionSize.x);for(a=min(a.y+b.y/2,tileCollisionSize.y);e<a;++e)for(b=d;b<f;++b){const h=tileCollision[e*tileCollisionSize.x+b];if(h&&(!c||c.collideWithTile(h,new Vector2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){var d=(b=b.floor()).subtract(a=a.floor());const e=abs(d.x),f=-abs(d.y),h=sign(d.x);d=sign(d.y);for(let g=a.x,l=a.y,m=e+f;;){var k=getTileCollisionData(vec2(g,l));if(k&&(c?c.collideWithTileRaycast(k,new Vector2(g,l)):0<k))return debugRaycast&&debugLine(a,b,"#f00",.02,1),debugRaycast&&debugPoint(new Vector2(g+.5,l+.5),"#ff0",1),new Vector2(g+.5,l+.5);if(g==b.x&l==b.y)break;k=2*m;k>=f&&(m+=f,g+=h);k<=e&&(m+=e,l+=d)}debugRaycast&&debugLine(a,b,"#00f",.02,1)}class TileLayerData{constructor(a,b=0,c=0,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=this.mirror=0;color=new Color}}class TileLayer extends EngineObject{constructor(a,b=tileCollisionSize,c=tileSizeDefault,d=vec2(1),e=0){super(a,b,-1,c,0,void 0,e);this.canvas=document.createElement("canvas");this.context=this.canvas.getContext("2d");this.scale=d;this.isOverlay;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c){a.arrayCheck(this.size)&&(this.data[(a.y|0)*this.size.x+a.x|0]=b,c&&this.drawTileData(a))}getData(a){return a.arrayCheck(this.size)&&this.data[(a.y|0)*this.size.x+a.x|0]}update(){}render(){ASSERT(mainContext!=this.context);glEnable&&!glOverlay&&!this.isOverlay&&glCopyToContext(mainContext);const a=worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));(this.isOverlay?overlayContext:mainContext).drawImage(this.canvas,a.x,a.y,cameraScale*this.size.x*this.scale.x,cameraScale*this.size.y*this.scale.y)}redraw(){this.redrawStart(1);this.drawAllTileData();this.redrawEnd()}redrawStart(a=0){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;cameraPos=this.size.scale(.5);cameraScale=this.tileSize.x;a&&(mainCanvas.width=this.size.x*this.tileSize.x,mainCanvas.height=this.size.y*this.tileSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context);glEnable&&glCopyToContext(mainContext,1);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a){const b=a.floor().add(this.pos).add(vec2(.5));this.drawCanvas2D(b,vec2(1),0,0,c=>c.clearRect(-.5,-.5,1,1));a=this.getData(a);void 0!=a.tile&&(ASSERT(mainContext==this.context),drawTile(b,vec2(1),a.tile,this.tileSize,a.color,a.direction*PI/2,a.mirror))}drawAllTileData(){for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b))}drawCanvas2D(a,b,c=0,d,e){const f=this.context;f.save();a=a.subtract(this.pos).multiply(this.tileSize);b=b.multiply(this.tileSize);f.translate(a.x,this.canvas.height-a.y);f.rotate(c);f.scale(d?-b.x:b.x,b.y);e(f);f.restore()}drawTile(a,b=vec2(1),c=-1,d=tileSizeDefault,e=new Color,f,h){this.drawCanvas2D(a,b,f,h,k=>{if(0>c)k.fillStyle=e,k.fillRect(-.5,-.5,1,1);else{const g=tileImage.width/d.x;k.globalAlpha=e.a;k.drawImage(tileImage,c%g*d.x,(c/g|0)*d.y,d.x,d.y,-.5,-.5,1,1)}})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}"use strict";class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,h=-1,k=tileSizeDefault,g=new Color,l=new Color,m=new Color(1,1,1,0),n=new Color(1,1,1,0),p=.5,q=.1,r=1,w=.1,u=.05,B=1,y=1,C=0,v=PI,F=.1,A=.2,x,D,t=1,z=D?1e9:0,G){super(a,new Vector2,h,k,b,void 0,z);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=g;this.colorStartB=l;this.colorEndA=m;this.colorEndB=n;this.randomColorLinear=t;this.particleTime=p;this.sizeStart=q;this.sizeEnd=r;this.speed=w;this.angleSpeed=u;this.damping=B;this.angleDamping=y;this.gravityScale=C;this.particleConeAngle=v;this.fadeRate=F;this.randomness=A;this.collideTiles=x;this.additive=D;this.localSpace=G;this.emitTimeBuffer=this.trailScale=0}update(){this.parent&&super.update();if(!this.emitTime|this.getAliveTime()<=this.emitTime){if(this.emitRate*particleEmitRateScale){const a=1/this.emitRate/particleEmitRateScale;for(this.emitTimeBuffer+=timeDelta;0<this.emitTimeBuffer;this.emitTimeBuffer-=a)this.emitParticle()}}else this.destroy();debugParticles&&debugRect(this.pos,vec2(this.emitSize),"#0f0",0,this.angle)}emitParticle(){var a=void 0!=this.emitSize.x?new Vector2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle):randInCircle(this.emitSize/2),b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);a=new Particle(a,this.tileIndex,this.tileSize,b);const c=this.randomness;var d=m=>m+m*rand(c,-c);b=d(this.particleTime);const e=d(this.sizeStart),f=d(this.sizeEnd),h=d(this.speed);d=d(this.angleSpeed)*randSign();var k=rand(this.emitConeAngle,-this.emitConeAngle);const g=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);k=this.localSpace?k:this.angle+k;a.colorStart=g;a.colorEndDelta=l.subtract(g);a.velocity=(new Vector2).setAngle(k,h);a.angleVelocity=d;a.lifeTime=b;a.sizeStart=e;a.sizeEndDelta=f-e;a.fadeRate=this.fadeRate;a.damping=this.damping;a.angleDamping=this.angleDamping;a.elasticity=this.elasticity;a.friction=this.friction;a.gravityScale=this.gravityScale;a.collideTiles=this.collideTiles;a.additive=this.additive;a.renderOrder=this.renderOrder;a.trailScale=this.trailScale;a.mirror=randInt(2);a.localSpaceEmitter=this.localSpace&&this;a.destroyCallback=this.particleDestroyCallback;this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d){super(a,new Vector2,b,c,d)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1);var b=this.sizeStart+a*this.sizeEndDelta;b=new Vector2(b,b);var c=this.fadeRate/2;c=new Color(this.colorStart.r+a*this.colorEndDelta.r,this.colorStart.g+a*this.colorEndDelta.g,this.colorStart.b+a*this.colorEndDelta.b,(this.colorStart.a+a*this.colorEndDelta.a)*(a<c?a/c:a>1-c?(1-a)/c:1));this.additive&&setBlendMode(1);let d=this.pos;var e=this.angle;this.localSpaceEmitter&&(d=this.localSpaceEmitter.pos.add(d.rotate(-this.localSpaceEmitter.angle)),e+=this.localSpaceEmitter.angle);if(this.trailScale){var f=this.velocity;this.localSpaceEmitter&&(f=f.rotate(-this.localSpaceEmitter.angle));e=f.length();f=f.scale(1/e);const h=e*this.trailScale;b.y=max(b.x,h);e=f.angle();drawTile(d.add(f.multiply(vec2(0,-h/2))),b,this.tileIndex,this.tileSize,c,e,this.mirror)}else drawTile(d,b,this.tileIndex,this.tileSize,c,e,this.mirror);this.additive&&setBlendMode();debugParticles&&debugRect(d,b,"#f005",0,e);1==a&&(this.color=c,this.size=b,this.destroyCallback&&this.destroyCallback(this),this.destroyed=1)}}"use strict";const medals=[];let medalsDisplayQueue=[],medalsSaveName,medalsDisplayTimeLast;function medalsInit(a){medalsSaveName=a;debugMedals||medals.forEach(b=>b.unlocked=localStorage[b.storageKey()]|0)}class Medal{constructor(a,b,c="",d="🏆",e){ASSERT(0<=a&&!medals[a]);medals[this.id=a]=this;this.name=b;this.description=c;this.icon=d;e&&((this.image=new Image).src=e)}unlock(){medalsPreventUnlock||this.unlocked||(ASSERT(medalsSaveName),localStorage[this.storageKey()]=this.unlocked=1,medalsDisplayQueue.push(this),newgrounds&&newgrounds.unlockMedal(this.id))}render(a=0){const b=overlayContext;var c=min(medalDisplaySize.x,mainCanvas.width);const d=overlayCanvas.width-c;a*=-medalDisplaySize.y;b.save();b.beginPath();b.fillStyle=new Color(.9,.9,.9);b.strokeStyle=new Color(0,0,0);b.lineWidth=3;b.fill(b.rect(d,a,c,medalDisplaySize.y));b.stroke();b.clip();this.renderIcon(vec2(d+15+medalDisplayIconSize/2,a+medalDisplaySize.y/2));c=vec2(d+medalDisplayIconSize+30,a+28);drawTextScreen(this.name,c,38,new Color(0,0,0),0,0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,0,"left");b.restore()}renderIcon(a,b=medalDisplayIconSize){this.image?overlayContext.drawImage(this.image,a.x-b/2,a.y-b/2,b,b):drawTextScreen(this.icon,a,.7*b,new Color(0,0,0))}storageKey(){return medalsSaveName+"_"+this.id}}function medalsRender(){if(medalsDisplayQueue.length){var a=medalsDisplayQueue[0],b=timeReal-medalsDisplayTimeLast;if(medalsDisplayTimeLast)if(b>medalDisplayTime)medalsDisplayQueue.shift(medalsDisplayTimeLast=0);else{const c=medalDisplayTime-medalDisplaySlideTime;a.render(b<medalDisplaySlideTime?1-b/medalDisplaySlideTime:b>c?(b-c)/medalDisplaySlideTime:0)}else medalsDisplayTimeLast=timeReal}}let newgrounds;function newgroundsInit(a,b){newgrounds=new Newgrounds(a,b)}class Newgrounds{constructor(a,b){ASSERT(!newgrounds&&a);this.app_id=a;this.cipher=b;this.host=location?location.hostname:"";b&&(this.cryptoJS=this.CryptoJS());if(this.session_id=new URL(location.href).searchParams.get("ngio_session_id")){this.medals=(a=this.call("Medal.getList"))?a.result.data.medals:[];debugMedals&&console.log(this.medals);for(var c of this.medals)if(a=medals[c.id])a.image=new Image,a.image.src=c.icon,a.name=c.name,a.description=c.description,a.unlocked=c.unlocked,a.difficulty=c.difficulty,a.value=c.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(c=this.call("ScoreBoard.getBoards"))?c.result.data.scoreboards:[];debugMedals&&console.log(this.scoreboards);setInterval(()=>this.call("Gateway.ping",0,1),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},1)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},1)}getScores(a,b=0,c=0,d=0,e=10){return this.call("ScoreBoard.getScores",{id:a,user:b,social:c,skip:d,limit:e})}logView(){return this.call("App.logView",{host:this.host},1)}call(a,b=0,c=0){a={component:a,parameters:b};if(this.cipher){b=this.cryptoJS;var d=b.enc.Base64.parse(this.cipher);const e=b.lib.WordArray.random(16);d=b.AES.encrypt(JSON.stringify(a),d,{iv:e});a.secure=b.enc.Base64.stringify(e.concat(d.ciphertext));a.parameters=0}b={app_id:this.app_id,session_id:this.session_id,call:a};a=new FormData;a.append("input",JSON.stringify(b));b=new XMLHttpRequest;b.open("POST","https://newgrounds.io/gateway_v3.php",!debugMedals&&c);b.send(a);debugMedals&&console.log(b.responseText);return b.responseText&&JSON.parse(b.responseText)}CryptoJS(){return eval(Function("[M='GBMGXz^oVYPPKKbB`agTXU|LxPc_ZBcMrZvCr~wyGfWrwk@ATqlqeTp^N?p{we}jIpEnB_sEr`l?YDkDhWhprc|Er|XETG?pTl`e}dIc[_N~}fzRycIfpW{HTolvoPB_FMe_eH~BTMx]yyOhv?biWPCGc]kABencBhgERHGf{OL`Dj`c^sh@canhy[secghiyotcdOWgO{tJIE^JtdGQRNSCrwKYciZOa]Y@tcRATYKzv|sXpboHcbCBf`}SKeXPFM|RiJsSNaIb]QPc[D]Jy_O^XkOVTZep`ONmntLL`Qz~UupHBX_Ia~WX]yTRJIxG`ioZ{fefLJFhdyYoyLPvqgH?b`[TMnTwwfzDXhfM?rKs^aFr|nyBdPmVHTtAjXoYUloEziWDCw_suyYT~lSMksI~ZNCS[Bex~j]Vz?kx`gdYSEMCsHpjbyxQvw|XxX_^nQYue{sBzVWQKYndtYQMWRef{bOHSfQhiNdtR{o?cUAHQAABThwHPT}F{VvFmgN`E@FiFYS`UJmpQNM`X|tPKHlccT}z}k{sACHL?Rt@MkWplxO`ASgh?hBsuuP|xD~LSH~KBlRs]t|l|_tQAroDRqWS^SEr[sYdPB}TAROtW{mIkE|dWOuLgLmJrucGLpebrAFKWjikTUzS|j}M}szasKOmrjy[?hpwnEfX[jGpLt@^v_eNwSQHNwtOtDgWD{rk|UgASs@mziIXrsHN_|hZuxXlPJOsA^^?QY^yGoCBx{ekLuZzRqQZdsNSx@ezDAn{XNj@fRXIwrDX?{ZQHwTEfu@GhxDOykqts|n{jOeZ@c`dvTY?e^]ATvWpb?SVyg]GC?SlzteilZJAL]mlhLjYZazY__qcVFYvt@|bIQnSno@OXyt]OulzkWqH`rYFWrwGs`v|~XeTsIssLrbmHZCYHiJrX}eEzSssH}]l]IhPQhPoQ}rCXLyhFIT[clhzYOvyHqigxmjz`phKUU^TPf[GRAIhNqSOdayFP@FmKmuIzMOeoqdpxyCOwCthcLq?n`L`tLIBboNn~uXeFcPE{C~mC`h]jUUUQe^`UqvzCutYCgct|SBrAeiYQW?X~KzCz}guXbsUw?pLsg@hDArw?KeJD[BN?GD@wgFWCiHq@Ypp_QKFixEKWqRp]oJFuVIEvjDcTFu~Zz]a{IcXhWuIdMQjJ]lwmGQ|]g~c]Hl]pl`Pd^?loIcsoNir_kikBYyg?NarXZEGYspt_vLBIoj}LI[uBFvm}tbqvC|xyR~a{kob|HlctZslTGtPDhBKsNsoZPuH`U`Fqg{gKnGSHVLJ^O`zmNgMn~{rsQuoymw^JY?iUBvw_~mMr|GrPHTERS[MiNpY[Mm{ggHpzRaJaoFomtdaQ_?xuTRm}@KjU~RtPsAdxa|uHmy}n^i||FVL[eQAPrWfLm^ndczgF~Nk~aplQvTUpHvnTya]kOenZlLAQIm{lPl@CCTchvCF[fI{^zPkeYZTiamoEcKmBMfZhk_j_~Fjp|wPVZlkh_nHu]@tP|hS@^G^PdsQ~f[RqgTDqezxNFcaO}HZhb|MMiNSYSAnQWCDJukT~e|OTgc}sf[cnr?fyzTa|EwEtRG|I~|IO}O]S|rp]CQ}}DWhSjC_|z|oY|FYl@WkCOoPuWuqr{fJu?Brs^_EBI[@_OCKs}?]O`jnDiXBvaIWhhMAQDNb{U`bqVR}oqVAvR@AZHEBY@depD]OLh`kf^UsHhzKT}CS}HQKy}Q~AeMydXPQztWSSzDnghULQgMAmbWIZ|lWWeEXrE^EeNoZApooEmrXe{NAnoDf`m}UNlRdqQ@jOc~HLOMWs]IDqJHYoMziEedGBPOxOb?[X`KxkFRg@`mgFYnP{hSaxwZfBQqTm}_?RSEaQga]w[vxc]hMne}VfSlqUeMo_iqmd`ilnJXnhdj^EEFifvZyxYFRf^VaqBhLyrGlk~qowqzHOBlOwtx?i{m~`n^G?Yxzxux}b{LSlx]dS~thO^lYE}bzKmUEzwW^{rPGhbEov[Plv??xtyKJshbG`KuO?hjBdS@Ru}iGpvFXJRrvOlrKN?`I_n_tplk}kgwSXuKylXbRQ]]?a|{xiT[li?k]CJpwy^o@ebyGQrPfF`aszGKp]baIx~H?ElETtFh]dz[OjGl@C?]VDhr}OE@V]wLTc[WErXacM{We`F|utKKjgllAxvsVYBZ@HcuMgLboFHVZmi}eIXAIFhS@A@FGRbjeoJWZ_NKd^oEH`qgy`q[Tq{x?LRP|GfBFFJV|fgZs`MLbpPYUdIV^]mD@FG]pYAT^A^RNCcXVrPsgk{jTrAIQPs_`mD}rOqAZA[}RETFz]WkXFTz_m{N@{W@_fPKZLT`@aIqf|L^Mb|crNqZ{BVsijzpGPEKQQZGlApDn`ruH}cvF|iXcNqK}cxe_U~HRnKV}sCYb`D~oGvwG[Ca|UaybXea~DdD~LiIbGRxJ_VGheI{ika}KC[OZJLn^IBkPrQj_EuoFwZ}DpoBRcK]Q}?EmTv~i_Tul{bky?Iit~tgS|o}JL_VYcCQdjeJ_MfaA`FgCgc[Ii|CBHwq~nbJeYTK{e`CNstKfTKPzw{jdhp|qsZyP_FcugxCFNpKitlR~vUrx^NrSVsSTaEgnxZTmKc`R|lGJeX}ccKLsQZQhsFkeFd|ckHIVTlGMg`~uPwuHRJS_CPuN_ogXe{Ba}dO_UBhuNXby|h?JlgBIqMKx^_u{molgL[W_iavNQuOq?ap]PGB`clAicnl@k~pA?MWHEZ{HuTLsCpOxxrKlBh]FyMjLdFl|nMIvTHyGAlPogqfZ?PlvlFJvYnDQd}R@uAhtJmDfe|iJqdkYr}r@mEjjIetDl_I`TELfoR|qTBu@Tic[BaXjP?dCS~MUK[HPRI}OUOwAaf|_}HZzrwXvbnNgltjTwkBE~MztTQhtRSWoQHajMoVyBBA`kdgK~h`o[J`dm~pm]tk@i`[F~F]DBlJKklrkR]SNw@{aG~Vhl`KINsQkOy?WhcqUMTGDOM_]bUjVd|Yh_KUCCgIJ|LDIGZCPls{RzbVWVLEhHvWBzKq|^N?DyJB|__aCUjoEgsARki}j@DQXS`RNU|DJ^a~d{sh_Iu{ONcUtSrGWW@cvUjefHHi}eSSGrNtO?cTPBShLqzwMVjWQQCCFB^culBjZHEK_{dO~Q`YhJYFn]jq~XSnG@[lQr]eKrjXpG~L^h~tDgEma^AUFThlaR{xyuP@[^VFwXSeUbVetufa@dX]CLyAnDV@Bs[DnpeghJw^?UIana}r_CKGDySoRudklbgio}kIDpA@McDoPK?iYcG?_zOmnWfJp}a[JLR[stXMo?_^Ng[whQlrDbrawZeSZ~SJstIObdDSfAA{MV}?gNunLOnbMv_~KFQUAjIMj^GkoGxuYtYbGDImEYiwEMyTpMxN_LSnSMdl{bg@dtAnAMvhDTBR_FxoQgANniRqxd`pWv@rFJ|mWNWmh[GMJz_Nq`BIN@KsjMPASXORcdHjf~rJfgZYe_uulzqM_KdPlMsuvU^YJuLtofPhGonVOQxCMuXliNvJIaoC?hSxcxKVVxWlNs^ENDvCtSmO~WxI[itnjs^RDvI@KqG}YekaSbTaB]ki]XM@[ZnDAP~@|BzLRgOzmjmPkRE@_sobkT|SszXK[rZN?F]Z_u}Yue^[BZgLtR}FHzWyxWEX^wXC]MJmiVbQuBzkgRcKGUhOvUc_bga|Tx`KEM`JWEgTpFYVeXLCm|mctZR@uKTDeUONPozBeIkrY`cz]]~WPGMUf`MNUGHDbxZuO{gmsKYkAGRPqjc|_FtblEOwy}dnwCHo]PJhN~JoteaJ?dmYZeB^Xd?X^pOKDbOMF@Ugg^hETLdhwlA}PL@_ur|o{VZosP?ntJ_kG][g{Zq`Tu]dzQlSWiKfnxDnk}KOzp~tdFstMobmy[oPYjyOtUzMWdjcNSUAjRuqhLS@AwB^{BFnqjCmmlk?jpn}TksS{KcKkDboXiwK]qMVjm~V`LgWhjS^nLGwfhAYrjDSBL_{cRus~{?xar_xqPlArrYFd?pHKdMEZzzjJpfC?Hv}mAuIDkyBxFpxhstTx`IO{rp}XGuQ]VtbHerlRc_LFGWK[XluFcNGUtDYMZny[M^nVKVeMllQI[xtvwQnXFlWYqxZZFp_|]^oWX[{pOMpxXxvkbyJA[DrPzwD|LW|QcV{Nw~U^dgguSpG]ClmO@j_TENIGjPWwgdVbHganhM?ema|dBaqla|WBd`poj~klxaasKxGG^xbWquAl~_lKWxUkDFagMnE{zHug{b`A~IYcQYBF_E}wiA}K@yxWHrZ{[d~|ARsYsjeNWzkMs~IOqqp[yzDE|WFrivsidTcnbHFRoW@XpAV`lv_zj?B~tPCppRjgbbDTALeFaOf?VcjnKTQMLyp{NwdylHCqmo?oelhjWuXj~}{fpuX`fra?GNkDiChYgVSh{R[BgF~eQa^WVz}ATI_CpY?g_diae]|ijH`TyNIF}|D_xpmBq_JpKih{Ba|sWzhnAoyraiDvk`h{qbBfsylBGmRH}DRPdryEsSaKS~tIaeF[s]I~xxHVrcNe@Jjxa@jlhZueLQqHh_]twVMqG_EGuwyab{nxOF?`HCle}nBZzlTQjkLmoXbXhOtBglFoMz?eqre`HiE@vNwBulglmQjj]DB@pPkPUgA^sjOAUNdSu_`oAzar?n?eMnw{{hYmslYi[TnlJD'",..."]charCodeAtUinyxpf","for(;e<10359;c[e++]=p-=128,A=A?p-A&&A:p==34&&p)for(p=1;p<128;y=f.map((n,x)=>(U=r[n]*2+1,U=Math.log(U/(h-U)),t-=a[x]*U,U/500)),t=~-h/(1+Math.exp(t))|1,i=o%h<t,o=o%h+(i?t:h-t)*(o>>17)-!i*t,f.map((n,x)=>(U=r[n]+=(i*h/2-r[n]<<13)/((C[n]+=C[n]<5)+1/20)>>13,a[x]+=y[x]*(i-t/h))),p=p*2+i)for(f='010202103203210431053105410642065206541'.split(t=0).map((n,x)=>(U=0,[...n].map((n,x)=>(U=U*997+(c[e-n]|0)|0)),h*32-1&U*997+p+!!A*129)*12+x);o<h*32;o=o*64|M.charCodeAt(d++)&63);for(C=String.fromCharCode(...c);r=/[\0-#?@\\\\~]/.exec(C);)with(C.split(r))C=join(shift());return C")([],[],131072,[0,0,0,0,0,0,0,0,0,0,0,0],new Uint16Array(51e6).fill(32768),new Uint8Array(51e6),0,0,0,0))}}"use strict";let glCanvas,glContext,glTileTexture,glActiveTexture,glShader,glArrayBuffer,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl",{antialias:!1});glTileTexture=glCreateTexture(tileImage);glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("precision highp float;uniform mat4 m;attribute vec2 p,t;attribute vec4 c,a;varying vec4 v,d,e;void main(){gl_Position=m*vec4(p,1,1);v=vec4(t,p);d=c;e=a;}","precision highp float;varying vec4 v,d,e;uniform sampler2D s;void main(){gl_FragColor=texture2D(s,v.xy)*d+e;}");const a=new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);glArrayBuffer=glContext.createBuffer();glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glBatchCount=0}function glSetBlendMode(a){glAdditive=a}function glSetTexture(a=glTileTexture){a!=glActiveTexture&&glFlush();glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=a)}function glCompileShader(a,b){b=glContext.createShader(b);glContext.shaderSource(b,a);glContext.compileShader(b);if(debug&&!glContext.getShaderParameter(b,gl_COMPILE_STATUS))throw glContext.getShaderInfoLog(b);return b}function glCreateProgram(a,b){const c=glContext.createProgram();glContext.attachShader(c,glCompileShader(a,gl_VERTEX_SHADER));glContext.attachShader(c,glCompileShader(b,gl_FRAGMENT_SHADER));glContext.linkProgram(c);if(debug&&!glContext.getProgramParameter(c,gl_LINK_STATUS))throw glContext.getProgramInfoLog(c);return c}function glCreateTexture(a){const b=glContext.createTexture();glContext.bindTexture(gl_TEXTURE_2D,b);a&&a.width&&glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,a);a=cavasPixelated?gl_NEAREST:gl_LINEAR;glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MIN_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_MAG_FILTER,a);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_S,gl_CLAMP_TO_EDGE);glContext.texParameteri(gl_TEXTURE_2D,gl_TEXTURE_WRAP_T,gl_CLAMP_TO_EDGE);return b}function glPreRender(){glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glContext.clear(gl_COLOR_BUFFER_BIT);glContext.useProgram(glShader);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glActiveTexture=glTileTexture);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_VERTEX_BUFFER_SIZE,gl_DYNAMIC_DRAW);glSetBlendMode();let a=0;var b=(d,e,f,h,k=0)=>{d=glContext.getAttribLocation(glShader,d);glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,h,e,k,gl_VERTEX_BYTE_STRIDE,a);a+=h*f};b("p",gl_FLOAT,4,2);b("t",gl_FLOAT,4,2);b("c",gl_UNSIGNED_BYTE,1,4,1);b("a",gl_UNSIGNED_BYTE,1,4,1);b=2*cameraScale/mainCanvas.width;const c=2*cameraScale/mainCanvas.height;glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([b,0,0,0,0,c,0,0,1,1,-1,1,-1-b*cameraPos.x,-1-c*cameraPos.y,0,0]))}function glFlush(){if(glBatchCount){var a=glBatchAdditive?gl_ONE:gl_ONE_MINUS_SRC_ALPHA;glContext.blendFuncSeparate(gl_SRC_ALPHA,a,gl_ONE,a);glContext.enable(gl_BLEND);glContext.bufferSubData(gl_ARRAY_BUFFER,0,glPositionData.subarray(0,glBatchCount*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLES,0,glBatchCount*gl_VERTICES_PER_QUAD);glBatchCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b){if(glBatchCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,h,k,g,l,m=0){glBatchCount!=gl_MAX_BATCH&&glBatchAdditive==glAdditive||glFlush();var n=Math.cos(e)/2,p=Math.sin(e)/2;e=n*c;n*=d;c*=p;d*=p;for(let q=6,r=glBatchCount++*gl_VERTICES_PER_QUAD*gl_INDICIES_PER_VERT;q--;){p=q-4&&1<q;const w=q-5&&q-2&&q-1;glPositionData[r++]=a+(p?-e:e)+(w?d:-d);glPositionData[r++]=b+(w?n:-n)+(p?c:-c);glPositionData[r++]=p?f:k;glPositionData[r++]=w?h:g;glColorData[r++]=l;glColorData[r++]=m}}let glPostShader,glPostArrayBuffer,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b){ASSERT(!glPostShader);a||="void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("precision highp float;attribute vec2 p;void main(){gl_Position=vec4(p,1,1);}","precision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;\n"+a+"\nvoid main(){mainImage(gl_FragColor,gl_FragCoord.xy);gl_FragColor.a=1.;}");glPostArrayBuffer=glContext.createBuffer();glPostTexture=glCreateTexture();glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden"}function glRenderPostProcess(){if(glPostShader){glEnable?(glFlush(),mainContext.drawImage(glCanvas,0,0)):glContext.viewport(0,0,glCanvas.width=mainCanvas.width,glCanvas.height=mainCanvas.height);glPostIncludeOverlay&&(mainContext.drawImage(overlayCanvas,0,0),overlayCanvas.width=mainCanvas.width);glContext.useProgram(glPostShader);glContext.disable(gl_BLEND);glContext.bindBuffer(gl_ARRAY_BUFFER,glPostArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,new Float32Array([-3,1,1,-3,1,1]),gl_STATIC_DRAW);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,!0);glContext.activeTexture(gl_TEXTURE0);glContext.bindTexture(gl_TEXTURE_2D,glPostTexture);glContext.texImage2D(gl_TEXTURE_2D,0,gl_RGBA,gl_RGBA,gl_UNSIGNED_BYTE,mainCanvas);var a=glContext.getAttribLocation(glPostShader,"p");glContext.enableVertexAttribArray(a);glContext.vertexAttribPointer(a,2,gl_FLOAT,0,8,0);glContext.uniform1i(glContext.getUniformLocation(glPostShader,"iChannel0"),0);glContext.uniform1f(glContext.getUniformLocation(glPostShader,"iTime"),time);glContext.uniform3f(glContext.getUniformLocation(glPostShader,"iResolution"),mainCanvas.width,mainCanvas.height,1);glContext.drawArrays(gl_TRIANGLES,0,3)}}const gl_ONE=1,gl_TRIANGLES=4,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,gl_BYTE=5120,gl_FLOAT=5126,gl_RGBA=6408,gl_NEAREST=9728,gl_LINEAR=9729,gl_TEXTURE_MAG_FILTER=10240,gl_TEXTURE_MIN_FILTER=10241,gl_TEXTURE_WRAP_S=10242,gl_TEXTURE_WRAP_T=10243,gl_COLOR_BUFFER_BIT=16384,gl_CLAMP_TO_EDGE=33071,gl_TEXTURE0=33984,gl_TEXTURE1=33985,gl_ARRAY_BUFFER=34962,gl_STATIC_DRAW=35044,gl_DYNAMIC_DRAW=35048,gl_FRAGMENT_SHADER=35632,gl_VERTEX_SHADER=35633,gl_COMPILE_STATUS=35713,gl_LINK_STATUS=35714,gl_UNPACK_FLIP_Y_WEBGL=37440,gl_VERTICES_PER_QUAD=6,gl_INDICIES_PER_VERT=6,gl_MAX_BATCH=65536,gl_VERTEX_BYTE_STRIDE=24,gl_VERTEX_BUFFER_SIZE=gl_MAX_BATCH*gl_VERTICES_PER_QUAD*gl_VERTEX_BYTE_STRIDE;const setCameraPos=pos=>cameraPos=pos;const setCameraScale=scale=>cameraScale=scale;const setCanvasMaxSize=size=>canvasMaxSize=size;const setCanvasFixedSize=size=>canvasFixedSize=size;const setCavasPixelated=pixelated=>cavasPixelated=pixelated;const setFontDefault=font=>fontDefault=font;const setGlEnable=enable=>glEnable=enable;const setGlOverlay=overlay=>glOverlay=overlay;const setTileSizeDefault=size=>tileSizeDefault=size;const setTileFixBleedScale=scale=>tileFixBleedScale=scale;const setEnablePhysicsSolver=enable=>enablePhysicsSolver=enable;const setObjectDefaultMass=mass=>objectDefaultMass=mass;const setObjectDefaultDamping=damp=>objectDefaultDamping=damp;const setObjectDefaultAngleDamping=damp=>objectDefaultAngleDamping=damp;const setObjectDefaultElasticity=elasticity=>objectDefaultElasticity=elasticity;const setObjectDefaultFriction=friction=>objectDefaultFriction=friction;const setObjectMaxSpeed=speed=>objectMaxSpeed=speed;const setGravity=g=>gravity=g;const setParticleEmitRateScale=scale=>particleEmitRateScale=scale;const setGamepadsEnable=enable=>gamepadsEnable=enable;const setGamepadDirectionEmulateStick=enable=>gamepadDirectionEmulateStick=enable;const setInputWASDEmulateDirection=enable=>inputWASDEmulateDirection=enable;const setTouchGamepadEnable=enable=>touchGamepadEnable=enable;const setTouchGamepadAnalog=analog=>touchGamepadAnalog=analog;const setTouchGamepadSize=size=>touchGamepadSize=size;const setTouchGamepadAlpha=alpha=>touchGamepadAlpha=alpha;const setVibrateEnable=enable=>vibrateEnable=enable;const setSoundEnable=enable=>soundEnable=enable;const setSoundVolume=volume=>soundVolume=volume;const setSoundDefaultRange=range=>soundDefaultRange=range;const setSoundDefaultTaper=taper=>soundDefaultTaper=taper;const setMedalDisplayTime=time=>medalDisplayTime=time;const setMedalDisplaySlideTime=time=>medalDisplaySlideTime=time;const setMedalDisplaySize=size=>medalDisplaySize=size;const setMedalDisplayIconSize=size=>medalDisplayIconSize=size;const setMedalsPreventUnlock=prevent=>medalsPreventUnlock=prevent;const setShowWatermark=show=>showWatermark=show;const setGodMode=enable=>godMode=enable;const setDebugKey=key=>debugKey=key;export{setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCavasPixelated,setFontDefault,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setGodMode,setDebugKey,canvasMaxSize,canvasFixedSize,cavasPixelated,fontDefault,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,cameraPos,cameraScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,debug,showWatermark,godMode,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,PI,abs,min,max,sign,mod,clamp,percent,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,randSeed,setRandSeed,randSeeded,Vector2,Color,Timer,vec2,rgb,hsl,EngineObject,tileImage,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawTileScreenSpace,drawRectScreenSpace,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds,glCanvas,glContext,glSetBlendMode,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback};
|