littlejsengine 1.8.1 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/build/littlejs.d.ts +509 -509
- package/build/littlejs.esm.js +140 -127
- package/build/littlejs.esm.min.js +1 -1
- package/build/littlejs.js +57 -44
- package/build/littlejs.min.js +1 -1
- package/build/littlejs.release.js +57 -44
- package/examples/breakout/index.html +3 -3
- package/examples/breakoutTutorial/README.md +1 -1
- package/examples/breakoutTutorial/index.html +2 -2
- package/examples/electron/index.html +2 -2
- package/examples/js13k/index.html +13 -13
- package/examples/module/game.js +1 -1
- package/examples/module/index.html +1 -1
- package/examples/particles/index.html +1 -1
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/index.html +2 -2
- package/examples/starter/index.html +13 -13
- package/examples/stress/index.html +3 -3
- package/examples/typescript/game.ts +1 -1
- package/examples/typescript/index.html +1 -1
- package/package.json +2 -1
- package/src/engine.js +2 -2
- package/src/engineAudio.js +2 -1
- package/src/engineDraw.js +35 -18
- package/src/engineExport.js +83 -83
- package/src/engineObject.js +1 -0
- package/src/engineWebGL.js +17 -23
|
@@ -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)}export{setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCanvasPixelated,setFontDefault,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setDebugKey,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,cameraPos,cameraScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,debug,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,PI,abs,min,max,sign,mod,clamp,percent,distanceWrap,lerpWrap,distanceAngle,lerpAngle,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,RandomGenerator,Vector2,Color,Timer,vec2,rgb,hsl,EngineObject,textureInfos,tile,TileInfo,TextureInfo,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds,glCanvas,glContext,glSetBlendMode,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback};
|
|
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],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.3",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)}export{engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback,debug,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,cameraPos,cameraScale,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,tileSizeDefault,tileFixBleedScale,enablePhysicsSolver,objectDefaultMass,objectDefaultDamping,objectDefaultAngleDamping,objectDefaultElasticity,objectDefaultFriction,objectMaxSpeed,gravity,particleEmitRateScale,glEnable,glOverlay,gamepadsEnable,gamepadDirectionEmulateStick,inputWASDEmulateDirection,touchGamepadEnable,touchGamepadAnalog,touchGamepadSize,touchGamepadAlpha,vibrateEnable,soundEnable,soundVolume,soundDefaultRange,soundDefaultTaper,medalDisplayTime,medalDisplaySlideTime,medalDisplaySize,medalDisplayIconSize,setCameraPos,setCameraScale,setCanvasMaxSize,setCanvasFixedSize,setCanvasPixelated,setFontDefault,setGlEnable,setGlOverlay,setTileSizeDefault,setTileFixBleedScale,setEnablePhysicsSolver,setObjectDefaultMass,setObjectDefaultDamping,setObjectDefaultAngleDamping,setObjectDefaultElasticity,setObjectDefaultFriction,setObjectMaxSpeed,setGravity,setParticleEmitRateScale,setGamepadsEnable,setGamepadDirectionEmulateStick,setInputWASDEmulateDirection,setTouchGamepadEnable,setTouchGamepadAnalog,setTouchGamepadSize,setTouchGamepadAlpha,setVibrateEnable,setSoundEnable,setSoundVolume,setSoundDefaultRange,setSoundDefaultTaper,setMedalDisplayTime,setMedalDisplaySlideTime,setMedalDisplaySize,setMedalDisplayIconSize,setMedalsPreventUnlock,setShowWatermark,setDebugKey,PI,abs,min,max,sign,mod,clamp,percent,distanceWrap,lerpWrap,distanceAngle,lerpAngle,lerp,smoothStep,nearestPowerOfTwo,isOverlapping,wave,formatTime,rand,randInt,randSign,randInCircle,randVector,randColor,RandomGenerator,Vector2,Color,Timer,vec2,rgb,hsl,textureInfos,tile,TileInfo,TextureInfo,mainCanvas,mainContext,overlayCanvas,overlayContext,mainCanvasSize,screenToWorld,worldToScreen,drawTile,drawRect,drawLine,drawCanvas2D,setBlendMode,drawTextScreen,drawText,engineFontImage,FontImage,isFullscreen,toggleFullscreen,glCanvas,glContext,glSetTexture,glCompileShader,glCreateProgram,glCreateTexture,glInitPostProcess,keyIsDown,keyWasPressed,keyWasReleased,clearInput,mouseIsDown,mouseWasPressed,mouseWasReleased,mousePos,mousePosScreen,mouseWheel,isUsingGamepad,preventDefaultInput,gamepadIsDown,gamepadWasPressed,gamepadWasReleased,gamepadStick,mouseToScreen,gamepadsUpdate,vibrate,vibrateStop,isTouchDevice,Sound,Music,playAudioFile,speak,speakStop,getNoteFrequency,audioContext,playSamples,zzfx,EngineObject,tileCollision,tileCollisionSize,initTileCollision,setTileCollisionData,getTileCollisionData,tileCollisionTest,tileCollisionRaycast,TileLayerData,TileLayer,ParticleEmitter,Particle,medals,medalsPreventUnlock,medalsInit,newgroundsInit,Medal,Newgrounds};
|
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 (
|
|
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
|
-
},
|
|
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
|
-
{
|
|
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
|
-
|
|
2171
|
-
|
|
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
|
-
|
|
2174
|
-
|
|
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
|
|
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
|
-
|
|
2225
|
-
|
|
2237
|
+
ASSERT(!context || !useWebGL); // context only supported in canvas 2D mode
|
|
2238
|
+
if (useWebGL)
|
|
2239
|
+
glAdditive = additive;
|
|
2226
2240
|
else
|
|
2227
|
-
|
|
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]
|
|
2897
|
+
this.randomness = zzfxSound[1];
|
|
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
|
|
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=
|
|
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.
|
|
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
|
-
|
|
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,
|
|
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,
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
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
|
|
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.
|
|
4815
|
+
const engineVersion = '1.8.3';
|
|
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 {
|
|
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
|
{
|