littlejsengine 1.9.4 → 1.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LittleJS.zip +0 -0
- package/dist/littlejs.d.ts +16 -18
- package/dist/littlejs.esm.js +131 -56
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +131 -56
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +130 -55
- package/examples/platformer/gameEffects.js +2 -3
- package/package.json +1 -1
- package/reference.md +11 -11
- package/src/engine.js +66 -33
- package/src/engineBuild.js +4 -4
- package/src/engineDebug.js +1 -1
- package/src/engineObject.js +9 -11
- package/src/engineTileLayer.js +6 -3
- package/src/engineUtilities.js +49 -8
package/dist/littlejs.esm.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let showWatermark=0,debugKey="";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){return 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=vec2()){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=!1){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"number"===typeof a?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return a instanceof Vector2}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){ASSERT(isVector2(a));return this.distanceSquared(a)**.5}distanceSquared(a){ASSERT(isVector2(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)}setDirection(a,b=1){ASSERT(0==a||1==a||2==a||3==a);return vec2(a%2?a-1?-b:b:0,a%2?0:a?-b: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){ASSERT(isVector2(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)}function isColor(a){return a instanceof Color}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){ASSERT(isColor(a));return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){ASSERT(isColor(a));return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){ASSERT(isColor(a));return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){ASSERT(isColor(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){ASSERT(isColor(a));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,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}HSLA(){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 k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,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=!0){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)<<8,c=255*clamp(this.b)<<16,d=255*clamp(this.a)<<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=!0,fontDefault="arial",showSplashScreen=!1,glEnable=!0,glOverlay=!0,tileSizeDefault=vec2(16),tileFixBleedScale=.1,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock=!1;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 setShowSplashScreen(a){showSplashScreen=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),"ensure pos and size are vec2s");ASSERT("number"!==typeof c||!c,"old style tile setup");this.pos=a.copy();this.size=b;this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor=void 0;this.mirror=!1;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.parent=void 0;this.localPos=vec2();this.localAngle=0;this.isSolid=this.collideSolidObjects=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 k=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||!k)if(this.pos.y=d.pos.y+(e.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-c;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const h=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,h)}!f&&k&&(this.pos.x=d.pos.x+(e.x/2+.001)*sign(a.x-d.pos.x),d.mass?(e=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),this.velocity.x=lerp(c,e,this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass)),d.velocity.x=lerp(c,e,f)):this.velocity.x*=-c);debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}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!0}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=!0,b=!0,c=!0){ASSERT(a||!b,"solid objects must be set to collide");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){"number"===typeof b&&(ASSERT(0<b),b=vec2(b));if("number"===typeof a){var d=textureInfos[c];ASSERT(d,"Texture not loaded");d=d.size.x/b.x|0;a=vec2(a%d*b.x,(a/d|0)*b.y)}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)}frame(a){ASSERT("number"==typeof a);return this.offset(vec2(a*this.size.x,0))}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 getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),k=glEnable,h,l){ASSERT(!l||!k,"context only supported in canvas 2D mode");ASSERT("number"!==typeof c||!c,"this is an old style calls, to fix replace it with tile(tileIndex, tileSize)");const n=c&&c.getTextureInfo();if(k)if(h&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),n){k=c.pos.x/n.size.x;h=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,k+p.x,h+p.y,k-p.x+l,h-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 showWatermark&&++drawCount,drawCanvas2D(a,b,e,f,m=>{if(n){const p=c.pos.x+tileFixBleedScale,t=c.pos.y+tileFixBleedScale,u=c.size.x-2*tileFixBleedScale,x=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(n.image,p,t,u,x,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},h,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}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,"context only supported in canvas 2D mode");b?glAdditive=a:(c||=mainContext,c.globalCompositeOperation=a?"lighter":"source-over")}function drawText(a,b,c=1,d,e=0,f,g,k,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,h)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d.toString();h.lineWidth=e;h.strokeStyle=f.toString();h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.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),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const n=d?h.length*f.x*c/2|0:0;for(let t=h.length;t--;){var m=h[t].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%k;p=p/k|0;const u=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,u.x-n,u.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){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&1)}function keyWasPressed(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&2)}function keyWasReleased(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,preventDefaultInput=!1;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||(isUsingGamepad=!1,inputData[0][a.code]=3,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=3)),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][a.code]=4,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=4))};function remapKey(a){return inputWASDEmulateDirection?"KeyW"==a?"ArrowUp":"KeyS"==a?"ArrowDown":"KeyA"==a?"ArrowLeft":"KeyD"==a?"ArrowRight":a:a}onmousedown=a=>{isUsingGamepad=!1;inputData[0][a.button]=3;mousePosScreen=mouseToScreen(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>mouseWheel=a.ctrlKey?0: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(){const a=g=>{const k=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;return vec2(k(g.x),k(-g.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),touchGamepadTimer.isSet())){var b=stickData[0]||(stickData[0]=[]);b[0]=vec2();touchGamepadAnalog?b[0]=a(touchGamepadStick):.3<touchGamepadStick.lengthSquared()&&(b[0].x=Math.round(touchGamepadStick.x),b[0].y=-Math.round(touchGamepadStick.y),b[0]=b[0].clampLength());b=inputData[1]||(inputData[1]=[]);for(var c=10;c--;){var d=3==c?2:2==c?3:c;b[d]=touchGamepadButtons[c]?gamepadIsDown(d,0)?1:3:gamepadIsDown(d,0)?4:0}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){var e=b[c];const g=inputData[c+1]||(inputData[c+1]=[]);d=stickData[c]||(stickData[c]=[]);if(e){for(var f=0;f<e.axes.length-1;f+=2)d[f>>1]=a(vec2(e.axes[f],e.axes[f+1]));for(f=e.buttons.length;f--;){const k=e.buttons[f],h=gamepadIsDown(f,c);g[f]=k.pressed?h?1:3:h?4:0;isUsingGamepad||=!c&&k.pressed}gamepadDirectionEmulateStick&&(e=vec2((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1)),e.lengthSquared()&&(d[0]=e.clampLength()));touchGamepadEnable&&isUsingGamepad&&touchGamepadTimer.unset()}}}function vibrate(a=100){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=b=>{soundEnable&&audioContext&&"running"!=audioContext.state&&zzfx(0);const c=b.touches.length;if(c){const d=vec2(b.touches[0].clientX,b.touches[0].clientY);mousePosScreen=mouseToScreen(d);a?isUsingGamepad=!1:inputData[0][0]=3}else a&&(inputData[0][0]=inputData[0][0]&2|4);a=c;document.hasFocus()&&b.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?touchGamepadStick=f.subtract(c).scale(2/touchGamepadSize).clampLength():f.distance(d)<touchGamepadSize?(f=f.subtract(d).direction(),touchGamepadButtons[f]=1):f.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)}a.bind(window)(b);return isUsingGamepad=!0}}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),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().setDirection(b,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||0,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=!1){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=void 0}getSource(){return this.source}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(void 0,c,d);this.randomness=b;soundEnable&&fetch(a).then(e=>e.arrayBuffer()).then(e=>audioContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=Array.from(e.getChannelData(f));this.sampleRate=e.sampleRate})}}class Music extends Sound{constructor(a){super(void 0);soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}playMusic(a,b=!1){return super.play(void 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=new AudioContext,audioSuspended=!1;function playSamples(a,b=1,c=1,d=0,e=!1,f=zzfxR){if(soundEnable){var g=audioSuspended;if(audioSuspended="running"!=audioContext.state)if(audioContext.resume(),g)return;var k=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,l)=>k.getChannelData(l).set(h));f.buffer=k;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,k=1,h=0,l=0,n=0,m=0,p=0,t=0,u=0,x=0,v=0,D=1,z=0,E=0,A=0){let w=2*PI;var q=zzfxR;let F=h*=500*w/q/q;b=c*=rand(1+b,1-b)*w/q;let C=[],y=0,G=0,r=0,H=1,R=0,S=0,B=0,J;var L=w*abs(A)*2/q,K=Math.cos(L),M=Math.sin(L)/2/2,I=1+M;L=-2*K/I;M=(1-M)/I;let N=(1+sign(A)*K)/2/I;K=-(sign(A)+K)/I;let O=I=0,P=0,Q=0;d=d*q+9;z*=q;e*=q;f*=q;v*=q;l*=500*w/q**3;u*=w/q;n*=w/q;m*=q;p=p*q|0;a*=soundVolume;for(J=d+z+e+f+v|0;r<J;C[r++]=B*a)++S%(100*x|0)||(B=g?1<g?2<g?3<g?Math.sin(y**3):clamp(Math.tan(y),1,-1):1-(2*y/w%2+2)%2:1-4*abs(Math.round(y/w)-y/w):Math.sin(y),B=(p?1-E+E*Math.sin(w*r/p):1)*sign(B)*abs(B)**k*(r<d?r/d:r<d+z?1-(r-d)/z*(1-D):r<d+z+e?D:r<J-v?(J-r-v)/f*D:0),B=v?B/2+(v>r?0:(r<J-v?1:(J-r)/v)*C[r-v|0]/2/a):B,A&&(B=Q=N*I+K*(I=O)+N*(O=B)-M*P-L*(P=Q))),q=(c+=h+=l)*Math.cos(u*G++),y+=q+q*t*Math.sin(r**5),H&&++H>m&&(c+=n,b+=n,H=0),!p||++R%p||(c=b,h=F,H=H||1);return C}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,n,m,p,t,u,x,v,D=0,z,E=[],A=[],w=[],q=0,F=0,C=1,y={},G=zzfxR/d*60>>2;for(;C;q++)E=[C=m=x=0],c.forEach((r,H)=>{n=b[r][q]||[0,0,0];C|=b[r][q]&&1;z=x+(b[r][0].length-2-(m?0:1))*G;v=H==c.length-1;e=2;for(g=x;e<n.length+v;m=++e){h=n[e];p=e==n.length+v-1&&v||t!=(n[0]||0)||h|0;for(f=0;f<G&&m;f++>G-99&&p&&1>u?u+=1/99:0)l=(1-u)*E[D++]/2||0,A[g]=(A[g]||0)-l*F+l,w[g]=(w[g++]||0)+l*F+l;h&&(u=h%1,F=n[1]||0,h|=0)&&(E=y[[t=n[D=0]||0,h]]=y[[t,h]]||(k=[...a[t]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}x=z});return[A,w]}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!0}}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(),k=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),h=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(k>e&&h>e)break;k>h?(g.y+=sign(d.y),h+=f.y):(g.x+=sign(d.x),k+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=0;this.mirror=!1;this.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=!1;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c=!1){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,"must call redrawEnd() after drawing tiles");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(!0);for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b),!1);this.redrawEnd()}redrawStart(a=!1){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;mainCanvasSize=this.size.multiply(this.tileInfo.size);cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;a&&(mainCanvas.width=mainCanvasSize.x,mainCanvas.height=mainCanvasSize.y);enginePreRender()}redrawEnd(){ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles");glEnable&&glCopyToContext(mainContext,!0);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a,b=!0){var c=this.tileInfo.size;b&&(b=a.multiply(c),this.context.clearRect(b.x,this.canvas.height-b.y,c.x,-c.y));b=this.getData(a);void 0!=b.tile&&(a=this.pos.add(a).add(vec2(.5)),ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles"),c=tile(b.tile,c,this.tileInfo.textureIndex),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}drawCanvas2D(a,b,c,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 k=c&&c.getTextureInfo();k?(g.globalAlpha=d.a,g.drawImage(k.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,void 0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,k=new Color,h=new Color,l=new Color(1,1,1,0),n=new Color(1,1,1,0),m=.5,p=.1,t=1,u=.1,x=.05,v=1,D=1,z=0,E=PI,A=.1,w=.2,q=!1,F=!1,C=!0,y=F?1e9:0,G=!1){super(a,vec2(),g,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=h;this.colorEndA=l;this.colorEndB=n;this.randomColorLinear=C;this.particleTime=m;this.sizeStart=p;this.sizeEnd=t;this.speed=u;this.angleSpeed=x;this.damping=v;this.angleDamping=D;this.gravityScale=z;this.particleConeAngle=E;this.fadeRate=A;this.randomness=w;this.collideTiles=q;this.additive=F;this.localSpace=G;this.trailScale=0;this.particleCreateCallback=this.particleDestroyCallback=void 0;this.emitTimeBuffer=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="number"===typeof this.emitSize?randInCircle(this.emitSize/2):vec2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle);let b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);const c=this.randomness;var d=m=>m+m*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),k=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a=new Particle(a,this.tileInfo,b,l,n,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(h,k);a.angleVelocity=d;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.renderOrder=this.renderOrder;a.mirror=!!randInt(2);this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,k,h,l,n,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=k-g;this.fadeRate=h;this.additive=l;this.trailScale=n;this.localSpaceEmitter=m;this.destroyCallback=p}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(!0);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,"save name must be set"),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).toString();b.strokeStyle=new Color(0,0,0).toString();b.lineWidth=3;b.rect(d,a,c,medalDisplaySize.y);b.fill();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,void 0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,void 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)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();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&&0<a,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");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,!0),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},!0)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},!0)}getScores(a,b,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},!0)}call(a,b,c=!1){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,glShader,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glInstanceCount,glAdditive,glBatchAdditive;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 g;in vec4 p,u,c,a;in float r;out vec2 v;out vec4 d,e;void main(){vec2 s=(g-.5)*p.zw;gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);v=mix(u.xw,u.zy,g);d=c;e=a;}","#version 300 es\nprecision highp float;in vec2 v;in vec4 d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(s,v)*d+e;}");var a=new ArrayBuffer(gl_INSTANCE_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(gl_ARRAY_BUFFER,a,gl_STATIC_DRAW)}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);let a=glAdditive=glBatchAdditive=0;var b=(d,e,f,g)=>{d=glContext.getAttribLocation(glShader,d);const k=f&&gl_INSTANCE_BYTE_STRIDE,h=f&&1,l=1==f;glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,l,k,a);glContext.vertexAttribDivisor(d,h);a+=g*f};glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);b("g",gl_FLOAT,0,2);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_INSTANCE_BUFFER_SIZE,gl_DYNAMIC_DRAW);b("p",gl_FLOAT,4,4);b("u",gl_FLOAT,4,4);b("c",gl_UNSIGNED_BYTE,1,4);b("a",gl_UNSIGNED_BYTE,1,4);b("r",gl_FLOAT,4,1);b=vec2(2*cameraScale).divide(mainCanvasSize);const c=vec2(-1).subtract(cameraPos.multiply(b));glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),!1,new Float32Array([b.x,0,0,0,0,b.y,0,0,1,1,1,1,c.x,c.y,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&&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);return b}function glFlush(){if(glInstanceCount){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);glContext.drawArraysInstanced(gl_TRIANGLE_STRIP,0,4,glInstanceCount);showWatermark&&(drawCount+=glInstanceCount);glInstanceCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b=!1){if(glInstanceCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,n=0){ASSERT("number"==typeof l&&"number"==typeof n,"invalid color");(glInstanceCount>=gl_MAX_INSTANCES||glBatchAdditive!=glAdditive)&&glFlush();let m=glInstanceCount*gl_INDICIES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=k;glPositionData[m++]=h;glColorData[m++]=l;glColorData[m++]=n;glPositionData[m++]=e;glInstanceCount++}let glPostShader,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b=!1){ASSERT(!glPostShader,"can only have 1 post effects shader");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+p-1.,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.;}");glPostTexture=glCreateTexture(void 0);glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden";glPostIncludeOverlay&&(overlayCanvas.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);glContext.useProgram(glPostShader);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,1);glContext.disable(gl_BLEND);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,!1,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,4)}}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_COLOR_BUFFER_BIT=16384,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_INSTANCE=11,gl_MAX_INSTANCES=1e4,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICIES_PER_INSTANCE,gl_INSTANCE_BUFFER_SIZE=gl_MAX_INSTANCES*gl_INSTANCE_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.9.4",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;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 l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(l||1));h=debug&&keyIsDown("Equal");const n=debug&&keyIsDown("Minus");debug&&(l*=h?5:n?.2:1);timeReal+=l/1e3;frameTimeBufferMS+=paused?0:l;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));k();if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{l=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(l=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=l}enginePreRender();d();engineObjects.sort((p,t)=>p.renderOrder-t.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)}function k(){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const h=innerWidth/innerHeight,l=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=h<l?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=h<l?"":"100%"}else 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)}ASSERT(Array.isArray(f),"pass in images as array");document.body.style.cssText="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.cssText=mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";k();f=f.map((h,l)=>new Promise(n=>{const m=new Image;m.onerror=m.onload=()=>{textureInfos[l]=new TextureInfo(m);n()};m.src=h}));showSplashScreen&&f.push(new Promise(h=>{function l(){clearInput();drawEngineSplashScreen(n+=.01);1<n?h():setTimeout(l,16)}let n=0;console.log(`${engineName} Engine v${engineVersion}`);l()}));Promise.all(f).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("object"===typeof b)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)}function drawEngineSplashScreen(a){const b=overlayContext;var c=overlayCanvas.width=innerWidth,d=overlayCanvas.height=innerHeight,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.7*Math.hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(f,0,e/2),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(h,l,n,m,p)=>{b.beginPath();b.rect(h,l,n,p?m*k:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(h,l,n,m=0,p=2*PI,t,u)=>{const x=(m+p)/2;m=k*(p-m)/2;b.beginPath();u&&b.lineTo(h,l);b.arc(h,l,n,x-m,x+m);(b.fillStyle=t)?b.fill():b.stroke()};e=(h=0,l=0)=>hsl([.98,.3,.57,.14][h%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const k=percent(a,.1,.5);b.translate(c/2,d/2);c=min(6,min(c,d)/99);b.scale(c,c);b.translate(-40,-35);b.lineJoin=b.lineCap="round";b.lineWidth=.1+1.9*k;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,17,18,-8,e(2,2));g(7,9,18,4,e(2,3));g(25,9,8,8,e(2,1));g(25,9,-18,8);g(25,9,8,8);g(25,17,7,22,e());g(11,40,14,-23,e(1,1));g(11,17,14,17,e(1,2));g(11,17,14,9,e(1,3));g(15,31,6,-9,e(2,2));f(15,23,5,0,PI/2,e(2,4),1);g(25,17,-14,23);g(21,22,-6,9);g(37,14,9,6,e(3,2));g(37,14,4.5,6,e(3,3));g(37,14,9,6);g(50,20,10,-10,e(0,1));g(50,20,6.5,-10,e(0,2));g(50,20,3.5,-10,e(0,3));g(50,20,10,-10);f(55,2,11.4,.5,PI-.5,e(3,3));f(55,2,11.4,.5,PI/2,e(3,2),1);f(55,2,11.4,.5,PI-.5);g(45,7,20,-7,e(0,2));g(45,0,20,3,e(0,3));g(45,0,20,7);for(c=5;c--;)f(60-6*c,30,9.9,0,2*PI,e(c+2,3)),f(60-6*c,30,10,-.5,PI+.5,e(c+2,2)),f(60-6*c,30,10.1,.5,PI-.5,e(c+2,1));f(36,30,10,PI/2,3*PI/2);f(48,30,10,PI/2,3*PI/2);f(60,30,10);b.beginPath();b.lineTo(36,20);b.lineTo(60,20);b.stroke();f(60,30,4,PI,3*PI,e(3,2));f(60,30,4,PI,2*PI,e(3,3));f(60,30,4,PI,3*PI);for(c=6;c--;)b.beginPath(),b.lineTo(53,54),b.lineTo(53,40),b.lineTo(53+(1+2.9*c)*k,40),b.lineTo(53+(4+3.5*c)*k,54),b.fillStyle=e(0,c%2+2),b.fill(),c%2&&b.stroke();g(6,40,5,5);g(6,40,5,5,e());g(15,54,38,-14,e());for(g=3;g--;)for(c=2;c--;)f(15*g+15,47,c?7:1,PI,3*PI,e(g,3)),b.stroke(),f(15*g+15,47,c?7:1,0,PI,e(g,2)),b.stroke();b.beginPath();b.lineTo(6,40);b.lineTo(68,40);b.stroke();b.beginPath();b.lineTo(77,54);b.lineTo(4,54);b.stroke();f=engineName;b.font="900 16px arial";b.textAlign="center";b.textBaseline="top";b.lineWidth=.1+3.9*k;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let h=0,l=41-g/2;h<f.length;++h)b.fillStyle=e(h,2),d=b.measureText(f[h]).width,b[c?"strokeText":"fillText"](f[h],l+d/2,55.5,17*k),l+=d;b.restore()}export{engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback,debug,debugOverlay,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,cameraPos,cameraScale,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,showSplashScreen,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,setShowSplashScreen,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,SoundWave,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};
|
|
1
|
+
let showWatermark=0,debugKey="";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){return 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=vec2()){return 2*abs(a.x-c.x)<b.x+d.x&&2*abs(a.y-c.y)<b.y+d.y}function isIntersecting(a,b,c,d){c=c.subtract(d.scale(.5));d=c.add(d);b=b.subtract(a);c=a.subtract(c);d=a.subtract(d);a=[-b.x,b.x,-b.y,b.y];b=[c.x,-d.x,c.y,-d.y];c=0;d=1;for(let e=4;e--;)if(a[e]){const f=b[e]/a[e];if(0>a[e]){if(f>d)return!1;c=max(f,c)}else{if(f<c)return!1;d=min(f,d)}}else if(0>b[e])return!1;return!0}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=!1){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"number"===typeof a?new Vector2(a,void 0==b?a:b):new Vector2(a.x,a.y)}function isVector2(a){return a instanceof Vector2}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){ASSERT(isVector2(a));return this.distanceSquared(a)**.5}distanceSquared(a){ASSERT(isVector2(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)}setDirection(a,b=1){ASSERT(0==a||1==a||2==a||3==a);return vec2(a%2?a-1?-b:b:0,a%2?0:a?-b: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){ASSERT(isVector2(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)}function isColor(a){return a instanceof Color}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){ASSERT(isColor(a));return new Color(this.r+a.r,this.g+a.g,this.b+a.b,this.a+a.a)}subtract(a){ASSERT(isColor(a));return new Color(this.r-a.r,this.g-a.g,this.b-a.b,this.a-a.a)}multiply(a){ASSERT(isColor(a));return new Color(this.r*a.r,this.g*a.g,this.b*a.b,this.a*a.a)}divide(a){ASSERT(isColor(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){ASSERT(isColor(a));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,k)=>(k=(k%1+1)%1)<1/6?f+6*(g-f)*k:.5>k?g:k<2/3?f+(g-f)*(2/3-k)*6:f;this.r=e(c,b,a+1/3);this.g=e(c,b,a);this.b=e(c,b,a-1/3);this.a=d;return this}HSLA(){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 k=0,h=0;if(e!=f){let l=e-f;h=.5<g?l/(2-e-f):l/(e+f);a==e?k=(b-c)/l+(b<c?6:0):b==e?k=(c-a)/l+2:c==e&&(k=(a-b)/l+4)}return[k/6,h,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=!0){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)<<8,c=255*clamp(this.b)<<16,d=255*clamp(this.a)<<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=!0,fontDefault="arial",showSplashScreen=!1,glEnable=!0,glOverlay=!0,tileSizeDefault=vec2(16),tileFixBleedScale=.1,enablePhysicsSolver=!0,objectDefaultMass=1,objectDefaultDamping=1,objectDefaultAngleDamping=1,objectDefaultElasticity=0,objectDefaultFriction=.8,objectMaxSpeed=1,gravity=0,particleEmitRateScale=1,gamepadsEnable=!0,gamepadDirectionEmulateStick=!0,inputWASDEmulateDirection=!0,touchGamepadEnable=!1,touchGamepadAnalog=!0,touchGamepadSize=99,touchGamepadAlpha=.3,vibrateEnable=!0,soundEnable=!0,soundVolume=.5,soundDefaultRange=40,soundDefaultTaper=.7,medalDisplayTime=5,medalDisplaySlideTime=.5,medalDisplaySize=vec2(640,80),medalDisplayIconSize=50,medalsPreventUnlock=!1;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 setShowSplashScreen(a){showSplashScreen=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),"ensure pos and size are vec2s");ASSERT("number"!==typeof c||!c,"old style tile setup");this.pos=a.copy();this.size=b;this.drawSize=void 0;this.tileInfo=c;this.angle=d;this.color=e;this.additiveColor=void 0;this.mirror=!1;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.parent=void 0;this.localPos=vec2();this.localAngle=0;this.collideRaycast=this.isSolid=this.collideSolidObjects=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 k=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||!k)if(this.pos.y=d.pos.y+(e.y/2+.001)*sign(a.y-d.pos.y),d.groundObject&&b||!d.mass)b&&(this.groundObject=d),this.velocity.y*=-c;else if(d.mass){g=(this.mass*this.velocity.y+d.mass*d.velocity.y)/(this.mass+d.mass);const h=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,h)}!f&&k&&(this.pos.x=d.pos.x+(e.x/2+.001)*sign(a.x-d.pos.x),d.mass?(e=(this.mass*this.velocity.x+d.mass*d.velocity.x)/(this.mass+d.mass),f=d.velocity.x*(d.mass-this.mass)/(this.mass+d.mass)+2*this.velocity.x*this.mass/(this.mass+d.mass),this.velocity.x=lerp(c,e,this.velocity.x*(this.mass-d.mass)/(this.mass+d.mass)+2*d.velocity.x*d.mass/(this.mass+d.mass)),d.velocity.x=lerp(c,e,f)):this.velocity.x*=-c);debugOverlay&&debugPhysics&&debugAABB(this.pos,this.size,d.pos,d.size,"#f0f")}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}collideWithObject(a){return!0}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=!0,b=!0,c=!0,d=!0){ASSERT(a||!b,"solid objects must be set to collide");this.collideSolidObjects=a;this.isSolid=b;this.collideTiles=c;this.collideRaycast=d}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){"number"===typeof b&&(ASSERT(0<b),b=vec2(b));if("number"===typeof a){var d=textureInfos[c];ASSERT(d,"Texture not loaded");d=d.size.x/b.x|0;a=vec2(a%d*b.x,(a/d|0)*b.y)}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)}frame(a){ASSERT("number"==typeof a);return this.offset(vec2(a*this.size.x,0))}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 getCameraSize(){return mainCanvasSize.scale(1/cameraScale)}function drawTile(a,b=vec2(1),c,d=new Color,e=0,f,g=new Color(0,0,0,0),k=glEnable,h,l){ASSERT(!l||!k,"context only supported in canvas 2D mode");ASSERT("number"!==typeof c||!c,"this is an old style calls, to fix replace it with tile(tileIndex, tileSize)");const n=c&&c.getTextureInfo();if(k)if(h&&(a=screenToWorld(a),b=b.scale(1/cameraScale)),n){k=c.pos.x/n.size.x;h=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,k+p.x,h+p.y,k-p.x+l,h-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 showWatermark&&++drawCount,drawCanvas2D(a,b,e,f,m=>{if(n){const p=c.pos.x+tileFixBleedScale,t=c.pos.y+tileFixBleedScale,u=c.size.x-2*tileFixBleedScale,x=c.size.y-2*tileFixBleedScale;m.globalAlpha=d.a;m.drawImage(n.image,p,t,u,x,-.5,-.5,1,1);m.globalAlpha=1}else m.fillStyle=d,m.fillRect(-.5,-.5,1,1)},h,l)}function drawRect(a,b,c,d,e,f,g){drawTile(a,b,void 0,c,d,!1,void 0,e,f,g)}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,"context only supported in canvas 2D mode");b?glAdditive=a:(c||=mainContext,c.globalCompositeOperation=a?"lighter":"source-over")}function drawText(a,b,c=1,d,e=0,f,g,k,h){drawTextScreen(a,worldToScreen(b),c*cameraScale,d,e*cameraScale,f,g,k,h)}function drawTextScreen(a,b,c=1,d=new Color,e=0,f=new Color(0,0,0),g="center",k=fontDefault,h=overlayContext){h.fillStyle=d.toString();h.lineWidth=e;h.strokeStyle=f.toString();h.textAlign=g;h.font=c+"px "+k;h.textBaseline="middle";h.lineJoin="round";b=b.copy();(a+"").split("\n").forEach(l=>{e&&h.strokeText(l,b.x,b.y);h.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),k=this.image.width/this.tileSize.x|0;(a+"").split("\n").forEach((h,l)=>{const n=d?h.length*f.x*c/2|0:0;for(let t=h.length;t--;){var m=h[t].charCodeAt(0);if(32>m||127<m)m=127;var p=m-32;m=p%k;p=p/k|0;const u=b.add(vec2(t,l).multiply(g));e.drawImage(this.image,m*f.x,p*f.y,f.x,f.y,u.x-n,u.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){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&1)}function keyWasPressed(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&2)}function keyWasReleased(a,b=0){ASSERT(0<b||"number"!==typeof a||3>a,"use code string for keyboard");return inputData[b]&&!!(inputData[b][a]&4)}function clearInput(){inputData=[[]]}const mouseIsDown=keyIsDown,mouseWasPressed=keyWasPressed,mouseWasReleased=keyWasReleased;let mousePos=vec2(),mousePosScreen=vec2(),mouseWheel=0,isUsingGamepad=!1,preventDefaultInput=!1;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||(isUsingGamepad=!1,inputData[0][a.code]=3,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=3)),preventDefaultInput&&a.preventDefault())};onkeyup=a=>{debug&&a.target!=document.body||(inputData[0][a.code]=4,inputWASDEmulateDirection&&(inputData[0][remapKey(a.code)]=4))};function remapKey(a){return inputWASDEmulateDirection?"KeyW"==a?"ArrowUp":"KeyS"==a?"ArrowDown":"KeyA"==a?"ArrowLeft":"KeyD"==a?"ArrowRight":a:a}onmousedown=a=>{isUsingGamepad=!1;inputData[0][a.button]=3;mousePosScreen=mouseToScreen(a);a.button&&a.preventDefault()};onmouseup=a=>inputData[0][a.button]=inputData[0][a.button]&2|4;onmousemove=a=>mousePosScreen=mouseToScreen(a);onwheel=a=>mouseWheel=a.ctrlKey?0: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(){const a=g=>{const k=h=>.3<h?percent(h,.3,.8):-.3>h?-percent(-h,.3,.8):0;return vec2(k(g.x),k(-g.y)).clampLength()};if(touchGamepadEnable&&isTouchDevice&&(touchGamepadButtons||createTouchGamepad(),touchGamepadTimer.isSet())){var b=stickData[0]||(stickData[0]=[]);b[0]=vec2();touchGamepadAnalog?b[0]=a(touchGamepadStick):.3<touchGamepadStick.lengthSquared()&&(b[0].x=Math.round(touchGamepadStick.x),b[0].y=-Math.round(touchGamepadStick.y),b[0]=b[0].clampLength());b=inputData[1]||(inputData[1]=[]);for(var c=10;c--;){var d=3==c?2:2==c?3:c;b[d]=touchGamepadButtons[c]?gamepadIsDown(d,0)?1:3:gamepadIsDown(d,0)?4:0}}if(gamepadsEnable&&navigator&&navigator.getGamepads&&(debug||document.hasFocus()))for(b=navigator.getGamepads(),c=b.length;c--;){var e=b[c];const g=inputData[c+1]||(inputData[c+1]=[]);d=stickData[c]||(stickData[c]=[]);if(e){for(var f=0;f<e.axes.length-1;f+=2)d[f>>1]=a(vec2(e.axes[f],e.axes[f+1]));for(f=e.buttons.length;f--;){const k=e.buttons[f],h=gamepadIsDown(f,c);g[f]=k.pressed?h?1:3:h?4:0;isUsingGamepad||=!c&&k.pressed}gamepadDirectionEmulateStick&&(e=vec2((gamepadIsDown(15,c)&&1)-(gamepadIsDown(14,c)&&1),(gamepadIsDown(12,c)&&1)-(gamepadIsDown(13,c)&&1)),e.lengthSquared()&&(d[0]=e.clampLength()));touchGamepadEnable&&isUsingGamepad&&touchGamepadTimer.unset()}}}function vibrate(a=100){vibrateEnable&&navigator&&navigator.vibrate&&navigator.vibrate(a)}function vibrateStop(){vibrate(0)}const isTouchDevice=void 0!==window.ontouchstart;if(isTouchDevice){let a;onmousedown=onmouseup=()=>0;ontouchstart=ontouchmove=ontouchend=b=>{soundEnable&&audioContext&&"running"!=audioContext.state&&zzfx(0);const c=b.touches.length;if(c){const d=vec2(b.touches[0].clientX,b.touches[0].clientY);mousePosScreen=mouseToScreen(d);a?isUsingGamepad=!1:inputData[0][0]=3}else a&&(inputData[0][0]=inputData[0][0]&2|4);a=c;document.hasFocus()&&b.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?touchGamepadStick=f.subtract(c).scale(2/touchGamepadSize).clampLength():f.distance(d)<touchGamepadSize?(f=f.subtract(d).direction(),touchGamepadButtons[f]=1):f.distance(e)<touchGamepadSize&&(touchGamepadButtons[9]=1)}a.bind(window)(b);return isUsingGamepad=!0}}function touchGamepadRender(){if(touchGamepadEnable&&touchGamepadTimer.isSet()){var a=percent(touchGamepadTimer.get(),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().setDirection(b,touchGamepadSize/2)),overlayContext.fillStyle=touchGamepadButtons[b]?"#fff":"#000",overlayContext.beginPath(),overlayContext.arc(c.x,c.y,touchGamepadSize/4,0,9),overlayContext.fill(),overlayContext.stroke();overlayContext.restore()}}}class Sound{constructor(a,b=soundDefaultRange,c=soundDefaultTaper){soundEnable&&(this.range=b,this.taper=c,this.randomness=0,a&&(this.randomness=a[1]||0,a[1]=0,this.sampleChannels=[zzfxG(...a)],this.sampleRate=zzfxR))}play(a,b=1,c=1,d=1,e=!1){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=void 0}getSource(){return this.source}playNote(a,b,c){return this.play(b,c,2**(a/12),0)}getDuration(){return this.sampleChannels&&this.sampleChannels[0].length/this.sampleRate}isLoading(){return!this.sampleChannels}}class SoundWave extends Sound{constructor(a,b=0,c,d){super(void 0,c,d);this.randomness=b;soundEnable&&fetch(a).then(e=>e.arrayBuffer()).then(e=>audioContext.decodeAudioData(e)).then(e=>{this.sampleChannels=[];for(let f=e.numberOfChannels;f--;)this.sampleChannels[f]=Array.from(e.getChannelData(f));this.sampleRate=e.sampleRate})}}class Music extends Sound{constructor(a){super(void 0);soundEnable&&(this.randomness=0,this.sampleChannels=zzfxM(...a),this.sampleRate=zzfxR)}playMusic(a,b=!1){return super.play(void 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=new AudioContext,audioSuspended=!1;function playSamples(a,b=1,c=1,d=0,e=!1,f=zzfxR){if(soundEnable){var g=audioSuspended;if(audioSuspended="running"!=audioContext.state)if(audioContext.resume(),g)return;var k=audioContext.createBuffer(a.length,a[0].length,f);f=audioContext.createBufferSource();a.forEach((h,l)=>k.getChannelData(l).set(h));f.buffer=k;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,k=1,h=0,l=0,n=0,m=0,p=0,t=0,u=0,x=0,v=0,D=1,z=0,E=0,A=0){let w=2*PI;var q=zzfxR;let F=h*=500*w/q/q;b=c*=rand(1+b,1-b)*w/q;let C=[],y=0,G=0,r=0,H=1,R=0,S=0,B=0,J;var L=w*abs(A)*2/q,K=Math.cos(L),M=Math.sin(L)/2/2,I=1+M;L=-2*K/I;M=(1-M)/I;let N=(1+sign(A)*K)/2/I;K=-(sign(A)+K)/I;let O=I=0,P=0,Q=0;d=d*q+9;z*=q;e*=q;f*=q;v*=q;l*=500*w/q**3;u*=w/q;n*=w/q;m*=q;p=p*q|0;a*=soundVolume;for(J=d+z+e+f+v|0;r<J;C[r++]=B*a)++S%(100*x|0)||(B=g?1<g?2<g?3<g?Math.sin(y**3):clamp(Math.tan(y),1,-1):1-(2*y/w%2+2)%2:1-4*abs(Math.round(y/w)-y/w):Math.sin(y),B=(p?1-E+E*Math.sin(w*r/p):1)*sign(B)*abs(B)**k*(r<d?r/d:r<d+z?1-(r-d)/z*(1-D):r<d+z+e?D:r<J-v?(J-r-v)/f*D:0),B=v?B/2+(v>r?0:(r<J-v?1:(J-r)/v)*C[r-v|0]/2/a):B,A&&(B=Q=N*I+K*(I=O)+N*(O=B)-M*P-L*(P=Q))),q=(c+=h+=l)*Math.cos(u*G++),y+=q+q*t*Math.sin(r**5),H&&++H>m&&(c+=n,b+=n,H=0),!p||++R%p||(c=b,h=F,H=H||1);return C}function zzfxM(a,b,c,d=125){let e,f,g,k,h,l,n,m,p,t,u,x,v,D=0,z,E=[],A=[],w=[],q=0,F=0,C=1,y={},G=zzfxR/d*60>>2;for(;C;q++)E=[C=m=x=0],c.forEach((r,H)=>{n=b[r][q]||[0,0,0];C|=b[r][q]&&1;z=x+(b[r][0].length-2-(m?0:1))*G;v=H==c.length-1;e=2;for(g=x;e<n.length+v;m=++e){h=n[e];p=e==n.length+v-1&&v||t!=(n[0]||0)||h|0;for(f=0;f<G&&m;f++>G-99&&p&&1>u?u+=1/99:0)l=(1-u)*E[D++]/2||0,A[g]=(A[g]||0)-l*F+l,w[g]=(w[g++]||0)+l*F+l;h&&(u=h%1,F=n[1]||0,h|=0)&&(E=y[[t=n[D=0]||0,h]]=y[[t,h]]||(k=[...a[t]],k[2]*=2**((h-12)/12),0<h?zzfxG(...k):[]))}x=z});return[A,w]}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!0}}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(),k=f.x*(0>d.x?a.x-g.x:g.x-a.x+1),h=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(k>e&&h>e)break;k>h?(g.y+=sign(d.y),h+=f.y):(g.x+=sign(d.x),k+=f.x)}debugRaycast&&debugLine(a,b,"#00f",.02)}class TileLayerData{constructor(a,b=0,c=!1,d=new Color){this.tile=a;this.direction=b;this.mirror=c;this.color=d}clear(){this.tile=this.direction=0;this.mirror=!1;this.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=!1;this.data=[];for(a=this.size.area();a--;)this.data.push(new TileLayerData)}setData(a,b,c=!1){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,"must call redrawEnd() after drawing tiles");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(!0);for(let a=this.size.x;a--;)for(let b=this.size.y;b--;)this.drawTileData(vec2(a,b),!1);this.redrawEnd()}redrawStart(a=!1){this.savedRenderSettings=[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale];mainCanvas=this.canvas;mainContext=this.context;mainCanvasSize=this.size.multiply(this.tileInfo.size);cameraPos=this.size.scale(.5);cameraScale=this.tileInfo.size.x;a&&(mainCanvas.width=mainCanvasSize.x,mainCanvas.height=mainCanvasSize.y);this.context.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender()}redrawEnd(){ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles");glEnable&&glCopyToContext(mainContext,!0);[mainCanvas,mainContext,mainCanvasSize,cameraPos,cameraScale]=this.savedRenderSettings}drawTileData(a,b=!0){var c=this.tileInfo.size;b&&(b=a.multiply(c),this.context.clearRect(b.x,this.canvas.height-b.y,c.x,-c.y));b=this.getData(a);void 0!=b.tile&&(a=this.pos.add(a).add(vec2(.5)),ASSERT(mainContext==this.context,"must call redrawStart() before drawing tiles"),c=tile(b.tile,c,this.tileInfo.textureIndex),drawTile(a,vec2(1),c,b.color,b.direction*PI/2,b.mirror))}drawCanvas2D(a,b,c,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 k=c&&c.getTextureInfo();k?(g.globalAlpha=d.a,g.drawImage(k.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,void 0,c,d)}}class ParticleEmitter extends EngineObject{constructor(a,b,c=0,d=0,e=100,f=PI,g,k=new Color,h=new Color,l=new Color(1,1,1,0),n=new Color(1,1,1,0),m=.5,p=.1,t=1,u=.1,x=.05,v=1,D=1,z=0,E=PI,A=.1,w=.2,q=!1,F=!1,C=!0,y=F?1e9:0,G=!1){super(a,vec2(),g,b,void 0,y);this.emitSize=c;this.emitTime=d;this.emitRate=e;this.emitConeAngle=f;this.colorStartA=k;this.colorStartB=h;this.colorEndA=l;this.colorEndB=n;this.randomColorLinear=C;this.particleTime=m;this.sizeStart=p;this.sizeEnd=t;this.speed=u;this.angleSpeed=x;this.damping=v;this.angleDamping=D;this.gravityScale=z;this.particleConeAngle=E;this.fadeRate=A;this.randomness=w;this.collideTiles=q;this.additive=F;this.localSpace=G;this.trailScale=0;this.particleCreateCallback=this.particleDestroyCallback=void 0;this.emitTimeBuffer=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="number"===typeof this.emitSize?randInCircle(this.emitSize/2):vec2(rand(-.5,.5),rand(-.5,.5)).multiply(this.emitSize).rotate(this.angle);let b=rand(this.particleConeAngle,-this.particleConeAngle);this.localSpace||(a=this.pos.add(a),b+=this.angle);const c=this.randomness;var d=m=>m+m*rand(c,-c);const e=d(this.particleTime),f=d(this.sizeStart),g=d(this.sizeEnd),k=d(this.speed);d=d(this.angleSpeed)*randSign();var h=rand(this.emitConeAngle,-this.emitConeAngle);const l=randColor(this.colorStartA,this.colorStartB,this.randomColorLinear),n=randColor(this.colorEndA,this.colorEndB,this.randomColorLinear);h=this.localSpace?h:this.angle+h;a=new Particle(a,this.tileInfo,b,l,n,e,f,g,this.fadeRate,this.additive,this.trailScale,this.localSpace&&this,this.particleDestroyCallback);a.velocity=vec2().setAngle(h,k);a.angleVelocity=d;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.renderOrder=this.renderOrder;a.mirror=!!randInt(2);this.particleCreateCallback&&this.particleCreateCallback(a);return a}render(){}}class Particle extends EngineObject{constructor(a,b,c,d,e,f,g,k,h,l,n,m,p){super(a,vec2(),b,c);this.colorStart=d;this.colorEndDelta=e.subtract(d);this.lifeTime=f;this.sizeStart=g;this.sizeEndDelta=k-g;this.fadeRate=h;this.additive=l;this.trailScale=n;this.localSpaceEmitter=m;this.destroyCallback=p}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(!0);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,"save name must be set"),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).toString();b.strokeStyle=new Color(0,0,0).toString();b.lineWidth=3;b.rect(d,a,c,medalDisplaySize.y);b.fill();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,void 0,"left");c.y+=32;drawTextScreen(this.description,c,24,new Color(0,0,0),0,void 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)medalsDisplayTimeLast=0,medalsDisplayQueue.shift();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&&0<a,"there can only be one newgrounds object");ASSERT(!b||c,"must provide cryptojs if there is a cipher");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,!0),3e5)}}unlockMedal(a){return this.call("Medal.unlock",{id:a},!0)}postScore(a,b){return this.call("ScoreBoard.postScore",{id:a,value:b},!0)}getScores(a,b,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},!0)}call(a,b,c=!1){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,glShader,glActiveTexture,glArrayBuffer,glGeometryBuffer,glPositionData,glColorData,glInstanceCount,glAdditive,glBatchAdditive;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 g;in vec4 p,u,c,a;in float r;out vec2 v;out vec4 d,e;void main(){vec2 s=(g-.5)*p.zw;gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);v=mix(u.xw,u.zy,g);d=c;e=a;}","#version 300 es\nprecision highp float;in vec2 v;in vec4 d,e;uniform sampler2D s;out vec4 c;void main(){c=texture(s,v)*d+e;}");var a=new ArrayBuffer(gl_INSTANCE_BUFFER_SIZE);glPositionData=new Float32Array(a);glColorData=new Uint32Array(a);glArrayBuffer=glContext.createBuffer();glGeometryBuffer=glContext.createBuffer();a=new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.bufferData(gl_ARRAY_BUFFER,a,gl_STATIC_DRAW)}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);let a=glAdditive=glBatchAdditive=0;var b=(d,e,f,g)=>{d=glContext.getAttribLocation(glShader,d);const k=f&&gl_INSTANCE_BYTE_STRIDE,h=f&&1,l=1==f;glContext.enableVertexAttribArray(d);glContext.vertexAttribPointer(d,g,e,l,k,a);glContext.vertexAttribDivisor(d,h);a+=g*f};glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);b("g",gl_FLOAT,0,2);glContext.bindBuffer(gl_ARRAY_BUFFER,glArrayBuffer);glContext.bufferData(gl_ARRAY_BUFFER,gl_INSTANCE_BUFFER_SIZE,gl_DYNAMIC_DRAW);b("p",gl_FLOAT,4,4);b("u",gl_FLOAT,4,4);b("c",gl_UNSIGNED_BYTE,1,4);b("a",gl_UNSIGNED_BYTE,1,4);b("r",gl_FLOAT,4,1);b=vec2(2*cameraScale).divide(mainCanvasSize);const c=vec2(-1).subtract(cameraPos.multiply(b));glContext.uniformMatrix4fv(glContext.getUniformLocation(glShader,"m"),!1,new Float32Array([b.x,0,0,0,0,b.y,0,0,1,1,1,1,c.x,c.y,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&&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);return b}function glFlush(){if(glInstanceCount){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);glContext.drawArraysInstanced(gl_TRIANGLE_STRIP,0,4,glInstanceCount);showWatermark&&(drawCount+=glInstanceCount);glInstanceCount=0;glBatchAdditive=glAdditive}}function glCopyToContext(a,b=!1){if(glInstanceCount||b)glFlush(),glOverlay&&!b||a.drawImage(glCanvas,0,0)}function glDraw(a,b,c,d,e,f,g,k,h,l,n=0){ASSERT("number"==typeof l&&"number"==typeof n,"invalid color");(glInstanceCount>=gl_MAX_INSTANCES||glBatchAdditive!=glAdditive)&&glFlush();let m=glInstanceCount*gl_INDICIES_PER_INSTANCE;glPositionData[m++]=a;glPositionData[m++]=b;glPositionData[m++]=c;glPositionData[m++]=d;glPositionData[m++]=f;glPositionData[m++]=g;glPositionData[m++]=k;glPositionData[m++]=h;glColorData[m++]=l;glColorData[m++]=n;glPositionData[m++]=e;glInstanceCount++}let glPostShader,glPostTexture,glPostIncludeOverlay;function glInitPostProcess(a,b=!1){ASSERT(!glPostShader,"can only have 1 post effects shader");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+p-1.,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.;}");glPostTexture=glCreateTexture(void 0);glPostIncludeOverlay=b;mainCanvas.style.visibility="hidden";glPostIncludeOverlay&&(overlayCanvas.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);glContext.useProgram(glPostShader);glContext.bindBuffer(gl_ARRAY_BUFFER,glGeometryBuffer);glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL,1);glContext.disable(gl_BLEND);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,!1,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,4)}}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_COLOR_BUFFER_BIT=16384,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_INSTANCE=11,gl_MAX_INSTANCES=1e4,gl_INSTANCE_BYTE_STRIDE=4*gl_INDICIES_PER_INSTANCE,gl_INSTANCE_BUFFER_SIZE=gl_MAX_INSTANCES*gl_INSTANCE_BYTE_STRIDE,engineName="LittleJS",engineVersion="1.9.5",frameRate=60,timeDelta=1/frameRate;let engineObjects=[],engineObjectsCollide=[],frame=0,time=0,timeReal=0,paused=!1;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 l=h-frameTimeLastMS;frameTimeLastMS=h;if(debug||showWatermark)averageFPS=lerp(.05,averageFPS,1e3/(l||1));h=debug&&keyIsDown("Equal");const n=debug&&keyIsDown("Minus");debug&&(l*=h?5:n?.2:1);timeReal+=l/1e3;frameTimeBufferMS+=paused?0:l;h||(frameTimeBufferMS=min(frameTimeBufferMS,50));k();if(paused)inputUpdate(),debugUpdate(),c(),inputUpdatePost();else{l=0;0>frameTimeBufferMS&&-9<frameTimeBufferMS&&(l=frameTimeBufferMS,frameTimeBufferMS=0);for(;0<=frameTimeBufferMS;frameTimeBufferMS-=1e3/frameRate)time=frame++/frameRate,inputUpdate(),b(),engineObjectsUpdate(),debugUpdate(),c(),inputUpdatePost();frameTimeBufferMS+=l}mainCanvasSize=vec2(mainCanvas.width,mainCanvas.height);mainContext.imageSmoothingEnabled=!canvasPixelated;glEnable&&glPreRender();d();engineObjects.sort((p,t)=>p.renderOrder-t.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)}function k(){if(canvasFixedSize.x){mainCanvas.width=canvasFixedSize.x;mainCanvas.height=canvasFixedSize.y;const h=innerWidth/innerHeight,l=mainCanvas.width/mainCanvas.height;(glCanvas||mainCanvas).style.width=mainCanvas.style.width=overlayCanvas.style.width=h<l?"100%":"";(glCanvas||mainCanvas).style.height=mainCanvas.style.height=overlayCanvas.style.height=h<l?"":"100%"}else 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)}ASSERT(Array.isArray(f),"pass in images as array");document.body.style.cssText="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.cssText=mainCanvas.style.cssText=overlayCanvas.style.cssText="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)";k();f=f.map((h,l)=>new Promise(n=>{const m=new Image;m.onerror=m.onload=()=>{textureInfos[l]=new TextureInfo(m);n()};m.src=h}));showSplashScreen&&f.push(new Promise(h=>{function l(){clearInput();drawEngineSplashScreen(n+=.01);1<n?h():setTimeout(l,16)}let n=0;console.log(`${engineName} Engine v${engineVersion}`);l()}));Promise.all(f).then(()=>{a();g()})}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 engineObjectsCollect(a,b,c=engineObjects){const d=[];if(a)if(b instanceof Vector2)for(const e of c)isOverlapping(a,b,e.pos,e.size)&&d.push(e);else{b*=b;for(const e of c)a.distanceSquared(e.pos)<b&&d.push(e)}else for(const e of c)d.push(e);return d}function engineObjectsCallback(a,b,c,d=engineObjects){engineObjectsCollect(a,b,d).forEach(e=>c(e))}function engineObjectsRaycast(a,b,c=engineObjects){const d=[];for(const e of c)e.collideRaycast&&isIntersecting(a,b,e.pos,e.size)&&(debugRaycast&&debugRect(e.pos,e.size,"#f00"),d.push(e));debugRaycast&&debugLine(a,b,d.length?"#f00":"#00f",.02);return d}function drawEngineSplashScreen(a){const b=overlayContext;var c=overlayCanvas.width=innerWidth,d=overlayCanvas.height=innerHeight,e=percent(a,1,.8),f=percent(a,0,.5),g=b.createRadialGradient(c/2,d/2,0,c/2,d/2,.7*Math.hypot(c,d));g.addColorStop(0,hsl(0,0,lerp(f,0,e/2),e).toString());g.addColorStop(1,hsl(0,0,0,e).toString());b.save();b.fillStyle=g;b.fillRect(0,0,c,d);g=(h,l,n,m,p)=>{b.beginPath();b.rect(h,l,n,p?m*k:m);(b.fillStyle=p)?b.fill():b.stroke()};f=(h,l,n,m=0,p=2*PI,t,u)=>{const x=(m+p)/2;m=k*(p-m)/2;b.beginPath();u&&b.lineTo(h,l);b.arc(h,l,n,x-m,x+m);(b.fillStyle=t)?b.fill():b.stroke()};e=(h=0,l=0)=>hsl([.98,.3,.57,.14][h%4]-10,.8,[0,.3,.5,.8,.9][l]).toString();a=wave(1,1,a);const k=percent(a,.1,.5);b.translate(c/2,d/2);c=min(6,min(c,d)/99);b.scale(c,c);b.translate(-40,-35);b.lineJoin=b.lineCap="round";b.lineWidth=.1+1.9*k;c=percent(a,.1,1);b.setLineDash([99*c,99]);g(7,17,18,-8,e(2,2));g(7,9,18,4,e(2,3));g(25,9,8,8,e(2,1));g(25,9,-18,8);g(25,9,8,8);g(25,17,7,22,e());g(11,40,14,-23,e(1,1));g(11,17,14,17,e(1,2));g(11,17,14,9,e(1,3));g(15,31,6,-9,e(2,2));f(15,23,5,0,PI/2,e(2,4),1);g(25,17,-14,23);g(21,22,-6,9);g(37,14,9,6,e(3,2));g(37,14,4.5,6,e(3,3));g(37,14,9,6);g(50,20,10,-8,e(0,1));g(50,20,6.5,-8,e(0,2));g(50,20,3.5,-8,e(0,3));g(50,20,10,-8);f(55,2,11.4,.5,PI-.5,e(3,3));f(55,2,11.4,.5,PI/2,e(3,2),1);f(55,2,11.4,.5,PI-.5);g(45,7,20,-7,e(0,2));g(45,-1,20,4,e(0,3));g(45,-1,20,8);for(c=5;c--;)f(60-6*c,30,9.9,0,2*PI,e(c+2,3)),f(60-6*c,30,10,-.5,PI+.5,e(c+2,2)),f(60-6*c,30,10.1,.5,PI-.5,e(c+2,1));f(36,30,10,PI/2,3*PI/2);f(48,30,10,PI/2,3*PI/2);f(60,30,10);b.beginPath();b.lineTo(36,20);b.lineTo(60,20);b.stroke();f(60,30,4,PI,3*PI,e(3,2));f(60,30,4,PI,2*PI,e(3,3));f(60,30,4,PI,3*PI);for(c=6;c--;)b.beginPath(),b.lineTo(53,54),b.lineTo(53,40),b.lineTo(53+(1+2.9*c)*k,40),b.lineTo(53+(4+3.5*c)*k,54),b.fillStyle=e(0,c%2+2),b.fill(),c%2&&b.stroke();g(6,40,5,5);g(6,40,5,5,e());g(15,54,38,-14,e());for(g=3;g--;)for(c=2;c--;)f(15*g+15,47,c?7:1,PI,3*PI,e(g,3)),b.stroke(),f(15*g+15,47,c?7:1,0,PI,e(g,2)),b.stroke();b.beginPath();b.lineTo(6,40);b.lineTo(68,40);b.stroke();b.beginPath();b.lineTo(77,54);b.lineTo(4,54);b.stroke();f=engineName;b.font="900 16px arial";b.textAlign="center";b.textBaseline="top";b.lineWidth=.1+3.9*k;g=0;for(c=0;c<f.length;++c)g+=b.measureText(f[c]).width;for(c=2;c--;)for(let h=0,l=41-g/2;h<f.length;++h)b.fillStyle=e(h,2),d=b.measureText(f[h]).width,b[c?"strokeText":"fillText"](f[h],l+d/2,55.5,17*k),l+=d;b.restore()}export{engineName,engineVersion,frameRate,timeDelta,engineObjects,frame,time,timeReal,paused,setPaused,engineInit,engineObjectsUpdate,engineObjectsDestroy,engineObjectsCallback,debug,debugOverlay,showWatermark,ASSERT,debugRect,debugCircle,debugPoint,debugLine,debugAABB,debugText,debugClear,debugSaveCanvas,cameraPos,cameraScale,canvasMaxSize,canvasFixedSize,canvasPixelated,fontDefault,showSplashScreen,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,setShowSplashScreen,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,SoundWave,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/dist/littlejs.js
CHANGED
|
@@ -357,7 +357,7 @@ function debugRender()
|
|
|
357
357
|
overlayContext.restore();
|
|
358
358
|
});
|
|
359
359
|
|
|
360
|
-
// remove expired
|
|
360
|
+
// remove expired primitives
|
|
361
361
|
debugPrimitives = debugPrimitives.filter(r=>r.time<0);
|
|
362
362
|
}
|
|
363
363
|
|
|
@@ -542,16 +542,57 @@ function smoothStep(percent) { return percent * percent * (3 - 2 * percent); }
|
|
|
542
542
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
543
543
|
|
|
544
544
|
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
545
|
-
* @param {Vector2}
|
|
546
|
-
* @param {Vector2} sizeA
|
|
547
|
-
* @param {Vector2}
|
|
548
|
-
* @param {Vector2} [sizeB=(0,0)]
|
|
549
|
-
* @return {Boolean}
|
|
545
|
+
* @param {Vector2} posA - Center of box A
|
|
546
|
+
* @param {Vector2} sizeA - Size of box A
|
|
547
|
+
* @param {Vector2} posB - Center of box B
|
|
548
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
549
|
+
* @return {Boolean} - True if overlapping
|
|
550
550
|
* @memberof Utilities */
|
|
551
|
-
function isOverlapping(
|
|
551
|
+
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
552
552
|
{
|
|
553
|
-
return abs(
|
|
554
|
-
&& abs(
|
|
553
|
+
return abs(posA.x - posB.x)*2 < sizeA.x + sizeB.x
|
|
554
|
+
&& abs(posA.y - posB.y)*2 < sizeA.y + sizeB.y;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/** Returns true if a line segment is intersecting an axis aligned box
|
|
558
|
+
* @param {Vector2} start - Start of raycast
|
|
559
|
+
* @param {Vector2} end - End of raycast
|
|
560
|
+
* @param {Vector2} pos - Center of box
|
|
561
|
+
* @param {Vector2} size - Size of box
|
|
562
|
+
* @return {Boolean} - True if intersecting
|
|
563
|
+
* @memberof Utilities */
|
|
564
|
+
function isIntersecting(start, end, pos, size)
|
|
565
|
+
{
|
|
566
|
+
// Liang-Barsky algorithm
|
|
567
|
+
const boxMin = pos.subtract(size.scale(.5));
|
|
568
|
+
const boxMax = boxMin.add(size);
|
|
569
|
+
const delta = end.subtract(start);
|
|
570
|
+
const a = start.subtract(boxMin);
|
|
571
|
+
const b = start.subtract(boxMax);
|
|
572
|
+
const p = [-delta.x, delta.x, -delta.y, delta.y];
|
|
573
|
+
const q = [a.x, -b.x, a.y, -b.y];
|
|
574
|
+
let tMin = 0, tMax = 1;
|
|
575
|
+
for (let i = 4; i--;)
|
|
576
|
+
{
|
|
577
|
+
if (p[i])
|
|
578
|
+
{
|
|
579
|
+
const t = q[i] / p[i];
|
|
580
|
+
if (p[i] < 0)
|
|
581
|
+
{
|
|
582
|
+
if (t > tMax) return false;
|
|
583
|
+
tMin = max(t, tMin);
|
|
584
|
+
}
|
|
585
|
+
else
|
|
586
|
+
{
|
|
587
|
+
if (t < tMin) return false;
|
|
588
|
+
tMax = min(t, tMax);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
else if (q[i] < 0)
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return true;
|
|
555
596
|
}
|
|
556
597
|
|
|
557
598
|
/** Returns an oscillating wave between 0 and amplitude with frequency of 1 Hz by default
|
|
@@ -1735,6 +1776,8 @@ class EngineObject
|
|
|
1735
1776
|
this.collideSolidObjects = false;
|
|
1736
1777
|
/** @property {Boolean} - Object collides with and blocks other objects */
|
|
1737
1778
|
this.isSolid = false;
|
|
1779
|
+
/** @property {Boolean} - Object collides with raycasts */
|
|
1780
|
+
this.collideRaycast = false;
|
|
1738
1781
|
|
|
1739
1782
|
// add to list of objects
|
|
1740
1783
|
engineObjects.push(this);
|
|
@@ -1939,13 +1982,7 @@ class EngineObject
|
|
|
1939
1982
|
* @param {Number} tileData - the value of the tile at the position
|
|
1940
1983
|
* @param {Vector2} pos - tile where the collision occured
|
|
1941
1984
|
* @return {Boolean} - true if the collision should be resolved */
|
|
1942
|
-
collideWithTile(tileData, pos)
|
|
1943
|
-
|
|
1944
|
-
/** Called to check if a tile raycast hit
|
|
1945
|
-
* @param {Number} tileData - the value of the tile at the position
|
|
1946
|
-
* @param {Vector2} pos - tile where the raycast is
|
|
1947
|
-
* @return {Boolean} - true if the raycast should hit */
|
|
1948
|
-
collideWithTileRaycast(tileData, pos) { return tileData > 0; }
|
|
1985
|
+
collideWithTile(tileData, pos) { return tileData > 0; }
|
|
1949
1986
|
|
|
1950
1987
|
/** Called to check if a object collision should be resolved
|
|
1951
1988
|
* @param {EngineObject} object - the object to test against
|
|
@@ -1992,16 +2029,18 @@ class EngineObject
|
|
|
1992
2029
|
}
|
|
1993
2030
|
|
|
1994
2031
|
/** Set how this object collides
|
|
1995
|
-
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects
|
|
1996
|
-
* @param {Boolean} [isSolid] - Does it collide with and block other objects (expensive in large numbers)
|
|
1997
|
-
* @param {Boolean} [collideTiles] - Does it collide with the tile collision
|
|
1998
|
-
|
|
2032
|
+
* @param {Boolean} [collideSolidObjects] - Does it collide with solid objects?
|
|
2033
|
+
* @param {Boolean} [isSolid] - Does it collide with and block other objects? (expensive in large numbers)
|
|
2034
|
+
* @param {Boolean} [collideTiles] - Does it collide with the tile collision?
|
|
2035
|
+
* @param {Boolean} [collideRaycast] - Does it collide with raycasts? */
|
|
2036
|
+
setCollision(collideSolidObjects=true, isSolid=true, collideTiles=true, collideRaycast=true)
|
|
1999
2037
|
{
|
|
2000
2038
|
ASSERT(collideSolidObjects || !isSolid, 'solid objects must be set to collide');
|
|
2001
2039
|
|
|
2002
2040
|
this.collideSolidObjects = collideSolidObjects;
|
|
2003
2041
|
this.isSolid = isSolid;
|
|
2004
2042
|
this.collideTiles = collideTiles;
|
|
2043
|
+
this.collideRaycast = collideRaycast;
|
|
2005
2044
|
}
|
|
2006
2045
|
|
|
2007
2046
|
/** Returns string containg info about this object for debugging
|
|
@@ -3654,7 +3693,7 @@ function tileCollisionTest(pos, size=vec2(), object)
|
|
|
3654
3693
|
}
|
|
3655
3694
|
}
|
|
3656
3695
|
|
|
3657
|
-
/** Return the center of tile
|
|
3696
|
+
/** Return the center of first tile hit (does not return the exact intersection)
|
|
3658
3697
|
* @param {Vector2} posStart
|
|
3659
3698
|
* @param {Vector2} posEnd
|
|
3660
3699
|
* @param {EngineObject} [object]
|
|
@@ -3850,8 +3889,11 @@ class TileLayer extends EngineObject
|
|
|
3850
3889
|
mainCanvas.height = mainCanvasSize.y;
|
|
3851
3890
|
}
|
|
3852
3891
|
|
|
3853
|
-
//
|
|
3854
|
-
|
|
3892
|
+
// disable smoothing for pixel art
|
|
3893
|
+
this.context.imageSmoothingEnabled = !canvasPixelated;
|
|
3894
|
+
|
|
3895
|
+
// setup gl rendering if enabled
|
|
3896
|
+
glEnable && glPreRender();
|
|
3855
3897
|
}
|
|
3856
3898
|
|
|
3857
3899
|
/** Call to end the redraw process */
|
|
@@ -5000,7 +5042,7 @@ const engineName = 'LittleJS';
|
|
|
5000
5042
|
* @type {String}
|
|
5001
5043
|
* @default
|
|
5002
5044
|
* @memberof Engine */
|
|
5003
|
-
const engineVersion = '1.9.
|
|
5045
|
+
const engineVersion = '1.9.5';
|
|
5004
5046
|
|
|
5005
5047
|
/** Frames per second to update
|
|
5006
5048
|
* @type {Number}
|
|
@@ -5067,6 +5109,19 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5067
5109
|
{
|
|
5068
5110
|
ASSERT(Array.isArray(imageSources), 'pass in images as array');
|
|
5069
5111
|
|
|
5112
|
+
// Called automatically by engine to setup render system
|
|
5113
|
+
function enginePreRender()
|
|
5114
|
+
{
|
|
5115
|
+
// save canvas size
|
|
5116
|
+
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
5117
|
+
|
|
5118
|
+
// disable smoothing for pixel art
|
|
5119
|
+
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
5120
|
+
|
|
5121
|
+
// setup gl rendering if enabled
|
|
5122
|
+
glEnable && glPreRender();
|
|
5123
|
+
}
|
|
5124
|
+
|
|
5070
5125
|
// internal update loop for engine
|
|
5071
5126
|
function engineUpdate(frameTimeMS=0)
|
|
5072
5127
|
{
|
|
@@ -5224,7 +5279,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5224
5279
|
}
|
|
5225
5280
|
image.src = src;
|
|
5226
5281
|
})
|
|
5227
|
-
)
|
|
5282
|
+
);
|
|
5228
5283
|
|
|
5229
5284
|
// draw splash screen
|
|
5230
5285
|
showSplashScreen && promises.push(new Promise(resolve =>
|
|
@@ -5249,19 +5304,6 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
5249
5304
|
});
|
|
5250
5305
|
}
|
|
5251
5306
|
|
|
5252
|
-
// Called automatically by engine to setup render system
|
|
5253
|
-
function enginePreRender()
|
|
5254
|
-
{
|
|
5255
|
-
// save canvas size
|
|
5256
|
-
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
5257
|
-
|
|
5258
|
-
// disable smoothing for pixel art
|
|
5259
|
-
mainContext.imageSmoothingEnabled = !canvasPixelated;
|
|
5260
|
-
|
|
5261
|
-
// setup gl rendering if enabled
|
|
5262
|
-
glEnable && glPreRender();
|
|
5263
|
-
}
|
|
5264
|
-
|
|
5265
5307
|
/** Update each engine object, remove destroyed objects, and update time
|
|
5266
5308
|
* @memberof Engine */
|
|
5267
5309
|
function engineObjectsUpdate()
|
|
@@ -5295,30 +5337,63 @@ function engineObjectsDestroy()
|
|
|
5295
5337
|
engineObjects = engineObjects.filter(o=>!o.destroyed);
|
|
5296
5338
|
}
|
|
5297
5339
|
|
|
5298
|
-
/**
|
|
5299
|
-
* @param {Vector2} [pos] - Center of test area
|
|
5340
|
+
/** Collects all object within a given area
|
|
5341
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
5300
5342
|
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
5301
|
-
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
5302
5343
|
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
5344
|
+
* @return {Array} - List of collected objects
|
|
5303
5345
|
* @memberof Engine */
|
|
5304
|
-
function
|
|
5346
|
+
function engineObjectsCollect(pos, size, objects=engineObjects)
|
|
5305
5347
|
{
|
|
5348
|
+
const collectedObjects = [];
|
|
5306
5349
|
if (!pos) // all objects
|
|
5307
5350
|
{
|
|
5308
5351
|
for (const o of objects)
|
|
5309
|
-
|
|
5352
|
+
collectedObjects.push(o);
|
|
5310
5353
|
}
|
|
5311
|
-
else if (
|
|
5354
|
+
else if (size instanceof Vector2) // bounding box test
|
|
5312
5355
|
{
|
|
5313
5356
|
for (const o of objects)
|
|
5314
|
-
isOverlapping(pos, size, o.pos, o.size) &&
|
|
5357
|
+
isOverlapping(pos, size, o.pos, o.size) && collectedObjects.push(o);
|
|
5315
5358
|
}
|
|
5316
5359
|
else // circle test
|
|
5317
5360
|
{
|
|
5318
5361
|
const sizeSquared = size*size;
|
|
5319
5362
|
for (const o of objects)
|
|
5320
|
-
pos.distanceSquared(o.pos) < sizeSquared &&
|
|
5363
|
+
pos.distanceSquared(o.pos) < sizeSquared && collectedObjects.push(o);
|
|
5364
|
+
}
|
|
5365
|
+
return collectedObjects;
|
|
5366
|
+
}
|
|
5367
|
+
|
|
5368
|
+
/** Triggers a callback for each object within a given area
|
|
5369
|
+
* @param {Vector2} [pos] - Center of test area, or undefined for all objects
|
|
5370
|
+
* @param {Number|Vector2} [size] - Radius of circle if float, rectangle size if Vector2
|
|
5371
|
+
* @param {Function} [callbackFunction] - Calls this function on every object that passes the test
|
|
5372
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
5373
|
+
* @memberof Engine */
|
|
5374
|
+
function engineObjectsCallback(pos, size, callbackFunction, objects=engineObjects)
|
|
5375
|
+
{ engineObjectsCollect(pos, size, objects).forEach(o => callbackFunction(o)); }
|
|
5376
|
+
|
|
5377
|
+
/** Return a list of objects intersecting a ray
|
|
5378
|
+
* @param {Vector2} start
|
|
5379
|
+
* @param {Vector2} end
|
|
5380
|
+
* @param {Array} [objects=engineObjects] - List of objects to check
|
|
5381
|
+
* @return {Array} - List of objects hit
|
|
5382
|
+
* @memberof Engine */
|
|
5383
|
+
function engineObjectsRaycast(start, end, objects=engineObjects)
|
|
5384
|
+
{
|
|
5385
|
+
const hitObjects = [];
|
|
5386
|
+
for (const o of objects)
|
|
5387
|
+
{
|
|
5388
|
+
if (o.collideRaycast && isIntersecting(start, end, o.pos, o.size))
|
|
5389
|
+
{
|
|
5390
|
+
debugRaycast && debugRect(o.pos, o.size, '#f00');
|
|
5391
|
+
hitObjects.push(o);
|
|
5392
|
+
}
|
|
5321
5393
|
}
|
|
5394
|
+
|
|
5395
|
+
debugRaycast && debugLine(start, end, hitObjects.length ? '#f00' : '#00f', .02);
|
|
5396
|
+
return hitObjects;
|
|
5322
5397
|
}
|
|
5323
5398
|
|
|
5324
5399
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -5406,16 +5481,16 @@ function drawEngineSplashScreen(t)
|
|
|
5406
5481
|
rect(37,14,9,6);
|
|
5407
5482
|
|
|
5408
5483
|
// big stack
|
|
5409
|
-
rect(50,20,10,-
|
|
5410
|
-
rect(50,20,6.5,-
|
|
5411
|
-
rect(50,20,3.5,-
|
|
5412
|
-
rect(50,20,10,-
|
|
5413
|
-
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
5414
|
-
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
5415
|
-
circle(55,2,11.4,.5,PI-.5)
|
|
5416
|
-
rect(45,7,20,-7,color(0,2))
|
|
5417
|
-
rect(45,
|
|
5418
|
-
rect(45,
|
|
5484
|
+
rect(50,20,10,-8,color(0,1))
|
|
5485
|
+
rect(50,20,6.5,-8,color(0,2))
|
|
5486
|
+
rect(50,20,3.5,-8,color(0,3))
|
|
5487
|
+
rect(50,20,10,-8)
|
|
5488
|
+
circle(55,2,11.4,.5,PI-.5,color(3,3))
|
|
5489
|
+
circle(55,2,11.4,.5,PI/2,color(3,2),1)
|
|
5490
|
+
circle(55,2,11.4,.5,PI-.5)
|
|
5491
|
+
rect(45,7,20,-7,color(0,2))
|
|
5492
|
+
rect(45,-1,20,4,color(0,3))
|
|
5493
|
+
rect(45,-1,20,8)
|
|
5419
5494
|
|
|
5420
5495
|
// engine
|
|
5421
5496
|
for (let i=5; i--;)
|