littlejsengine 1.8.1 → 1.8.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/build/littlejs.js CHANGED
@@ -1558,6 +1558,7 @@ class EngineObject
1558
1558
  // set passed in params
1559
1559
  ASSERT(isVector2(pos) && isVector2(size)); // ensure pos and size are vec2s
1560
1560
  ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
1561
+ ASSERT(!(renderOrder instanceof Color)); // prevent old style calls
1561
1562
  // to fix old calls, replace with tile(tileIndex, tileSize)
1562
1563
 
1563
1564
  /** @property {Vector2} - World space position of the object */
@@ -2079,16 +2080,18 @@ function worldToScreen(worldPos)
2079
2080
  * @param {Color} [additiveColor=Color(0,0,0,0)] - Additive color to be applied
2080
2081
  * @param {Boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
2081
2082
  * @param {Boolean} [screenSpace=0] - If true the pos and size are in screen space
2083
+ * @param {CanvasRenderingContext2D} [context] - Canvas 2D context to draw to
2082
2084
  * @memberof Draw */
2083
2085
  function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
2084
- angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace)
2086
+ angle=0, mirror, additiveColor=new Color(0,0,0,0), useWebGL=glEnable, screenSpace, context)
2085
2087
  {
2088
+ ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
2086
2089
  ASSERT(typeof tileInfo !== 'number' || !tileInfo); // prevent old style calls
2087
2090
  // to fix old calls, replace with tile(tileIndex, tileSize)
2088
2091
 
2089
2092
  showWatermark && ++drawCount;
2090
2093
  const textureInfo = tileInfo && tileInfo.getTextureInfo();
2091
- if (glEnable && useWebGL)
2094
+ if (useWebGL)
2092
2095
  {
2093
2096
  if (screenSpace)
2094
2097
  {
@@ -2139,7 +2142,7 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
2139
2142
  context.fillStyle = color;
2140
2143
  context.fillRect(-.5, -.5, 1, 1);
2141
2144
  }
2142
- }, undefined, screenSpace);
2145
+ }, screenSpace, context);
2143
2146
  }
2144
2147
  }
2145
2148
 
@@ -2150,28 +2153,36 @@ function drawTile(pos, size=vec2(1), tileInfo, color=new Color,
2150
2153
  * @param {Number} [angle=0]
2151
2154
  * @param {Boolean} [useWebGL=glEnable]
2152
2155
  * @param {Boolean} [screenSpace=0]
2156
+ * @param {CanvasRenderingContext2D} [context]
2153
2157
  * @memberof Draw */
2154
- function drawRect(pos, size, color, angle, useWebGL, screenSpace)
2155
- { drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace); }
2158
+ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
2159
+ {
2160
+ drawTile(pos, size, undefined, color, angle, 0, undefined, useWebGL, screenSpace, context);
2161
+ }
2156
2162
 
2157
2163
  /** Draw colored polygon using passed in points
2158
2164
  * @param {Array} points - Array of Vector2 points
2159
2165
  * @param {Color} [color=Color()]
2160
2166
  * @param {Boolean} [useWebGL=glEnable]
2161
2167
  * @param {Boolean} [screenSpace=0]
2168
+ * @param {CanvasRenderingContext2D} [context]
2162
2169
  * @memberof Draw */
2163
- function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
2170
+ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace, context)
2164
2171
  {
2172
+ ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
2173
+
2165
2174
  if (useWebGL)
2166
2175
  glDrawPoints(screenSpace ? points.map(screenToWorld) : points, color.rgbaInt());
2167
2176
  else
2168
2177
  {
2169
2178
  // draw using canvas
2170
- mainContext.fillStyle = color;
2171
- mainContext.beginPath();
2179
+ if (!context)
2180
+ context = mainContext;
2181
+ context.fillStyle = color;
2182
+ context.beginPath();
2172
2183
  for (const point of screenSpace ? points : points.map(worldToScreen))
2173
- mainContext.lineTo(point.x, point.y);
2174
- mainContext.fill();
2184
+ context.lineTo(point.x, point.y);
2185
+ context.fill();
2175
2186
  }
2176
2187
  }
2177
2188
 
@@ -2182,12 +2193,13 @@ function drawPoly(points, color=new Color, useWebGL=glEnable, screenSpace)
2182
2193
  * @param {Color} [color=Color()]
2183
2194
  * @param {Boolean} [useWebGL=glEnable]
2184
2195
  * @param {Boolean} [screenSpace=0]
2196
+ * @param {CanvasRenderingContext2D} [context]
2185
2197
  * @memberof Draw */
2186
- function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
2198
+ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
2187
2199
  {
2188
2200
  const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
2189
2201
  const size = vec2(thickness, halfDelta.length()*2);
2190
- drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace);
2202
+ drawRect(posA.add(halfDelta), size, color, halfDelta.angle(), useWebGL, screenSpace, context);
2191
2203
  }
2192
2204
 
2193
2205
  /** Draw directly to a 2d canvas context in world space
@@ -2196,10 +2208,10 @@ function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace)
2196
2208
  * @param {Number} angle
2197
2209
  * @param {Boolean} mirror
2198
2210
  * @param {Function} drawFunction
2199
- * @param {CanvasRenderingContext2D} [context=mainContext]
2200
2211
  * @param {Boolean} [screenSpace=0]
2212
+ * @param {CanvasRenderingContext2D} [context=mainContext]
2201
2213
  * @memberof Draw */
2202
- function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainContext, screenSpace)
2214
+ function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, context=mainContext)
2203
2215
  {
2204
2216
  if (!screenSpace)
2205
2217
  {
@@ -2218,13 +2230,19 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, context = mainCont
2218
2230
  /** Enable normal or additive blend mode
2219
2231
  * @param {Boolean} [additive=0]
2220
2232
  * @param {Boolean} [useWebGL=glEnable]
2233
+ * @param {CanvasRenderingContext2D} [context=mainContext]
2221
2234
  * @memberof Draw */
2222
- function setBlendMode(additive, useWebGL=glEnable)
2235
+ function setBlendMode(additive, useWebGL=glEnable, context)
2223
2236
  {
2224
- if (glEnable && useWebGL)
2225
- glSetBlendMode(additive);
2237
+ ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
2238
+ if (useWebGL)
2239
+ glAdditive = additive;
2226
2240
  else
2227
- mainContext.globalCompositeOperation = additive ? 'lighter' : 'source-over';
2241
+ {
2242
+ if (!context)
2243
+ context = mainContext;
2244
+ context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
2245
+ }
2228
2246
  }
2229
2247
 
2230
2248
  /** Draw text on overlay canvas in world space
@@ -2876,7 +2894,8 @@ class Sound
2876
2894
  if (zzfxSound)
2877
2895
  {
2878
2896
  // generate zzfx sound now for fast playback
2879
- this.randomness = zzfxSound[1] || (zzfxSound[1] = 0);
2897
+ this.randomness = zzfxSound[1] || 0;
2898
+ zzfxSound[1] = 0; // generate without randomness
2880
2899
  this.sampleChannels = [zzfxG(...zzfxSound)];
2881
2900
  this.sampleRate = zzfxR;
2882
2901
  }
@@ -4382,21 +4401,20 @@ function glInit()
4382
4401
  '#version 300 es\n' + // specify GLSL ES version
4383
4402
  'precision highp float;'+ // use highp for better accuracy
4384
4403
  'uniform mat4 m;'+ // transform matrix
4385
- 'in vec2 p,t;'+ // position, uv
4386
- 'in vec4 c,a;'+ // color, additiveColor
4404
+ 'in vec4 p,c,a;'+ // position, uv, color, additiveColor
4387
4405
  'out vec4 v,d,e;'+ // return uv, color, additiveColor
4388
4406
  'void main(){'+ // shader entry point
4389
- 'gl_Position=m*vec4(p,1,1);'+ // transform position
4390
- 'v=vec4(t,p);d=c;e=a;'+ // pass stuff to fragment shader
4407
+ 'gl_Position=m*vec4(p.xy,1,1);'+ // transform position
4408
+ 'v=p;d=c;e=a;'+ // pass stuff to fragment shader
4391
4409
  '}' // end of shader
4392
4410
  ,
4393
4411
  '#version 300 es\n' + // specify GLSL ES version
4394
4412
  'precision highp float;'+ // use highp for better accuracy
4395
- 'in vec4 v,d,e;'+ // uv, color, additiveColor
4413
+ 'in vec4 v,d,e;'+ // position, uv, color, additiveColor
4396
4414
  'uniform sampler2D s;'+ // texture
4397
4415
  'out vec4 c;'+ // out color
4398
4416
  'void main(){'+ // shader entry point
4399
- 'c=texture(s,v.xy)*d+e;'+ // modulate texture by color plus additive
4417
+ 'c=texture(s,v.zw)*d+e;'+ // modulate texture by color plus additive
4400
4418
  '}' // end of shader
4401
4419
  );
4402
4420
 
@@ -4421,7 +4439,7 @@ function glPreRender()
4421
4439
  glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
4422
4440
  glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
4423
4441
  glContext.bufferData(gl_ARRAY_BUFFER, gl_VERTEX_BUFFER_SIZE, gl_DYNAMIC_DRAW);
4424
- glSetBlendMode();
4442
+ glAdditive = 0;
4425
4443
 
4426
4444
  // set vertex attributes
4427
4445
  let offset = 0;
@@ -4432,33 +4450,25 @@ function glPreRender()
4432
4450
  glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
4433
4451
  offset += size*typeSize;
4434
4452
  }
4435
- initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
4436
- initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
4453
+ initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & texture coords
4437
4454
  initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
4438
4455
  initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
4439
4456
 
4440
4457
  // build the transform matrix
4441
4458
  const sx = 2 * cameraScale / mainCanvas.width;
4442
4459
  const sy = 2 * cameraScale / mainCanvas.height;
4460
+ const cx = -1 - sx*cameraPos.x;
4461
+ const cy = -1 - sy*cameraPos.y;
4443
4462
  glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader, 'm'), 0,
4444
4463
  new Float32Array([
4445
- sx, 0, 0, 0,
4446
- 0, sy, 0, 0,
4447
- 1, 1, -1, 1,
4448
- -1-sx*cameraPos.x, -1-sy*cameraPos.y, 0, 0
4464
+ sx, 0, 0, 0,
4465
+ 0, sy, 0, 0,
4466
+ 1, 1, -1, 1,
4467
+ cx, cy, 0, 0
4449
4468
  ])
4450
4469
  );
4451
4470
  }
4452
4471
 
4453
- /** Set the WebGl blend mode, normally you should call setBlendMode instead
4454
- * @param {Boolean} [additive=0]
4455
- * @memberof WebGL */
4456
- function glSetBlendMode(additive=0)
4457
- {
4458
- // setup blending
4459
- glAdditive = additive;
4460
- }
4461
-
4462
4472
  /** Set the WebGl texture, called automatically if using multiple textures
4463
4473
  * - This may also flush the gl buffer resulting in more draw calls and worse performance
4464
4474
  * @param {WebGLTexture} texture
@@ -4694,8 +4704,11 @@ function glRenderPostProcess()
4694
4704
  glFlush(); // clear out the buffer
4695
4705
  mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
4696
4706
  }
4697
- else // set viewport
4707
+ else
4708
+ {
4709
+ // set the viewport
4698
4710
  glContext.viewport(0, 0, glCanvas.width = mainCanvas.width, glCanvas.height = mainCanvas.height);
4711
+ }
4699
4712
 
4700
4713
  if (glPostIncludeOverlay)
4701
4714
  {
@@ -4799,7 +4812,7 @@ const engineName = 'LittleJS';
4799
4812
  * @type {String}
4800
4813
  * @default
4801
4814
  * @memberof Engine */
4802
- const engineVersion = '1.8.1';
4815
+ const engineVersion = '1.8.4';
4803
4816
 
4804
4817
  /** Frames per second to update objects
4805
4818
  * @type {Number}
@@ -4860,7 +4873,7 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, averageFPS = 0;
4860
4873
  * @param {Function} gameUpdatePost - Called after physics and objects are updated, setup camera and prepare for render
4861
4874
  * @param {Function} gameRender - Called before objects are rendered, draw any background effects that appear behind objects
4862
4875
  * @param {Function} gameRenderPost - Called after objects are rendered, draw effects or hud that appear above all objects
4863
- * @param {String} [imageSources='tiles.png'] - Image to load
4876
+ * @param {Array} [imageSources=['tiles.png']] - Image to load
4864
4877
  * @memberof Engine */
4865
4878
  function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, imageSources=['tiles.png'])
4866
4879
  {
@@ -1 +1 @@
1
- let showWatermark=0,debugKeyCode=0;const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0;function ASSERT(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRect(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugAABB(){}function debugText(){}function debugClear(){}function debugSaveCanvas(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(a,b){return Math.min(a,b)}function max(a,b){return Math.max(a,b)}function sign(a){return Math.sign(a)}function mod(a,b=1){return(a%b+b)%b}function clamp(a,b=0,c=1){return a<b?b:a>c?c:a}function percent(a,b,c){return c-b?clamp((a-b)/(c-b)):0}function lerp(a,b,c){return b+clamp(a)*(c-b)}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){return c+clamp(a)*distanceWrap(b,c,d)}function distanceAngle(a,b){distanceWrap(a,b,2*PI)}function lerpAngle(a,b,c){return lerpWrap(a,b,c,2*PI)}function smoothStep(a){return a*a*(3-2*a)}function nearestPowerOfTwo(a){return 2**Math.ceil(Math.log2(a))}function isOverlapping(a,b,c,d){return 2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y}function wave(a=1,b=1,c=time){return b/2*(1-Math.cos(c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randSign(){return 2*randInt(2)-1}function randVector(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVector(a*rand(b/a,1)**.5):new Vector2}function randColor(a=new Color,b=new Color(0,0,0,1),c){return 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))}class RandomGenerator{constructor(a){this.seed=a}float(a=1,b=0){this.seed^=this.seed<<13;this.seed^=this.seed>>>17;this.seed^=this.seed<<5;return b+(a-b)*abs(this.seed%1e9)/1e9}int(a,b=0){return Math.floor(this.float(a,b))}sign(){return 2*this.int(2)-1}}function vec2(a=0,b){return void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return!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)} )`}}function rgb(a,b,c,d){return new Color(a,b,c,d)}function hsl(a,b,c,d){return(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,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*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),g=(e+f)/2;let h=0,k=0;if(e!=f){let l=e-f;k=.5<g?l/(2-e-f):l/(e+f);a==e?h=(b-c)/l+(b<c?6:0):b==e?h=(c-a)/l+2:c==e&&(h=(a-b)/l+4)}return[h/6,k,g,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.isSet()?Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after"):"unset"}valueOf(){return this.get()}}let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),canvasPixelated=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;function setCameraPos(a){cameraPos=a}function setCameraScale(a){cameraScale=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a}function setFontDefault(a){fontDefault=a}function setGlEnable(a){glEnable=a}function setGlOverlay(a){glOverlay=a}function setTileSizeDefault(a){tileSizeDefault=a}function setTileFixBleedScale(a){tileFixBleedScale=a}function setEnablePhysicsSolver(a){enablePhysicsSolver=a}function setObjectDefaultMass(a){objectDefaultMass=a}function setObjectDefaultDamping(a){objectDefaultDamping=a}function setObjectDefaultAngleDamping(a){objectDefaultAngleDamping=a}function setObjectDefaultElasticity(a){objectDefaultElasticity=a}function setObjectDefaultFriction(a){objectDefaultFriction=a}function setObjectMaxSpeed(a){objectMaxSpeed=a}function setGravity(a){gravity=a}function setParticleEmitRateScale(a){particleEmitRateScale=a}function setGamepadsEnable(a){gamepadsEnable=a}function setGamepadDirectionEmulateStick(a){gamepadDirectionEmulateStick=a}function setInputWASDEmulateDirection(a){inputWASDEmulateDirection=a}function setTouchGamepadEnable(a){touchGamepadEnable=a}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundVolume(a){soundVolume=a}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setMedalDisplayTime(a){medalDisplayTime=a}function setMedalDisplaySlideTime(a){medalDisplaySlideTime=a}function setMedalDisplaySize(a){medalDisplaySize=a}function setMedalDisplayIconSize(a){medalDisplayIconSize=a}function setMedalsPreventUnlock(a){medalsPreventUnlock=a}function setShowWatermark(a){showWatermark=a}function setDebugKey(a){debugKey=a}class EngineObject{constructor(a=vec2(),b=vec2(1),c,d=0,e,f=0){ASSERT(isVector2(a)&&isVector2(b));ASSERT("number"!==typeof c||!c);this.pos=a.copy();this.size=b;this.drawSize;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();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;c=this.collideWithObject(d);var e=d.collideWithObject(this);if(!c||!e)continue;if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);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 h=2*abs(a.y-d.pos.y)<e.y;var g=2*abs(a.x-d.pos.x)<e.x;c=max(this.elasticity,d.elasticity);if(f||g||!h)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){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const k=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,g,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,g,k)}!f&&h&&(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")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this);if(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.tileInfo,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}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=vec2(),b=tileSizeDefault,c=0){void 0==b.x&&(ASSERT(0<b),b=vec2(b));if(void 0==a.x){var d=textureInfos[c];d?(d=d.size.x/b.x|0,a=vec2(a%d*b.x,(a/d|0)*b.y)):a=vec2()}return new TileInfo(a,b,c)}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0){this.pos=a;this.size=b;this.textureIndex=c}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex)}getTextureInfo(){return textureInfos[this.textureIndex]}}class TextureInfo{constructor(a){this.image=a;this.size=vec2(a.width,a.height);this.glTexture=glEnable&&glCreateTexture(a);this.fixBleedSize=vec2(tileFixBleedScale).divide(this.size)}}function screenToWorld(a){return new Vector2((a.x-mainCanvasSize.x/2+.5)/cameraScale+cameraPos.x,(a.y-mainCanvasSize.y/2+.5)/-cameraScale+cameraPos.y)}function worldToScreen(a){return new Vector2((a.x-cameraPos.x)*cameraScale+mainCanvasSize.x/2-.5,(a.y-cameraPos.y)*-cameraScale+mainCanvasSize.y/2-.5)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),h=glEnable,k){ASSERT("number"!==typeof c||!c);showWatermark&&++drawCount;const l=c&&c.getTextureInfo();if(glEnable&&h)if(k&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),l){h=c.pos.x/l.size.x;k=c.pos.y/l.size.y;const m=c.size.x/l.size.x,n=c.size.y/l.size.y,p=l.fixBleedSize;glSetTexture(l.glTexture);glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+p.x,k+p.y,h-p.x+m,k-p.y+n,d.rgbaInt(),g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else drawCanvas2D(a,b,e,f,m=>{if(l){const n=c.pos.x+tileFixBleedScale,p=c.pos.y+tileFixBleedScale,t=c.size.x-2*tileFixBleedScale,q=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(l.image,n,p,t,q,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},void 0,k)}function drawRect(a,b,c,d,e,f){drawTile(a,b,void 0,c,d,0,void 0,e,f)}function drawPoly(a,b=new Color,c=glEnable,d){if(c)glDrawPoints(d?a.map(screenToWorld):a,b.rgbaInt());else{mainContext.fillStyle=b;mainContext.beginPath();for(const e of d?a:a.map(worldToScreen))mainContext.lineTo(e.x,e.y);mainContext.fill()}}function drawLine(a,b,c=.1,d,e,f){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,f)}function drawCanvas2D(a,b,c,d,e,f=mainContext,g){g||(a=worldToScreen(a),b=b.scale(cameraScale));f.save();f.translate(a.x+.5,a.y+.5);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,g,h,k){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,h,k)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault,k=overlayContext){k.fillStyle=d;k.lineWidth=e;k.strokeStyle=f;k.textAlign=g;k.font=c+"px "+h;k.textBaseline="middle";k.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&k.strokeText(l,b.x,b.y);k.fillText(l,b.x,b.y);b.y+=c})}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=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.context=d}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!canvasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((k,l)=>{const m=d?k.length*f.x*c/2|0:0;for(let t=k.length;t--;){var n=k[t].charCodeAt();if(32>n||127<n)n=127;var p=n-32;n=p%h;p=p/h|0;const q=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,n*f.x,p*f.y,f.x,f.y,q.x-m,q.y,f.x*c,f.y*c)}});e.restore()}}function isFullscreen(){return document.fullscreenElement}function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}function keyIsDown(a,b=0){return inputData[b]&&inputData[b][a]&1}function keyWasPressed(a,b=0){return inputData[b]&&inputData[b][a]&2?1:0}function keyWasReleased(a,b=0){return inputData[b]&&inputData[b][a]&4?1:0}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0,preventDefaultInput=0;function gamepadIsDown(a,b=0){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=0){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=0){return keyWasReleased(a,b+1)}function gamepadStick(a,b=0){return 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)};function remapKey(a){return 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;function 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)))}const stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),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 g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.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],g[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()))}}}function vibrate(a){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b=onmousedown,c=onmouseup;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=d=>{d.button=0;soundEnable&&(audioContext?audioContext.resume():zzfx(0));const e=d.touches.length;e?(d.x=d.touches[0].clientX,d.y=d.touches[0].clientY,a?onmousemove(d):b(d)):a&&c(d);a=e;document.hasFocus()&&d.preventDefault();return!0}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function createTouchGamepad(){touchGamepadButtons=[];touchGamepadStick=vec2();const 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 g of b.touches){var f=mouseToScreen(vec2(g.clientX,g.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(vec2().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()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||(a[1]=0),this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=0){if(soundEnable&&this.sampleChannels){var f;if(a){if(f=this.range){const g=cameraPos.distanceSquared(a);if(g>f*f)return;b*=percent(g**.5,f,f*this.taper)}f=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return this.source=playSamples(this.sampleChannels,b,a,f,e,this.sampleRate)}}stop(){this.source&&this.source.stop();this.source=0}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isPlaying(){return this.source&&!this.source.ended}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(0,c,d);this.randomness=b;soundEnable&&(soundDecoderContext||=new AudioContext,fetch(a).then(e=>e.arrayBuffer()).then(e=>soundDecoderContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=e.getChannelData(f);this.sampleRate=e.sampleRate}))}}let soundDecoderContext;class Music extends Sound{constructor(a){super();soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}play(a,b=1){return super.play(0,a,1,1,b)}}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}function speakStop(){speechSynthesis&&speechSynthesis.cancel()}function getNoteFrequency(a,b=220){return b*2**(a/12)}let audioContext;function playSamples(a,b=1,c=1,d=0,e=0,f=zzfxR){if(soundEnable)if(audioContext||=new AudioContext,"running"!=audioContext.state)audioContext.resume();else{var g=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,k)=>g.getChannelData(k).set(h));f.buffer=g;f.playbackRate.value=c;f.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);f.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);f.start();return f}}function zzfx(...a){return playSamples([zzfxG(...a)])}const zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,l=0,m=0,n=0,p=0,t=0,q=0,A=0,u=0,B=1,x=0,C=0){let v=2*PI,E=k*=500*v/zzfxR/zzfxR,z=[];b=c*=(1+b*rand(-1,1))*v/zzfxR;let w=0,F=0,r=0,y=1,H=0,I=0,D=0,J,G;d=d*zzfxR+9;x*=zzfxR;e*=zzfxR;f*=zzfxR;u*=zzfxR;l*=500*v/zzfxR**3;q*=v/zzfxR;m*=v/zzfxR;n*=zzfxR;p=p*zzfxR|0;for(G=d+x+e+f+u|0;r<G;z[r++]=D)++I%(100*A|0)||(D=g?1<g?2<g?3<g?Math.sin((w%v)**3):max(min(Math.tan(w),1),-1):1-(2*w/v%2+2)%2:1-4*abs(Math.round(w/v)-w/v):Math.sin(w),D=(p?1-C+C*Math.sin(v*r/p):1)*sign(D)*abs(D)**h*a*soundVolume*(r<d?r/d:r<d+x?1-(r-d)/x*(1-B):r<d+x+e?B:r<G-u?(G-r-u)/f*B:0),D=u?D/2+(u>r?0:(r<G-u?1:(G-r)/u)*z[r-u|0]/2):D),J=(c+=k+=l)*Math.cos(q*F++),w+=J-J*t*(1-1e9*(Math.sin(r)+1)%2),y&&++y>n&&(c+=m,b+=m,y=0),!p||++H%p||(c=b,k=E,y||=1);return z}function zzfxM(a,b,c,d=125){let e,f,g,h,k,l,m,n,p,t,q,A,u,B=0,x,C=[],v=[],E=[],z=0,w=0,F=1,r={},y=zzfxR/d*60>>2;for(;F;z++)C=[F=n=A=0],c.forEach((H,I)=>{m=b[H][z]||[0,0,0];F||=!!b[H][z];x=A+(b[H][0].length-2-!n)*y;u=I==c.length-1;e=2;for(g=A;e<m.length+u;n=++e){k=m[e];p=e==m.length+u-1&&u||t!=(m[0]||0)||k|0;for(f=0;f<y&&n;f++>y-99&&p?q+=(1>q)/99:0)l=(1-q)*C[B++]/2||0,v[g]=(v[g]||0)-l*w+l,E[g]=(E[g++]||0)+l*w+l;k&&(q=k%1,w=m[1]||0,k|=0)&&(C=r[[t=m[B=0]||0,k]]=r[[t,k]]||(h=[...a[t]],h[2]*=2**((k-12)/12),0<k?zzfxG(...h):[]))}A=x});return[v,E]}let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}function setTileCollisionData(a,b=0){a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b)}function getTileCollisionData(a){return 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 g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,vec2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){const d=b.subtract(a),e=d.length();var f=d.normalize();f=vec2(abs(1/f.x),abs(1/f.y));let g=a.floor(),h=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),k=f.y*(0>d.y?a.y-g.y:g.y-a.y+1);for(;;){const l=getTileCollisionData(g);if(l&&(!c||c.collideWithTile(l,g)))return debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(g.add(vec2(.5)),"#ff0"),g.add(vec2(.5));if(h>e&&k>e)break;h>k?(g.y+=sign(d.y),k+=f.y):(g.x+=sign(d.x),h+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}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=tile(),d=vec2(1),e=0){super(a,b,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.tileInfo.size.x;a&&(mainCanvas.width=this.size.x*this.tileInfo.size.x,mainCanvas.height=this.size.y*this.tileInfo.size.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);if(void 0!=a.tile){ASSERT(mainContext==this.context);const c=tile(a.tile,this.tileInfo.size,this.tileInfo.textureIndex);drawTile(b,vec2(1),c,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.tileInfo.size);b=b.multiply(this.tileInfo.size);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,d=new Color,e,f){this.drawCanvas2D(a,b,e,f,g=>{const h=c&&c.getTextureInfo();h?(g.globalAlpha=d.a,g.drawImage(h.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1),g.globalAlpha=1):(g.fillStyle=d,g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=new Color,k=new Color,l=new Color(1,1,1,0),m=new Color(1,1,1,0),n=.5,p=.1,t=1,q=.1,A=.05,u=1,B=1,x=0,C=PI,v=.1,E=.2,z,w,F=1,r=w?1e9:0,y){super(a,vec2(),g,b,void 0,r);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=k;this.colorEndA=l;this.colorEndB=m;this.randomColorLinear=F;this.particleTime=n;this.sizeStart=p;this.sizeEnd=t;this.speed=q;this.angleSpeed=A;this.damping=u;this.angleDamping=B;this.gravityScale=x;this.particleConeAngle=C;this.fadeRate=v;this.randomness=E;this.collideTiles=z;this.additive=w;this.localSpace=y;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?vec2(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.tileInfo,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),g=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const k=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a.colorStart=k;a.colorEndDelta=l.subtract(k);a.velocity=vec2().setAngle(h,g);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){super(a,vec2(),b,c)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1),b=vec2(this.sizeStart+a*this.sizeEndDelta);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,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));var g=f.length();g&&(f=f.scale(1/g),g*=this.trailScale,b.y=max(b.x,g),e=f.angle(),drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileInfo,c,e,this.mirror))}else drawTile(d,b,this.tileInfo,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)}}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,c){newgrounds=new Newgrounds(a,b,c)}class Newgrounds{constructor(a,b,c){ASSERT(!newgrounds&&a);ASSERT(!b||c);this.app_id=a;this.cipher=b;this.cryptoJS=c;this.host=location?location.hostname:"";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 d of this.medals)if(a=medals[d.id])a.image=new Image,a.image.src=d.icon,a.name=d.name,a.description=d.description,a.unlocked=d.unlocked,a.difficulty=d.difficulty,a.value=d.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.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)}}let glCanvas,glContext,glActiveTexture,glShader,glArrayBuffer,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl2");glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec2 p,t;in vec4 c,a;out vec4 v,d,e;void main(){gl_Position=m*vec4(p,1,1);v=vec4(t,p);d=c;e=a;}","#version 300 es\nprecision highp float;in vec4 v,d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(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 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=textureInfos[0].glTexture);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,g,h=0)=>{d=glContext.getAttribLocation(glShader,d);glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,h,gl_VERTEX_BYTE_STRIDE,a);a+=g*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 glSetBlendMode(a=0){glAdditive=a}function glSetTexture(a){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=canvasPixelated?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 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_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLE_STRIP,0,glBatchCount);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,g,h,k,l,m=0){(glBatchCount>=gl_MAX_BATCH-6||glBatchAdditive!=glAdditive)&&glFlush();var n=Math.cos(e)/2;const p=Math.sin(e)/2;e=n*c;n*=d;c*=p;d*=p;a=[a-e+d,b+n+c,f,g,a-e-d,b-n+c,f,k,a+e+d,b+n-c,h,g,a+e-d,b-n-c,h,k];for(let t=6,q=glBatchCount*gl_INDICIES_PER_VERT;t--;)b=4*clamp(t-1,0,3),glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glColorData[q++]=l,glColorData[q++]=m;glBatchCount+=6}function glDrawPoints(a,b){const c=a.length+2;(glBatchCount>=gl_MAX_BATCH-c||glBatchAdditive!=glAdditive)&&glFlush();for(let e=c,f=glBatchCount*gl_INDICIES_PER_VERT;e--;){var d=clamp(e-1,0,c-3);const g=d>>1;d=a[d%2?g:c-3-g];glPositionData[f++]=d.x;glPositionData[f++]=d.y;glPositionData[f++]=0;glPositionData[f++]=0;glColorData[f++]=0;glColorData[f++]=b}glBatchCount+=c}let glPostShader,glPostArrayBuffer,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b){ASSERT(!glPostShader);a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p,1,1);}","#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;out vec4 c;\n"+a+"\nvoid main(){mainImage(c,gl_FragCoord.xy);c.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_TRIANGLE_STRIP,0,3)}}const gl_ONE=1,gl_TRIANGLE_STRIP=5,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,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_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_INDICIES_PER_VERT=6,gl_MAX_BATCH=1e5,gl_VERTEX_BYTE_STRIDE=24,gl_VERTEX_BUFFER_SIZE=gl_MAX_BATCH*gl_VERTEX_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.8.1",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0;function setPaused(a){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;function engineInit(a,b,c,d,e,f=["tiles.png"]){function g(h=0){var k=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(k||1));h=debug&&keyIsDown(107);const l=debug&&keyIsDown(109);debug&&(k*=h?5:l?.2:1);timeReal+=k/1e3;frameTimeBufferMS+=!paused*k;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,k=innerWidth/innerHeight,h=mainCanvas.width/mainCanvas.height,(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=k<h?"100%":"",(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=k<h?"":"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{k=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(k=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=k}enginePreRender();d();engineObjects.sort((n,p)=>n.renderOrder-p.renderOrder);for(var m of engineObjects)m.destroyed||m.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",m=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(m,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(m,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}ASSERT(Array.isArray(f));document.body.style="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout: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%);"+(canvasPixelated?"image-rendering:pixelated":"");Promise.all(f.map((h,k)=>new Promise((l,m)=>{const n=new Image;n.onerror=n.onload=()=>{textureInfos[k]=new TextureInfo(n);l()};n.src=h}))).then(()=>{a();g()})}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){function a(b){if(!b.destroyed){b.update();for(const c of b.children)a(c)}}engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed)}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)}
1
+ let showWatermark=0,debugKeyCode=0;const debug=0,debugOverlay=0,debugPhysics=0,debugParticles=0,debugRaycast=0,debugGamepads=0,debugMedals=0;function ASSERT(){}function debugInit(){}function debugUpdate(){}function debugRender(){}function debugRect(){}function debugCircle(){}function debugPoint(){}function debugLine(){}function debugAABB(){}function debugText(){}function debugClear(){}function debugSaveCanvas(){}const PI=Math.PI;function abs(a){return Math.abs(a)}function min(a,b){return Math.min(a,b)}function max(a,b){return Math.max(a,b)}function sign(a){return Math.sign(a)}function mod(a,b=1){return(a%b+b)%b}function clamp(a,b=0,c=1){return a<b?b:a>c?c:a}function percent(a,b,c){return c-b?clamp((a-b)/(c-b)):0}function lerp(a,b,c){return b+clamp(a)*(c-b)}function distanceWrap(a,b,c=1){a=(a-b)%c;return 2*a%c-a}function lerpWrap(a,b,c,d=1){return c+clamp(a)*distanceWrap(b,c,d)}function distanceAngle(a,b){distanceWrap(a,b,2*PI)}function lerpAngle(a,b,c){return lerpWrap(a,b,c,2*PI)}function smoothStep(a){return a*a*(3-2*a)}function nearestPowerOfTwo(a){return 2**Math.ceil(Math.log2(a))}function isOverlapping(a,b,c,d){return 2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y}function wave(a=1,b=1,c=time){return b/2*(1-Math.cos(c*a*2*PI))}function formatTime(a){return(a/60|0)+":"+(10>a%60?"0":"")+(a%60|0)}function rand(a=1,b=0){return b+Math.random()*(a-b)}function randInt(a,b=0){return Math.floor(rand(a,b))}function randSign(){return 2*randInt(2)-1}function randVector(a=1){return(new Vector2).setAngle(rand(2*PI),a)}function randInCircle(a=1,b=0){return 0<a?randVector(a*rand(b/a,1)**.5):new Vector2}function randColor(a=new Color,b=new Color(0,0,0,1),c){return 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))}class RandomGenerator{constructor(a){this.seed=a}float(a=1,b=0){this.seed^=this.seed<<13;this.seed^=this.seed>>>17;this.seed^=this.seed<<5;return b+(a-b)*abs(this.seed%1e9)/1e9}int(a,b=0){return Math.floor(this.float(a,b))}sign(){return 2*this.int(2)-1}}function vec2(a=0,b){return void 0==a.x?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return!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)} )`}}function rgb(a,b,c,d){return new Color(a,b,c,d)}function hsl(a,b,c,d){return(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,g,h)=>(h=(h%1+1)%1)<1/6?f+6*(g-f)*h:.5>h?g:h<2/3?f+(g-f)*(2/3-h)*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),g=(e+f)/2;let h=0,k=0;if(e!=f){let l=e-f;k=.5<g?l/(2-e-f):l/(e+f);a==e?h=(b-c)/l+(b<c?6:0):b==e?h=(c-a)/l+2:c==e&&(h=(a-b)/l+4)}return[h/6,k,g,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.isSet()?Math.abs(this.get())+" seconds "+(0>this.get()?"before":"after"):"unset"}valueOf(){return this.get()}}let cameraPos=vec2(),cameraScale=32,canvasMaxSize=vec2(1920,1200),canvasFixedSize=vec2(),canvasPixelated=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;function setCameraPos(a){cameraPos=a}function setCameraScale(a){cameraScale=a}function setCanvasMaxSize(a){canvasMaxSize=a}function setCanvasFixedSize(a){canvasFixedSize=a}function setCanvasPixelated(a){canvasPixelated=a}function setFontDefault(a){fontDefault=a}function setGlEnable(a){glEnable=a}function setGlOverlay(a){glOverlay=a}function setTileSizeDefault(a){tileSizeDefault=a}function setTileFixBleedScale(a){tileFixBleedScale=a}function setEnablePhysicsSolver(a){enablePhysicsSolver=a}function setObjectDefaultMass(a){objectDefaultMass=a}function setObjectDefaultDamping(a){objectDefaultDamping=a}function setObjectDefaultAngleDamping(a){objectDefaultAngleDamping=a}function setObjectDefaultElasticity(a){objectDefaultElasticity=a}function setObjectDefaultFriction(a){objectDefaultFriction=a}function setObjectMaxSpeed(a){objectMaxSpeed=a}function setGravity(a){gravity=a}function setParticleEmitRateScale(a){particleEmitRateScale=a}function setGamepadsEnable(a){gamepadsEnable=a}function setGamepadDirectionEmulateStick(a){gamepadDirectionEmulateStick=a}function setInputWASDEmulateDirection(a){inputWASDEmulateDirection=a}function setTouchGamepadEnable(a){touchGamepadEnable=a}function setTouchGamepadAnalog(a){touchGamepadAnalog=a}function setTouchGamepadSize(a){touchGamepadSize=a}function setTouchGamepadAlpha(a){touchGamepadAlpha=a}function setVibrateEnable(a){vibrateEnable=a}function setSoundEnable(a){soundEnable=a}function setSoundVolume(a){soundVolume=a}function setSoundDefaultRange(a){soundDefaultRange=a}function setSoundDefaultTaper(a){soundDefaultTaper=a}function setMedalDisplayTime(a){medalDisplayTime=a}function setMedalDisplaySlideTime(a){medalDisplaySlideTime=a}function setMedalDisplaySize(a){medalDisplaySize=a}function setMedalDisplayIconSize(a){medalDisplayIconSize=a}function setMedalsPreventUnlock(a){medalsPreventUnlock=a}function setShowWatermark(a){showWatermark=a}function setDebugKey(a){debugKey=a}class EngineObject{constructor(a=vec2(),b=vec2(1),c,d=0,e,f=0){ASSERT(isVector2(a)&&isVector2(b));ASSERT("number"!==typeof c||!c);ASSERT(!(f instanceof Color));this.pos=a.copy();this.size=b;this.drawSize;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor;this.mass=objectDefaultMass;this.damping=objectDefaultDamping;this.angleDamping=objectDefaultAngleDamping;this.elasticity=objectDefaultElasticity;this.friction=objectDefaultFriction;this.gravityScale=1;this.renderOrder=f;this.velocity=vec2();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;c=this.collideWithObject(d);var e=d.collideWithObject(this);if(!c||!e)continue;if(isOverlapping(a,this.size,d.pos,d.size)){c=a.subtract(d.pos);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 h=2*abs(a.y-d.pos.y)<e.y;var g=2*abs(a.x-d.pos.x)<e.x;c=max(this.elasticity,d.elasticity);if(f||g||!h)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){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const k=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,g,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,g,k)}!f&&h&&(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")}if(this.collideTiles&&tileCollisionTest(this.pos,this.size,this)&&!tileCollisionTest(a,this.size,this)){c=tileCollisionTest(vec2(a.x,this.pos.y),this.size,this);d=tileCollisionTest(vec2(this.pos.x,a.y),this.size,this);if(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.tileInfo,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}}}let mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize=vec2(),textureInfos=[],drawCount;function tile(a=vec2(),b=tileSizeDefault,c=0){void 0==b.x&&(ASSERT(0<b),b=vec2(b));if(void 0==a.x){var d=textureInfos[c];d?(d=d.size.x/b.x|0,a=vec2(a%d*b.x,(a/d|0)*b.y)):a=vec2()}return new TileInfo(a,b,c)}class TileInfo{constructor(a=vec2(),b=tileSizeDefault,c=0){this.pos=a;this.size=b;this.textureIndex=c}offset(a){return new TileInfo(this.pos.add(a),this.size,this.textureIndex)}getTextureInfo(){return textureInfos[this.textureIndex]}}class TextureInfo{constructor(a){this.image=a;this.size=vec2(a.width,a.height);this.glTexture=glEnable&&glCreateTexture(a);this.fixBleedSize=vec2(tileFixBleedScale).divide(this.size)}}function screenToWorld(a){return new Vector2((a.x-mainCanvasSize.x/2+.5)/cameraScale+cameraPos.x,(a.y-mainCanvasSize.y/2+.5)/-cameraScale+cameraPos.y)}function worldToScreen(a){return new Vector2((a.x-cameraPos.x)*cameraScale+mainCanvasSize.x/2-.5,(a.y-cameraPos.y)*-cameraScale+mainCanvasSize.y/2-.5)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),h=glEnable,k,l){ASSERT(!l||!h);ASSERT("number"!==typeof c||!c);showWatermark&&++drawCount;const n=c&&c.getTextureInfo();if(h)if(k&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),n){h=c.pos.x/n.size.x;k=c.pos.y/n.size.y;l=c.size.x/n.size.x;const m=c.size.y/n.size.y,p=n.fixBleedSize;glSetTexture(n.glTexture);glDraw(a.x,a.y,f?-b.x:b.x,b.y,e,h+p.x,k+p.y,h-p.x+l,k-p.y+m,d.rgbaInt(),g.rgbaInt())}else glDraw(a.x,a.y,b.x,b.y,e,0,0,0,0,0,d.rgbaInt());else drawCanvas2D(a,b,e,f,m=>{if(n){const p=c.pos.x+tileFixBleedScale,t=c.pos.y+tileFixBleedScale,q=c.size.x-2*tileFixBleedScale,x=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(n.image,p,t,q,x,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},k,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,0,void 0,e,f,g)}function drawPoly(a,b=new Color,c=glEnable,d,e){ASSERT(!e||!c);if(c)glDrawPoints(d?a.map(screenToWorld):a,b.rgbaInt());else{e||=mainContext;e.fillStyle=b;e.beginPath();for(const f of d?a:a.map(worldToScreen))e.lineTo(f.x,f.y);e.fill()}}function drawLine(a,b,c=.1,d,e,f,g){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,f,g)}function drawCanvas2D(a,b,c,d,e,f,g=mainContext){f||(a=worldToScreen(a),b=b.scale(cameraScale));g.save();g.translate(a.x+.5,a.y+.5);g.rotate(c);g.scale(d?-b.x:b.x,b.y);e(g);g.restore()}function setBlendMode(a,b=glEnable,c){ASSERT(!c||!b);b?glAdditive=a:(c||=mainContext,c.globalCompositeOperation=a?"lighter":"source-over")}function drawText(a,b,c=1,d,e=0,f,g,h,k){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,h,k)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",h=fontDefault,k=overlayContext){k.fillStyle=d;k.lineWidth=e;k.strokeStyle=f;k.textAlign=g;k.font=c+"px "+h;k.textBaseline="middle";k.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&k.strokeText(l,b.x,b.y);k.fillText(l,b.x,b.y);b.y+=c})}let engineFontImage;class FontImage{constructor(a,b=vec2(8),c=vec2(0,1),d=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.context=d}drawText(a,b,c=1,d){this.drawTextScreen(a,worldToScreen(b).floor(),c*cameraScale|0,d)}drawTextScreen(a,b,c=4,d){const e=this.context;e.save();e.imageSmoothingEnabled=!canvasPixelated;const f=this.tileSize,g=f.add(this.paddingSize).scale(c),h=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((k,l)=>{const n=d?k.length*f.x*c/2|0:0;for(let t=k.length;t--;){var m=k[t].charCodeAt();if(32>m||127<m)m=127;var p=m-32;m=p%h;p=p/h|0;const q=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,q.x-n,q.y,f.x*c,f.y*c)}});e.restore()}}function isFullscreen(){return document.fullscreenElement}function toggleFullscreen(){isFullscreen()?document.exitFullscreen&&document.exitFullscreen():document.body.requestFullscreen&&document.body.requestFullscreen()}function keyIsDown(a,b=0){return inputData[b]&&inputData[b][a]&1}function keyWasPressed(a,b=0){return inputData[b]&&inputData[b][a]&2?1:0}function keyWasReleased(a,b=0){return inputData[b]&&inputData[b][a]&4?1:0}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=0,preventDefaultInput=0;function gamepadIsDown(a,b=0){return keyIsDown(a,b+1)}function gamepadWasPressed(a,b=0){return keyWasPressed(a,b+1)}function gamepadWasReleased(a,b=0){return keyWasReleased(a,b+1)}function gamepadStick(a,b=0){return 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)};function remapKey(a){return 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;function 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)))}const stickData=[];function gamepadsUpdate(){if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),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 g=inputData[b+1]||(inputData[b+1]=[]);c=stickData[b]||(stickData[b]=[]);if(d){var e=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.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],g[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()))}}}function vibrate(a){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a,b=onmousedown,c=onmouseup;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=d=>{d.button=0;soundEnable&&(audioContext?audioContext.resume():zzfx(0));const e=d.touches.length;e?(d.x=d.touches[0].clientX,d.y=d.touches[0].clientY,a?onmousemove(d):b(d)):a&&c(d);a=e;document.hasFocus()&&d.preventDefault();return!0}}let touchGamepadTimer=new Timer,touchGamepadButtons,touchGamepadStick;function createTouchGamepad(){touchGamepadButtons=[];touchGamepadStick=vec2();const 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 g of b.touches){var f=mouseToScreen(vec2(g.clientX,g.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(vec2().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()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||0,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=0){if(soundEnable&&this.sampleChannels){var f;if(a){if(f=this.range){const g=cameraPos.distanceSquared(a);if(g>f*f)return;b*=percent(g**.5,f,f*this.taper)}f=2*worldToScreen(a).x/mainCanvas.width-1}a=c+c*this.randomness*d*rand(-1,1);return this.source=playSamples(this.sampleChannels,b,a,f,e,this.sampleRate)}}stop(){this.source&&this.source.stop();this.source=0}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isPlaying(){return this.source&&!this.source.ended}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(0,c,d);this.randomness=b;soundEnable&&(soundDecoderContext||=new AudioContext,fetch(a).then(e=>e.arrayBuffer()).then(e=>soundDecoderContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=e.getChannelData(f);this.sampleRate=e.sampleRate}))}}let soundDecoderContext;class Music extends Sound{constructor(a){super();soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}play(a,b=1){return super.play(0,a,1,1,b)}}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}function speakStop(){speechSynthesis&&speechSynthesis.cancel()}function getNoteFrequency(a,b=220){return b*2**(a/12)}let audioContext;function playSamples(a,b=1,c=1,d=0,e=0,f=zzfxR){if(soundEnable)if(audioContext||=new AudioContext,"running"!=audioContext.state)audioContext.resume();else{var g=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,k)=>g.getChannelData(k).set(h));f.buffer=g;f.playbackRate.value=c;f.loop=e;a=audioContext.createGain();a.gain.value=soundVolume*b;a.connect(audioContext.destination);f.connect(new StereoPannerNode(audioContext,{pan:clamp(d,-1,1)})).connect(a);f.start();return f}}function zzfx(...a){return playSamples([zzfxG(...a)])}const zzfxR=44100;function zzfxG(a=1,b=.05,c=220,d=0,e=0,f=.1,g=0,h=1,k=0,l=0,n=0,m=0,p=0,t=0,q=0,x=0,u=0,B=1,y=0,C=0){let v=2*PI,E=k*=500*v/zzfxR/zzfxR,A=[];b=c*=(1+b*rand(-1,1))*v/zzfxR;let w=0,F=0,r=0,z=1,H=0,I=0,D=0,J,G;d=d*zzfxR+9;y*=zzfxR;e*=zzfxR;f*=zzfxR;u*=zzfxR;l*=500*v/zzfxR**3;q*=v/zzfxR;n*=v/zzfxR;m*=zzfxR;p=p*zzfxR|0;for(G=d+y+e+f+u|0;r<G;A[r++]=D)++I%(100*x|0)||(D=g?1<g?2<g?3<g?Math.sin((w%v)**3):max(min(Math.tan(w),1),-1):1-(2*w/v%2+2)%2:1-4*abs(Math.round(w/v)-w/v):Math.sin(w),D=(p?1-C+C*Math.sin(v*r/p):1)*sign(D)*abs(D)**h*a*soundVolume*(r<d?r/d:r<d+y?1-(r-d)/y*(1-B):r<d+y+e?B:r<G-u?(G-r-u)/f*B:0),D=u?D/2+(u>r?0:(r<G-u?1:(G-r)/u)*A[r-u|0]/2):D),J=(c+=k+=l)*Math.cos(q*F++),w+=J-J*t*(1-1e9*(Math.sin(r)+1)%2),z&&++z>m&&(c+=n,b+=n,z=0),!p||++H%p||(c=b,k=E,z||=1);return A}function zzfxM(a,b,c,d=125){let e,f,g,h,k,l,n,m,p,t,q,x,u,B=0,y,C=[],v=[],E=[],A=0,w=0,F=1,r={},z=zzfxR/d*60>>2;for(;F;A++)C=[F=m=x=0],c.forEach((H,I)=>{n=b[H][A]||[0,0,0];F||=!!b[H][A];y=x+(b[H][0].length-2-!m)*z;u=I==c.length-1;e=2;for(g=x;e<n.length+u;m=++e){k=n[e];p=e==n.length+u-1&&u||t!=(n[0]||0)||k|0;for(f=0;f<z&&m;f++>z-99&&p?q+=(1>q)/99:0)l=(1-q)*C[B++]/2||0,v[g]=(v[g]||0)-l*w+l,E[g]=(E[g++]||0)+l*w+l;k&&(q=k%1,w=n[1]||0,k|=0)&&(C=r[[t=n[B=0]||0,k]]=r[[t,k]]||(h=[...a[t]],h[2]*=2**((k-12)/12),0<k?zzfxG(...h):[]))}x=y});return[v,E]}let tileCollision=[],tileCollisionSize=vec2();function initTileCollision(a){tileCollisionSize=a;tileCollision=[];for(a=tileCollision.length=tileCollisionSize.area();a--;)tileCollision[a]=0}function setTileCollisionData(a,b=0){a.arrayCheck(tileCollisionSize)&&(tileCollision[(a.y|0)*tileCollisionSize.x+a.x|0]=b)}function getTileCollisionData(a){return 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 g=tileCollision[e*tileCollisionSize.x+b];if(g&&(!c||c.collideWithTile(g,vec2(b,e))))return 1}}function tileCollisionRaycast(a,b,c){const d=b.subtract(a),e=d.length();var f=d.normalize();f=vec2(abs(1/f.x),abs(1/f.y));let g=a.floor(),h=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),k=f.y*(0>d.y?a.y-g.y:g.y-a.y+1);for(;;){const l=getTileCollisionData(g);if(l&&(!c||c.collideWithTile(l,g)))return debugRaycast&&debugLine(a,b,"#f00",.02),debugRaycast&&debugPoint(g.add(vec2(.5)),"#ff0"),g.add(vec2(.5));if(h>e&&k>e)break;h>k?(g.y+=sign(d.y),k+=f.y):(g.x+=sign(d.x),h+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}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=tile(),d=vec2(1),e=0){super(a,b,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.tileInfo.size.x;a&&(mainCanvas.width=this.size.x*this.tileInfo.size.x,mainCanvas.height=this.size.y*this.tileInfo.size.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);if(void 0!=a.tile){ASSERT(mainContext==this.context);const c=tile(a.tile,this.tileInfo.size,this.tileInfo.textureIndex);drawTile(b,vec2(1),c,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.tileInfo.size);b=b.multiply(this.tileInfo.size);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,d=new Color,e,f){this.drawCanvas2D(a,b,e,f,g=>{const h=c&&c.getTextureInfo();h?(g.globalAlpha=d.a,g.drawImage(h.image,c.pos.x,c.pos.y,c.size.x,c.size.y,-.5,-.5,1,1),g.globalAlpha=1):(g.fillStyle=d,g.fillRect(-.5,-.5,1,1))})}drawRect(a,b,c,d){this.drawTile(a,b,-1,0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,h=new Color,k=new Color,l=new Color(1,1,1,0),n=new Color(1,1,1,0),m=.5,p=.1,t=1,q=.1,x=.05,u=1,B=1,y=0,C=PI,v=.1,E=.2,A,w,F=1,r=w?1e9:0,z){super(a,vec2(),g,b,void 0,r);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=h;this.colorStartB=k;this.colorEndA=l;this.colorEndB=n;this.randomColorLinear=F;this.particleTime=m;this.sizeStart=p;this.sizeEnd=t;this.speed=q;this.angleSpeed=x;this.damping=u;this.angleDamping=B;this.gravityScale=y;this.particleConeAngle=C;this.fadeRate=v;this.randomness=E;this.collideTiles=A;this.additive=w;this.localSpace=z;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?vec2(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.tileInfo,this.tileSize,b);const c=this.randomness;var d=n=>n+n*rand(c,-c);b=d(this.particleTime);const e=d(this.sizeStart),f=d(this.sizeEnd),g=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const k=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),l=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a.colorStart=k;a.colorEndDelta=l.subtract(k);a.velocity=vec2().setAngle(h,g);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){super(a,vec2(),b,c)}render(){const a=min((time-this.spawnTime)/this.lifeTime,1),b=vec2(this.sizeStart+a*this.sizeEndDelta);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,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));var g=f.length();g&&(f=f.scale(1/g),g*=this.trailScale,b.y=max(b.x,g),e=f.angle(),drawTile(d.add(f.multiply(vec2(0,-g/2))),b,this.tileInfo,c,e,this.mirror))}else drawTile(d,b,this.tileInfo,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)}}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,c){newgrounds=new Newgrounds(a,b,c)}class Newgrounds{constructor(a,b,c){ASSERT(!newgrounds&&a);ASSERT(!b||c);this.app_id=a;this.cipher=b;this.cryptoJS=c;this.host=location?location.hostname:"";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 d of this.medals)if(a=medals[d.id])a.image=new Image,a.image.src=d.icon,a.name=d.name,a.description=d.description,a.unlocked=d.unlocked,a.difficulty=d.difficulty,a.value=d.value,a.value&&(a.description=a.description+" ("+a.value+")");this.scoreboards=(d=this.call("ScoreBoard.getBoards"))?d.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)}}let glCanvas,glContext,glActiveTexture,glShader,glArrayBuffer,glPositionData,glColorData,glBatchCount,glBatchAdditive,glAdditive;function glInit(){glCanvas=document.createElement("canvas");glContext=glCanvas.getContext("webgl2");glOverlay&&document.body.appendChild(glCanvas);glShader=glCreateProgram("#version 300 es\nprecision highp float;uniform mat4 m;in vec4 p,c,a;out vec4 v,d,e;void main(){gl_Position=m*vec4(p.xy,1,1);v=p;d=c;e=a;}","#version 300 es\nprecision highp float;in vec4 v,d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(s,v.zw)*d+e;}");const a=new ArrayBuffer(gl_VERTEX_BUFFER_SIZE);glArrayBuffer=glContext.createBuffer();glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glBatchCount=0}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=textureInfos[0].glTexture);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_VERTEX_BUFFER_SIZE,gl_DYNAMIC_DRAW);let a=glAdditive=0;var b=(f,g,h,k,l=0)=>{f=glContext.getAttribLocation(glShader,f);glContext.enableVertexAttribArray(f);glContext.vertexAttribPointer(f,k,g,l,gl_VERTEX_BYTE_STRIDE,a);a+=k*h};b("p",gl_FLOAT,4,4);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,d=-1-b*cameraPos.x,e=-1-c*cameraPos.y;glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),0,new Float32Array([b,0,0,0,0,c,0,0,1,1,-1,1,d,e,0,0]))}function glSetTexture(a){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=canvasPixelated?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 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_INDICIES_PER_VERT));glContext.drawArrays(gl_TRIANGLE_STRIP,0,glBatchCount);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,g,h,k,l,n=0){(glBatchCount>=gl_MAX_BATCH-6||glBatchAdditive!=glAdditive)&&glFlush();var m=Math.cos(e)/2;const p=Math.sin(e)/2;e=m*c;m*=d;c*=p;d*=p;a=[a-e+d,b+m+c,f,g,a-e-d,b-m+c,f,k,a+e+d,b+m-c,h,g,a+e-d,b-m-c,h,k];for(let t=6,q=glBatchCount*gl_INDICIES_PER_VERT;t--;)b=4*clamp(t-1,0,3),glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glPositionData[q++]=a[b++],glColorData[q++]=l,glColorData[q++]=n;glBatchCount+=6}function glDrawPoints(a,b){const c=a.length+2;(glBatchCount>=gl_MAX_BATCH-c||glBatchAdditive!=glAdditive)&&glFlush();for(let e=c,f=glBatchCount*gl_INDICIES_PER_VERT;e--;){var d=clamp(e-1,0,c-3);const g=d>>1;d=a[d%2?g:c-3-g];glPositionData[f++]=d.x;glPositionData[f++]=d.y;glPositionData[f++]=0;glPositionData[f++]=0;glColorData[f++]=0;glColorData[f++]=b}glBatchCount+=c}let glPostShader,glPostArrayBuffer,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b){ASSERT(!glPostShader);a||="void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}";glPostShader=glCreateProgram("#version 300 es\nprecision highp float;in vec2 p;void main(){gl_Position=vec4(p,1,1);}","#version 300 es\nprecision highp float;uniform sampler2D iChannel0;uniform vec3 iResolution;uniform float iTime;out vec4 c;\n"+a+"\nvoid main(){mainImage(c,gl_FragCoord.xy);c.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_TRIANGLE_STRIP,0,3)}}const gl_ONE=1,gl_TRIANGLE_STRIP=5,gl_SRC_ALPHA=770,gl_ONE_MINUS_SRC_ALPHA=771,gl_BLEND=3042,gl_TEXTURE_2D=3553,gl_UNSIGNED_BYTE=5121,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_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_INDICIES_PER_VERT=6,gl_MAX_BATCH=1e5,gl_VERTEX_BYTE_STRIDE=24,gl_VERTEX_BUFFER_SIZE=gl_MAX_BATCH*gl_VERTEX_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.8.4",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=0;function setPaused(a){paused=a}let frameTimeLastMS=0,frameTimeBufferMS=0,averageFPS=0;function engineInit(a,b,c,d,e,f=["tiles.png"]){function g(h=0){var k=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(k||1));h=debug&&keyIsDown(107);const l=debug&&keyIsDown(109);debug&&(k*=h?5:l?.2:1);timeReal+=k/1e3;frameTimeBufferMS+=!paused*k;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));canvasFixedSize.x?(mainCanvas.width=canvasFixedSize.x,mainCanvas.height=canvasFixedSize.y,k=innerWidth/innerHeight,h=mainCanvas.width/mainCanvas.height,(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=k<h?"100%":"",(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=k<h?"":"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{k=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(k=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=k}enginePreRender();d();engineObjects.sort((m,p)=>m.renderOrder-p.renderOrder);for(var n of engineObjects)n.destroyed||n.render();e();glRenderPostProcess();medalsRender();touchGamepadRender();debugRender();glEnable&&glCopyToContext(mainContext);showWatermark&&(overlayContext.textAlign="right",overlayContext.textBaseline="top",overlayContext.font="1em monospace",overlayContext.fillStyle="#000",n=engineName+" v"+engineVersion+" / "+drawCount+" / "+engineObjects.length+" / "+averageFPS.toFixed(1)+(glEnable?" GL":" 2D"),overlayContext.fillText(n,mainCanvas.width-3,3),overlayContext.fillStyle="#fff",overlayContext.fillText(n,mainCanvas.width-2,2),drawCount=0);requestAnimationFrame(g)}ASSERT(Array.isArray(f));document.body.style="margin:0;overflow:hidden;background:#000;touch-action:none;user-select:none;-webkit-user-select:none;-webkit-touch-callout: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%);"+(canvasPixelated?"image-rendering:pixelated":"");Promise.all(f.map((h,k)=>new Promise((l,n)=>{const m=new Image;m.onerror=m.onload=()=>{textureInfos[k]=new TextureInfo(m);l()};m.src=h}))).then(()=>{a();g()})}function enginePreRender(){mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender()}function engineObjectsUpdate(){function a(b){if(!b.destroyed){b.update();for(const c of b.children)a(c)}}engineObjectsCollide=engineObjects.filter(b=>b.collideSolidObjects);for(const b of engineObjects)b.parent||a(b);engineObjects=engineObjects.filter(b=>!b.destroyed)}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)}