-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengine.min.js
More file actions
1 lines (1 loc) · 93 KB
/
Copy pathengine.min.js
File metadata and controls
1 lines (1 loc) · 93 KB
1
function test2(){};function randInt(min,max){return Math.floor(min+Math.random()*(max-min+1));};function randFloat(min,max){return min+Math.random()*(max-min);};function weightedRandom(weightSet){let sum=0;let rnd=Math.random();for(let value in weightSet){sum+=weightSet[value];if(rnd<=sum)return value;};return Object.keys(weightSet)[0];};function distance(x1,y1,x2,y2){let dx=x2-x1;let dy=y2-y1;return Math.sqrt(dx*dx+dy*dy);};function clamp(value,min,max){return Math.min(max,Math.max(value,min));};function round(value,precision=2){return Math.round(value*Math.pow(10,precision))/Math.pow(10,precision);};function makeFinite(value){return Math.fround(value);};function lerp(baseValue,targetValue,amount=0.9){return baseValue+(targetValue-baseValue)*amount;};function sin(angle){return Math.sin(angle*Math.PI/180);};function cos(angle){return Math.cos(angle*Math.PI/180);};function pol(x,y){return{angle:Math.atan2(y,x)*(180/Math.PI),length:distance(0,0,x,y)};};function rec(a,l){return{x:cos(a)*l,y:sin(a)*l};}class Vector{x=0;y=0;get length(){if(this.x==0&&this.y==0)return0;return Math.sqrt(this.x**2+this.y**2);};get angle(){return(Math.atan2(this.y,this.x)*180)/Math.PI;};constructor(x,y){if(x==undefined){this.x=0;this.y=0;}else{this.x=x;if(y==undefined)this.y=x;else this.y=y;};};static fromObject(o){return new Vector(o.x,o.y);};static fromArray(a){return new Vector(a[0],a[1]);};static fromAngle(angle,length){return new Vector(cos(angle),sin(angle)).mult(length);};static dot(v1,v2){return v1.x*v2.x+v1.y*v2.y;};static cross(v1,v2){return v1.x*v2.y-v1.y*v2.x;};static lerp(v1,v2,amount=0.9){return new Vector(lerp(v1.x,v2.x,amount),lerp(v1.y,v2.y,amount));};toArray(){return[this.x,this.y];};toObject(){return{x:this.x,y:this.y};};render(x,y,scale=1,color="#00ffff"){ctx.strokeStyle=color;ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x+this.x*scale,y+this.y*scale);ctx.stroke();};isEqual(v2,y=null){return y==null?(this.x==v2.x&&this.y==v2.y):(this.x==v2&&this.y==y)};isNull(){return this.x===null||this.y===null||this.x===NaN||this.y===NaN||this.x===undefined||this.y===undefined;};copy(){return new Vector(this.x,this.y);};unit(n=1){if(n==0)return new Vector();return new Vector(this.x==0?0:(this.x/this.length)*n,this.y==0?0:(this.y/this.length)*n);};normal(n=1){return new Vector(-this.y,this.x).unit(n);};mult(n){if(n instanceof Vector){return new Vector(this.x*n.x,this.y*n.y);}else{return new Vector(this.x*n,this.y*n);};};add(v2){return new Vector(this.x+v2.x,this.y+v2.y);};sub(v2){return new Vector(this.x-v2.x,this.y-v2.y);};round(n=0){return new Vector(round(this.x,n),round(this.y,n));};}class Camera{pos=new Vector();#realPos=new Vector();zoom=1;#realZoom=1;settings={rounded:false,finite:false,zoomSpeed:-1,glideSpeed:-1,minZoom:0.1,maxZoom:5,};get realZoom(){return this.#realZoom;};get realPos(){return this.#realPos;};constructor(pos,zoom=1,settings={}){this.pos=pos;this.#realPos=pos;this.zoom=zoom;this.#realZoom=zoom;this.settings={rounded:false,finite:false,zoomSpeed:-1,glideSpeed:-1,minZoom:0.1,maxZoom:5,};for(let key in settings){this.settings[key]=settings[key];};};setZoom(zoom,instant=false){this.zoom=clamp(zoom,this.settings.minZoom,this.settings.maxZoom);if(instant)this.#realZoom=this.zoom;};lookAt(pos,instant=false){let center=new Vector(c.width/this.zoom,c.height/this.zoom).mult(0.5);this.pos=pos.sub(center);if(instant)this.#realPos=this.pos;};clampValues(){this.#realZoom=clamp(this.#realZoom,this.settings.minZoom,this.settings.maxZoom);this.zoom=clamp(this.zoom,this.settings.minZoom,this.settings.maxZoom);};update(){if(this.settings.zoomSpeed==-1){this.#realZoom=this.zoom;}else{this.#realZoom=lerp(this.#realZoom,this.zoom,this.settings.zoomSpeed);};if(this.settings.glideSpeed==-1){this.#realPos=this.pos;}else{this.#realPos=Vector.lerp(this.#realPos,this.pos,this.settings.glideSpeed);};if(this.settings.finite){this.#realPos=new Vector(makeFinite(this.#realPos.x),makeFinite(this.#realPos.y));this.#realZoom=makeFinite(this.#realZoom);};if(this.settings.rounded){this.#realPos=this.#realPos.round(this.rounded);};this.clampValues();};renderTexture(textureInstance,x,y,width,height,rotation=0,margin=0){if(typeof(textureInstance?.render)!==typeof(Function))console.error("Invalid instance found:",textureInstance);textureInstance.render(...this.worldToCamXY(x,y),...this.worldToCamSizeXY(width,height),rotation=rotation,margin=margin)};render(){ctx.strokeStyle="red";ctx.lineWidth=1;ctx.beginPath();ctx.rect(...this.#realPos.toArray(),c.width*this.#realZoom,c.height*this.#realZoom);ctx.stroke();};worldToCamSize(v){return v.mult(this.#realZoom);};get worldToScreenSize(){return this.worldToCamSize.bind(this);};get w2cs(){return this.worldToCamSize.bind(this);};worldToCamSizeXY(width,height){return[width*this.#realZoom,height*this.#realZoom];};get worldToScreenSizeXY(){return this.worldToCamSizeXY.bind(this);};get w2csXY(){return this.worldToCamSizeXY.bind(this);};worldToCamSizeX(width){return width*this.#realZoom;};get worldToScreenSizeX(){return this.worldToCamSizeX.bind(this);};get w2csX(){return this.worldToCamSizeX.bind(this);};worldToCamSizeY(height){return height*this.#realZoom;};get worldToScreenSizeY(){return this.worldToCamSizeY.bind(this);};get w2csY(){return this.worldToCamSizeY.bind(this);};worldToCam(v){return v.sub(this.#realPos).mult(this.#realZoom);};get worldToScreen(){return this.worldToCam.bind(this);};get w2c(){return this.worldToCam.bind(this);};worldToCamXY(x,y){return[(x-this.#realPos.x)*this.#realZoom,(y-this.#realPos.y)*this.#realZoom];};get worldToScreenXY(){return this.worldToCamXY.bind(this);};get w2cXY(){return this.worldToCamXY.bind(this);};worldToCamX(x){return(x-this.#realPos.x)*this.#realZoom;};get worldToScreenX(){return this.worldToCamX.bind(this);};get w2cX(){return this.worldToCamX.bind(this);};worldToCamY(y){return(y-this.#realPos.y)*this.#realZoom;};get worldToScreenY(){return this.worldToCamY.bind(this);};get w2cY(){return this.worldToCamY.bind(this);};w2cf(pos,size){return[...this.w2c(pos).toArray(),...this.w2cs(size).toArray()];};w2cfXY(x,y,w,h){return[...this.w2cXY(x,y),...this.w2csXY(w,h)];};camToWorldSize(v){return v.mult(1/this.#realZoom);};get screenToWorldSize(){return this.camToWorldSize.bind(this);};get c2ws(){return this.camToWorldSize.bind(this);};camToWorldSizeXY(width,height){return[width/this.#realZoom,height/this.#realZoom];};get screenToWorldSizeXY(){return this.camToWorldSizeXY.bind(this);};get c2wsXY(){return this.camToWorldSizeXY.bind(this);};camToWorldSizeX(width){return width/this.#realZoom;};get screenToWorldSizeX(){return this.camToWorldSizeX.bind(this);};get c2wsX(){return this.camToWorldSizeX.bind(this);};camToWorldSizeY(height){return height/this.#realZoom;};get screenToWorldSizeY(){return this.camToWorldSizeY.bind(this);};get c2wsY(){return this.camToWorldSizeY.bind(this);};camToWorld(v){return v.add(this.#realPos.mult(this.#realZoom)).mult(1/this.#realZoom);};get screenToWorld(){return this.camToWorld.bind(this);};get c2w(){return this.camToWorld.bind(this);};camToWorldXY(x,y){return[(x+this.#realPos.x)/this.#realZoom,(y+this.#realPos.y)/this.#realZoom];};get screenToWorldXY(){return this.camToWorldXY.bind(this);};get c2wXY(){return this.camToWorldXY.bind(this);};camToWorldX(x){return(x+this.#realPos.x)/this.#realZoom;};get screenToWorldX(){return this.camToWorldX.bind(this);};get c2wX(){return this.camToWorldX.bind(this);};camToWorldY(y){return(y+this.#realPos.y)/this.#realZoom;};get screenToWorldY(){return this.camToWorldY.bind(this);};get c2wY(){return this.camToWorldY.bind(this);};}class Color{#baseColor=[0,0,0,0];#color=[0,0,0,0];set r(value){this.#baseColor[0]=makeFinite(clamp(value/255,0,1));this.#syncColors();};get r(){return this.#color[0]*255;};set g(value){this.#baseColor[1]=makeFinite(clamp(value/255,0,1));this.#syncColors();};get g(){return this.#color[1]*255;};set b(value){this.#baseColor[2]=makeFinite(clamp(value/255,0,1));this.#syncColors();};get b(){return this.#color[2]*255;};set a(value){this.#baseColor[3]=makeFinite(clamp(value/255,0,1));this.#syncColors();};get a(){return this.#color[3]*255;};get brightness(){return(this.#color[0]*0.2989+this.#color[1]*0.5870+this.#color[2]*0.1140)*255;};set brightness(value){this.#color=[this.#baseColor[0]*value,this.#baseColor[1]*value,this.#baseColor[2]*value,this.#baseColor[3]*value,];};#numToHex(c){let hex=c.toString(16);return hex.length==1?"0"+hex:hex;};get hexString(){return "#"+this.#numToHex(this.r)+this.#numToHex(this.g)+this.#numToHex(this.b)+this.#numToHex(this.a);};get rgbString(){return "#"+this.#numToHex(this.r)+this.#numToHex(this.g)+this.#numToHex(this.b)+this.#numToHex(this.a);};constructor(color="#000000ff",g=null,b=null,a=null){if(g){this.#baseColor=[color,g,b,a];}else{let offCanvas=new OffscreenCanvas(1,1);let offCtx=offCanvas.getContext("2d");offCtx.fillStyle=color;offCtx.fillRect(0,0,1,1);let pixelData=offCtx.getImageData(0,0,1,1).data;this.#baseColor=[pixelData[0]/255,pixelData[1]/255,pixelData[2]/255,pixelData[3]/255];this.#syncColors();};};#syncColors(){this.#color=[...this.#baseColor];};multiplyAlpha(){this.#baseColor[0]=this.#color[0]*this.#color[3];this.#baseColor[1]=this.#color[1]*this.#color[3];this.#baseColor[2]=this.#color[2]*this.#color[3];this.#baseColor[3]=1;this.#syncColors();};static addBrightness(color,brightness){let offCanvas=new OffscreenCanvas(1,1);let offCtx=offCanvas.getContext("2d");offCtx.fillStyle=color;offCtx.fillRect(0,0,1,1);let pixelData=offCtx.getImageData(0,0,1,1).data;return[pixelData[0]*brightness,pixelData[1]*brightness,pixelData[2]*brightness,pixelData[3]*brightness];};add(color2){this.r+=color2.r;this.g+=color2.g;this.b+=color2.b;this.a+=color2.a;};mult(color2){let color2Norm=color2.normalised();this.#color[0]=makeFinite(clamp(this.#color[0]*color2Norm[0],0,1));this.#color[1]=makeFinite(clamp(this.#color[1]*color2Norm[1],0,1));this.#color[2]=makeFinite(clamp(this.#color[2]*color2Norm[2],0,1));this.#color[3]=makeFinite(clamp(this.#color[3]*color2Norm[3],0,1));};normalised(){return[this.#color[0],this.#color[1],this.#color[2],this.#color[3],];};setRgb(r=0,g=0,b=0,a=255){this.r=r;this.g=g;this.b=b;this.a=a;};static fromRgb(r=0,g=0,b=0){return new Color(`rgb(${r},${g},${b})`);};static fromRgba(r=0,g=0,b=0,a=255){return new Color(`rgb(${r},${g},${b},${a / 255})`);};static fromObject(object){return new Color(`rgba(${object?.r ?? 0},${object?.g ?? 0},${object?.b ?? 0},${(object?.a ?? 255) / 255})`);};static fromArray(array){if(!(array instanceof Array))return new Color();let a=[...array,0,0,0,255];return new Color(`rgba(${a[0]},${a[1]},${a[2]},${a[3] / 255})`);};static fromString(string){if(!(string instanceof String))return new Color();return new Color(string);};toArray(){return[this.#color[0]*255,this.#color[1]*255,this.#color[2]*255,this.#color[3]*255,];};toObject(){return{r:this.#color[0]*255,g:this.#color[1]*255,b:this.#color[2]*255,a:this.#color[3]*255,};};}function canvasFillScreen(){c.width=c.offsetWidth;c.height=c.offsetHeight;c.size=new Vector(c.width,c.height);c.center=c.size.mult(0.5);};function pushNotification(message,delay=1+message.length*0.08,type="normal"){let container=document.getElementById("notContainer");if(container==null){container=document.createElement("div");container.id="notContainer";document.body.appendChild(container);};if(container.children.length>=settings.maxNotificationCount){let childIndex=0;container.children[childIndex].remove();};let newNot=document.createElement("div");newNot.classList.add("notification");newNot.classList.add(type);newNot.onanimationend=function(e){if(e.animationName=="pop-in"){e.target.style.animationName="pop-out";e.target.style.animationDelay=delay+"s";};if(e.animationName=="pop-out"){e.target.remove();};};let newP=document.createElement("p");newP.textContent=message;newNot.appendChild(newP);container.appendChild(newNot);};function setClass(element,calssName,state){if(!element)return;if(element.classList.contains(calssName)!=state)element.classList.toggle(calssName);};function buildDebugMenu(){let container=document.getElementById("debug");if(container!==null)return;container=document.createElement("div");container.id="debug";container.classList.add("hidden");container.innerHTML=`<pre id="fps">FPS: 60 UPS: 120</pre><pre id="text"></pre>`;document.body.appendChild(container);};function buildLoadingBar(){let container=document.getElementById("loading_overlay");if(container!==null)return;container=document.createElement("div");container.id="loading_overlay";container.innerHTML=`<h1>Loading...</h1><div id="loading_bar"><div class="background"></div></div>`;document.body.appendChild(container);};function setLoadingBarProgress(percent){let loadingBar=document.querySelector("#loading_bar .background");if(loadingBar===null)return;loadingBar.style.width=percent+"%";};function addDebugOption(id,title,type,defaultValue,value){let container=document.getElementById("debug");let newOptionContainer=document.createElement("div");newOptionContainer.classList.add("item");newOptionContainer.innerHTML=`<label>${title}</label>`;switch(type){case "bool":newOptionContainer.innerHTML+=`<input id="${id}" type="checkbox"${defaultValue ? " checked" : ""}>`;break;case "range":newOptionContainer.innerHTML+=`<input id="${id}" type="range" value="${defaultValue}" min="${value?.min}" max="${value?.max}" step="${value?.step}">`;break;case "number":newOptionContainer.innerHTML+=`<input id="${id}" type="number" value="${defaultValue}">`;break;case "text":newOptionContainer.innerHTML+=`<input id="${id}" type="text">`;break;case "list":let selectElement=`<select id="${id}">`;for(let key in value){console.log(key,newOptionContainer.innerHTML);selectElement+=`<option value="${key}"${defaultValue == key ? " selected" : ""}>${value[key]}</option>`;};selectElement+=`</select>`;newOptionContainer.innerHTML+=selectElement;break;};container.appendChild(newOptionContainer);settings.debug[id]=defaultValue;};function setDebugMenu(state=true){setClass(document.getElementById("debug"),"hidden",!state);};class Panel extends HTMLElement{static observedAttributes=["src","margin"];margin=0;image;texture;constructor(){super();this.image=new Image();this.canvas=new OffscreenCanvas(16,16);};connectedCallback(){let self=this;window.addEventListener("resize",function(e){if(!self.image.complete)return;let offCtx=self.canvas.getContext("2d");self.canvas.width=self.offsetWidth;self.canvas.height=self.offsetHeight;offCtx.drawImage(self.image,0,0,self.canvas.width,self.canvas.height);self.style.backgroundImage=self.image;console.log(self);});};disconnectedCallback(){console.log("Custom element removed from page.");};connectedMoveCallback(){console.log("Custom element moved with moveBefore()");};adoptedCallback(){console.log("Custom element moved to new page.");};attributeChangedCallback(name,oldValue,newValue){if(name=="src"){this.image.src=newValue;};if(name=="margin"){this.margin=parseInt(newValue);};};};customElements.define("ui-panel",Panel);class BaseResource{resourceId="";uid="";disabled=false;constructor(resourceId){this.resourceId=resourceId;this.uid=Resource.generateResourceUID(resourceId);};update(){};render(){};destroy(){this.disabled=true;};};class Object2D{pos=new Vector();size=new Vector();disabled=false;get width(){return this.size.x;};get height(){return this.size.y;};get left(){return Math.min(this.pos.x,this.pos.x+this.size.x);};get right(){return Math.max(this.pos.x,this.pos.x+this.size.x);};get top(){return Math.min(this.pos.y,this.pos.y+this.size.y);};get bottom(){return Math.max(this.pos.y,this.pos.y+this.size.y);};get center(){return this.pos.add(this.size.mult(0.5));};get centerOffset(){return this.size.mult(0.5);};constructor(position=new Vector(0,0),size=new Vector(1,1)){this.pos=position;this.size=size;};setCenter(position){this.pos=position.sub(this.centerOffset);};update(){};render(){};destroy(){this.disabled=true;};};class PhysicsObject2D extends Object2D{vel=new Vector();constructor(position,size,velocity=new Vector(0,0)){super(position,size);this.vel=velocity;};update(){this.pos=this.pos.add(this.vel);this.vel=this.vel.mult(0.99);};render(){};destroy(){this.disabled=true;};}class Label2D extends Object2D{color="#dddddd";fontFamily="monospace";fontSize=16;#textcontent="";maxWidth=Infinity;set text(text){this.#textcontent=text;this.#updateSize();};constructor(text,position,color="#dddddd"){super(position);this.text=text;this.color=color;};get text(){return this.#textcontent;};setFont(fontFamily,fontSize=this.fontSize){this.fontFamily=fontFamily;this.fontSize=fontSize;this.#updateSize();};setSize(fontSize){this.fontSize=fontSize;this.#updateSize();};#updateSize(){let oldFontSize=parseInt(ctx.font,10);let oldFontFamily=ctx.font.split(' ').slice(1).join(' ');ctx.font=`${this.fontSize}px ${this.fontFamily}`;this.size.x=ctx.measureText(this.#textcontent).width;this.size.y=this.fontSize;ctx.font=`${oldFontSize}px ${oldFontFamily}`;};render(){ctx.font=`${camera.w2csX(this.fontSize)}px ${this.fontFamily}`;ctx.fillStyle=this.color;ctx.fillText(this.text,...camera.w2cXY(this.left,this.bottom));if(settings.debug?.boxes){ctx.strokeStyle=this.color;ctx.beginPath();ctx.strokeRect(...camera.w2cf(this.pos,this.size));};};};class Point extends Object2D{color="#00ddff";constructor(x,y,color="#00ddff"){super(new Vector(x,y),new Vector(1));this.color=color;};render(offset){ctx.fillStyle=this.color;ctx.beginPath();ctx.arc(...camera.w2c(this.pos.add(offset)).toArray(),10,0,Math.PI*2);ctx.fill();};};class Line{start=new Vector();end=new Vector();color="#55ff44";constructor(start,end,color="#55ff44"){this.start=start;this.end=end;this.color=color;};render(offset){ctx.strokeStyle=this.color;ctx.lineWidth=5;ctx.lineCap="round";ctx.lineJoin="round";ctx.beginPath();ctx.moveTo(...camera.w2c(this.start.add(offset)).toArray());ctx.lineTo(...camera.w2c(this.end.add(offset)).toArray());ctx.stroke();};}class Grid{defaultValue=null;size=new Vector();hashFunction;#data;get width(){return this.size.x;};get height(){return this.size.y;};get data(){return this.#data;};constructor(width,height,defaultValue=null,hashFunction=null){this.size=new Vector(width,height);this.defaultValue=defaultValue;this.#data=[];for(let y=0;y<height;y++){let row=[];for(let x=0;x<width;x++){row.push(structuredClone(this.defaultValue));};this.#data.push(row);};this.hashFunction=hashFunction;this.hashFunction??=function(cell){return cell;};};static fromArray(array,width){if(array.length==0)return;let newGrid;let firstItem=array[0];if(firstItem instanceof Array){newGrid=new Grid(firstItem.length,array.length);newGrid.map(function(x,y,cell){return array[y][x];});}else{newGrid=new Grid(width,Math.ceil(array.length/width));let lengthDiff=Math.ceil(array.length/width)*width-array.length;if(lengthDiff>0){array=array.concat(Array(lengthDiff).fill(null));};newGrid.map(function(x,y,cell){return array[Grid.coordinateToIndex(x,y,newGrid.width)];});};return newGrid;};toArray(mode="2d"){switch(mode){default:case "2d":return this.#data;case "1d":let out=[];for(let row of this.#data){out=out.concat(row);};return out;};};isInGrid(x,y){return x>=0&&x<this.size.x&&y>=0&&y<this.size.y;};setCell(x,y,value){if(!this.isInGrid(x,y))return false;this.#data[y][x]=value;return true;};getCell(x,y,defaultValue=this.defaultValue){if(!this.isInGrid(x,y))return defaultValue;return this.#data[y][x];};static indexToCoordinate(index,gridWidth){return new Vector(index%gridWidth,Math.floor(index/gridWidth));};static coordinateToIndex(x,y,gridWidth){return y*gridWidth+x;};resize(newWidth,newHeight,defaultValue=this.defaultValue){let originalSize=this.size.copy();this.size=new Vector(newWidth,newHeight);if(newHeight>originalSize.y){for(let i=0;i<newHeight-originalSize.y;i++){let extraRow=[];for(let i=0;i<newWidth;i++){extraRow.push(structuredClone(defaultValue));};this.#data.push(extraRow);};};if(newHeight<originalSize.y){let newData=[];for(let i=0;i<newHeight;i++){newData[i]=this.#data[i]};this.#data=newData;};if(newWidth>originalSize.x){for(let y=0;y<this.#data.length;y++){let extraValues=[];for(let i=0;i<newWidth-originalSize.x;i++){extraValues.push(structuredClone(defaultValue));};this.#data[y]=this.#data[y].concat(extraValues);};};if(newWidth<originalSize.x){for(let y=0;y<this.#data.length;y++){let newRow=[];for(let i=0;i<newWidth;i++){newRow[i]=this.#data[y][i]};this.#data[y]=newRow;};};return originalSize;};fill(cellValue){for(let y=0;y<this.height;y++){for(let x=0;x<this.width;x++){this.#data[y][x]=structuredClone(cellValue);};};};forEach(callback){for(let y=0;y<this.height;y++){for(let x=0;x<this.width;x++){callback(x,y,this.#data[y][x]);};};};map(callback){for(let y=0;y<this.height;y++){for(let x=0;x<this.width;x++){this.#data[y][x]=callback(x,y,this.#data[y][x]);};};};greedyMesh(firstAxis="x",hashFunction=null){};findIslands(defaultValue=this.defaultValue,hashFunction=this.hashFunction){bodyColors=[];resetBodyIndexes();let unassignedCell=undefined;let currentBodyIndex=startIndex-1;while(true){unassignedCell=findCellByBodyIndex(grid,-1);if(unassignedCell==undefined)break;let fillQueue=[];let processedCells=[];currentBodyIndex++;let iter=0;do{let cell=unassignedCell;if(iter!=0){cell=fillQueue.pop();};processedCells.push(cell);if(getBlockName(cell.type)=="air")continue;cell.bodyIndex=currentBodyIndex;let topCell=undefined;let rightCell=undefined;let bottomCell=undefined;let leftCell=undefined;let x=cell.pos.x;let y=cell.pos.y;if(cell.sides[0]==1){topCell=getGridCell(x,y-1,grid);};if(cell.sides[1]==1){rightCell=getGridCell(x+1,y,grid);};if(cell.sides[2]==1){bottomCell=getGridCell(x,y+1,grid);};if(cell.sides[3]==1){leftCell=getGridCell(x-1,y,grid);};if(topCell!=undefined&&topCell.sides[2]==0)topCell=undefined;if(rightCell!=undefined&&rightCell.sides[3]==0)rightCell=undefined;if(bottomCell!=undefined&&bottomCell.sides[0]==0)bottomCell=undefined;if(leftCell!=undefined&&leftCell.sides[1]==0)leftCell=undefined;if(topCell!=undefined&&processedCells.indexOf(topCell)==-1)fillQueue.push(topCell);if(rightCell!=undefined&&processedCells.indexOf(rightCell)==-1)fillQueue.push(rightCell);if(bottomCell!=undefined&&processedCells.indexOf(bottomCell)==-1)fillQueue.push(bottomCell);if(leftCell!=undefined&&processedCells.indexOf(leftCell)==-1)fillQueue.push(leftCell);iter++;}while(iter<gridWidth*gridHeight&&fillQueue.length>0);};let numOfBodies=(currentBodyIndex-startIndex)+1;for(let i=0;i<numOfBodies;i++){bodyColors.push(getColorHUE(i/numOfBodies));};return numOfBodies;};copyGrid(grid,pos,size){return create2DArray(size.x,size.y,function(x,y){let originalCell=getGridCell(pos.x+x,pos.y+y,grid);if(originalCell==undefined){return new GridCell(x,y,getBlockType("air"));}else{let cell=new GridCell(x,y,originalCell.type);return cell;};});};pasteGrid(gridX,gridY,blockArray,width,height,ignoreAir=true){for(let y=0;y<height;y++){for(let x=0;x<width;x++){let cell=getGridCell(x,y,blockArray);if(cell==undefined)continue;if(ignoreAir&&getBlockName(cell.type)=="air")continue;let gridCellX=gridX+x;let gridCellY=gridY+y;let gridCell=deepCopy(getGridCell(gridCellX,gridCellY));if(gridCell==undefined)continue;let blockNameUnder=getBlockName(gridCell.type);let blockNamePlaced=getBlockName(cell.type);setGridCell(gridCellX,gridCellY,cell.type);};};};filterCells(grid,filterFn,gridWidth=(grid[0]??[]).length,gridHeight=grid.length){let newGrid=create2DArray(gridWidth,gridHeight,function(x,y){let cell=getGridCell(x,y,grid);if(cell==undefined)return;if(filterFn(x,y,cell)){return cell;}else{return new GridCell(x,y,getBlockType("air"));};});return newGrid;};getBoundingRect(grid,gridWidth=(grid[0]??[]).length,gridHeight=grid.length){let minX=gridWidth;let minY=gridHeight;let maxX=0;let maxY=0;for(let y=0;y<gridHeight;y++){for(let x=0;x<gridWidth;x++){let cell=getGridCell(x,y,grid);if(cell==undefined||getBlockName(cell.type)=="air")continue;if(x<minX)minX=x;if(x>maxX)maxX=x;if(y<minY)minY=y;if(y>maxY)maxY=y;};};return{pos:{x:minX,y:minY,},size:{x:(maxX-minX)+1,y:(maxY-minY)+1,},};};};function findIslands(defaultValue=this.defaultValue,hashFunction=this.hashFunction){bodyColors=[];resetBodyIndexes();let unassignedCell=undefined;let currentBodyIndex=startIndex-1;while(true){unassignedCell=findCellByBodyIndex(grid,-1);if(unassignedCell==undefined)break;let fillQueue=[];let processedCells=[];currentBodyIndex++;let iter=0;do{let cell=unassignedCell;if(iter!=0){cell=fillQueue.pop();};processedCells.push(cell);if(getBlockName(cell.type)=="air")continue;cell.bodyIndex=currentBodyIndex;let topCell=undefined;let rightCell=undefined;let bottomCell=undefined;let leftCell=undefined;let x=cell.pos.x;let y=cell.pos.y;if(cell.sides[0]==1){topCell=getGridCell(x,y-1,grid);};if(cell.sides[1]==1){rightCell=getGridCell(x+1,y,grid);};if(cell.sides[2]==1){bottomCell=getGridCell(x,y+1,grid);};if(cell.sides[3]==1){leftCell=getGridCell(x-1,y,grid);};if(topCell!=undefined&&topCell.sides[2]==0)topCell=undefined;if(rightCell!=undefined&&rightCell.sides[3]==0)rightCell=undefined;if(bottomCell!=undefined&&bottomCell.sides[0]==0)bottomCell=undefined;if(leftCell!=undefined&&leftCell.sides[1]==0)leftCell=undefined;if(topCell!=undefined&&processedCells.indexOf(topCell)==-1)fillQueue.push(topCell);if(rightCell!=undefined&&processedCells.indexOf(rightCell)==-1)fillQueue.push(rightCell);if(bottomCell!=undefined&&processedCells.indexOf(bottomCell)==-1)fillQueue.push(bottomCell);if(leftCell!=undefined&&processedCells.indexOf(leftCell)==-1)fillQueue.push(leftCell);iter++;}while(iter<gridWidth*gridHeight&&fillQueue.length>0);};let numOfBodies=(currentBodyIndex-startIndex)+1;for(let i=0;i<numOfBodies;i++){bodyColors.push(getColorHUE(i/numOfBodies));};return numOfBodies;};function create2DArray(width,height,creatorFunction){let arr=[];for(let y=0;y<height;y++){let row=[];for(let x=0;x<width;x++){row.push(creatorFunction(x,y));};arr.push(row);};return arr;};function clearGrid(forceReset=true){let erasingArray=create2DArray(buildGrid.size.x,buildGrid.size.y,function(x,y){return new GridCell(x,y,getBlockType("air"));});if(forceReset||buildGrid.data.length==0){buildGrid.data=erasingArray;return;};mergeToGridFromArray(0,0,erasingArray,buildGrid.size.x,buildGrid.size.y,false);};function gridHasBlock(blockType){for(let y=0;y<buildGrid.size.y;y++){for(let x=0;x<buildGrid.size.x;x++){let cell=getGridCell(x,y);if(blockType==-1&&getBlockName(cell.type)!="air")return true;if(cell.type==blockType)return true;};};return false;};function getGridCell(x,y,gridArray=buildGrid.data){if(gridArray[y]==undefined)return undefined;return gridArray[y][x];};function setGridCell(x,y,type,gridArray=buildGrid.data){if(type<0||type>=Object.keys(blockData).length)throw new Error(`Block type (${type}) is invalid!`);if(gridArray[y]==undefined)throw new Error(`Position (${x}, ${y}) is out of bounds!`);if(gridArray[y][x]==undefined)throw new Error(`Position (${x}, ${y}) is out of bounds!`);gridArray[y][x].type=type;gridArray[y][x].update();};function setGridCellByName(x,y,name){setGridCell(x,y,getBlockType(name));};function mergeToGridFromArray(gridX,gridY,blockArray,width,height,ignoreAir=true){for(let y=0;y<height;y++){for(let x=0;x<width;x++){let cell=getGridCell(x,y,blockArray);if(cell==undefined)continue;if(ignoreAir&&getBlockName(cell.type)=="air")continue;let gridCellX=gridX+x;let gridCellY=gridY+y;let gridCell=deepCopy(getGridCell(gridCellX,gridCellY));if(gridCell==undefined)continue;let blockNameUnder=getBlockName(gridCell.type);let blockNamePlaced=getBlockName(cell.type);if(blockNameUnder=="air"){if(blockNamePlaced=="air"){setGridCell(gridCellX,gridCellY,cell.type);continue;};_removeBlock(blockNamePlaced);if(_getBlockAmount(blockNamePlaced)<0){_giveBlock(blockNamePlaced);if(!input.mouse.oldDown&&width>1&&height>1){pushNotification(`Not enough ${blockData[blockNamePlaced].name}s!`,0.5,"error");};continue;};setGridCell(gridCellX,gridCellY,cell.type);}else{_giveBlock(blockNameUnder);if(blockNamePlaced=="air"){setGridCell(gridCellX,gridCellY,cell.type);continue;};_removeBlock(blockNamePlaced);if(_getBlockAmount(blockNamePlaced)<0){_giveBlock(blockNamePlaced);_removeBlock(blockNameUnder);if(!input.mouse.oldDown&&width>1&&height>1){pushNotification(`Not enough ${blockData[blockNamePlaced].name}s!`,0.5,"error");};continue;};setGridCell(gridCellX,gridCellY,cell.type);};};};_updateBlockAmountsInHotbar();};function copyFromGrid(grid,pos,size){return create2DArray(size.x,size.y,function(x,y){let originalCell=getGridCell(pos.x+x,pos.y+y,grid);if(originalCell==undefined){return new GridCell(x,y,getBlockType("air"));}else{let cell=new GridCell(x,y,originalCell.type);return cell;};});};function findCellByBodyIndex(grid,bodyIndex,gridWidth=(grid[0]??[]).length,gridHeight=grid.length){for(let y=0;y<gridHeight;y++){for(let x=0;x<gridWidth;x++){let cell=getGridCell(x,y,grid);if(cell==undefined||getBlockName(cell.type)=="air")continue;if(cell.bodyIndex==bodyIndex)return cell;};};return undefined;};function resetBodyIndexes(){for(let y=0;y<buildGrid.size.y;y++){for(let x=0;x<buildGrid.size.x;x++){let cell=getGridCell(x,y);if(cell==undefined)continue;cell.bodyIndex=-1;};};};function filterCells(grid,filterFn,gridWidth=(grid[0]??[]).length,gridHeight=grid.length){let newGrid=create2DArray(gridWidth,gridHeight,function(x,y){let cell=getGridCell(x,y,grid);if(cell==undefined)return;if(filterFn(x,y,cell)){return cell;}else{return new GridCell(x,y,getBlockType("air"));};});return newGrid;};function getBoundingRect(grid,gridWidth=(grid[0]??[]).length,gridHeight=grid.length){let minX=gridWidth;let minY=gridHeight;let maxX=0;let maxY=0;for(let y=0;y<gridHeight;y++){for(let x=0;x<gridWidth;x++){let cell=getGridCell(x,y,grid);if(cell==undefined||getBlockName(cell.type)=="air")continue;if(x<minX)minX=x;if(x>maxX)maxX=x;if(y<minY)minY=y;if(y>maxY)maxY=y;};};return{pos:{x:minX,y:minY,},size:{x:(maxX-minX)+1,y:(maxY-minY)+1,},};};function calculateCenterOfMassGrid(){let sumCellX=0;let sumCellY=0;let cellsFound=0;for(let y=0;y<buildGrid.size.y;y++){for(let x=0;x<buildGrid.size.x;x++){let cell=getGridCell(x,y);if(cell==undefined||getBlockName(cell.type)=="air")continue;for(let i=0;i<blockData[getBlockName(cell.type)].mass*2;i++){sumCellX+=x;sumCellY+=y;cellsFound+=1;};};};sumCellX/=cellsFound;sumCellY/=cellsFound;centerOfMass.x=sumCellX;centerOfMass.y=sumCellY;centerOfMass.visible=cellsFound>0;}let c=document.getElementById("maincv");c.isPixelPerfect=c.classList.contains("pixel-perfect");let ctx=c.getContext("2d");window.onresize=canvasFillScreen;canvasFillScreen();buildDebugMenu();buildLoadingBar();let time={scale:1,fps:{value:60,delta:0,samples:0,buffer:[],bufferSize:4,elapsed:0,lastMeasured:0,lastMeasuredDelta:0,},ups:{value:120,delta:0,samples:0,buffer:[],bufferSize:1,elapsed:0,lastMeasured:0,lastMeasuredDelta:0,},};let settings={maxNotificationCount:5,enableAudio:true,debug:{fpsUpdateInterval:1000,},};let frameCounter=0;let camera=new Camera(new Vector());let _bodyLoaded=false;function _updateTime(timeUnit){let currentValue=makeFinite(time[timeUnit].samples*(1000/settings.debug.fpsUpdateInterval));time[timeUnit].buffer.push(currentValue);if(time[timeUnit].buffer.length>time[timeUnit].bufferSize){time[timeUnit].buffer.shift();};time[timeUnit].value=Math.round(time[timeUnit].buffer.reduce((a,b)=>(a+b))/time[timeUnit].buffer.length);time[timeUnit].lastMeasured=time[timeUnit].elapsed;time[timeUnit].samples=0;};async function _updateLoop(){time.ups.samples++;time.ups.elapsed=performance.now();time.ups.delta=time.ups.elapsed-time.ups.lastMeasuredDelta;Resource.update();if(typeof(update)===typeof(Function))await update(time.ups.delta);if(isKeyJustPressed("debug")){document.getElementById("debug").classList.toggle("hidden");};updateInputs();time.ups.lastMeasuredDelta=time.ups.elapsed;if(time.ups.elapsed-time.ups.lastMeasured>=settings.debug.fpsUpdateInterval){_updateTime("ups");};for(let c of document.getElementById("debug").children){if(!c.classList.contains("item"))continue;let inputElement=c.querySelector("input,option[selected='']");switch(inputElement.getAttribute("type")){case "checkbox":settings.debug[inputElement.getAttribute("id")]=inputElement.checked;break;case "range":case "number":settings.debug[inputElement.getAttribute("id")]=parseFloat(inputElement.value);break;default:settings.debug[inputElement.getAttribute("id")]=inputElement.value;break;};};setTimeout(()=>{_updateLoop()},1);};async function _renderLoop(currentTime){frameCounter++;time.fps.samples++;time.fps.elapsed=Math.floor(currentTime);time.fps.delta=time.fps.elapsed-time.fps.lastMeasuredDelta;document.getElementById("text").textContent="";if(typeof(render)===typeof(Function))await render(time.fps.delta);document.getElementById("fps").textContent=`FPS: ${time.fps.value}\tUPS: ${time.ups.value}\n`;time.fps.lastMeasuredDelta=time.fps.elapsed;if(time.fps.elapsed-time.fps.lastMeasured>=settings.debug.fpsUpdateInterval){_updateTime("fps");};requestAnimationFrame((currentTime)=>{_renderLoop(currentTime);});};window.addEventListener("load",function(){_bodyLoaded=true;_start();});async function _loading(){setLoadingBarProgress((Resource.loaded/Resource.maxLoadables)*100);if(typeof(loading)===typeof(Function))await loading(Resource.maxLoadables,Resource.loaded);};async function _start(){if(!_bodyLoaded)return;if(Resource.loaded<Resource.maxLoadables)return;if(frameCounter!=0)return;document.querySelector("#loading_overlay").classList.add("hidden");if(typeof(init)===typeof(Function))await init();_updateLoop();_renderLoop();}let input={mouse:{x:0,y:0,pos:new Vector(),prevX:0,prevY:0,wheel:0,wheelUp:false,wheelDown:false,motionX:0,motionY:0,left:false,oldLeft:false,right:false,oldRight:false,middle:false,oldMiddle:false,},keys:{justPressed:new Set(),pressed:new Set(),},sensor:{acceleration:{x:0,y:0,z:0,},},controls:{debug:"F2",},};window.addEventListener("keydown",function(e){input.keys.pressed.add(e.key);if(!e.repeat)input.keys.justPressed.add(e.key);});window.addEventListener("keyup",function(e){input.keys.pressed.delete(e.key);input.keys.pressed.delete(e.key.toLowerCase());input.keys.pressed.delete(e.key.toUpperCase());});c.addEventListener("mousedown",function(e){if(document.getElementById("debug")?.contains(e.target))return;_updateMousePosition(e);if(e.button==0)input.mouse.left=true;if(e.button==1)input.mouse.middle=true;if(e.button==2)input.mouse.right=true;});window.addEventListener("mouseup",function(e){_updateMousePosition(e);if(e.button==0)input.mouse.left=false;if(e.button==1)input.mouse.middle=false;if(e.button==2)input.mouse.right=false;});window.addEventListener("mousemove",_updateMousePosition);c.addEventListener("wheel",function(e){_updateMousePosition(e);input.mouse.wheel=e.deltaY;if(e.deltaY<0)input.mouse.wheelUp=true;if(e.deltaY>0)input.mouse.wheelDown=true;});window.addEventListener("blur",_inputLost);window.addEventListener("focus",_inputLost);window.addEventListener("mouseleave",_inputLost);function _syncMousePos(){input.mouse.pos.x=input.mouse.x;input.mouse.pos.y=input.mouse.y;};function _inputLost(){input.mouse.x=0;input.mouse.y=0;input.mouse.left=false;input.mouse.right=false;input.mouse.middle=false;input.keys.pressed.clear();input.keys.justPressed.clear();};function _updateMousePosition(e){input.mouse.x=((e.clientX-c.offsetLeft)/c.offsetWidth)*c.width;input.mouse.y=((e.clientY-c.offsetTop)/c.offsetHeight)*c.height;_syncMousePos();};function updateInputs(){input.keys.justPressed.clear();input.mouse.motionX=input.mouse.x-input.mouse.prevX;input.mouse.motionY=input.mouse.y-input.mouse.prevY;input.mouse.prevX=input.mouse.x;input.mouse.prevY=input.mouse.y;input.mouse.oldLeft=input.mouse.left;input.mouse.oldRight=input.mouse.right;input.mouse.oldMiddle=input.mouse.middle;input.mouse.wheel=0;input.mouse.wheelUp=false;input.mouse.wheelDown=false;};function _testKeyId(filterString,set){let parsedString=_parseFilterString(filterString);let pressed=false;parsedString.every(and=>{pressed=and.every(key=>{return set.has(key);});return!pressed;});return pressed;};function _parseFilterString(filterString){let out=[];let isEscape=false;let currentKey="";let keys=[];for(let i=0;i<filterString.length;i++){if(isEscape){currentKey+=filterString[i];isEscape=false;continue;};if(filterString[i]=="\\"){isEscape=true;continue;};if(filterString[i]==" ")continue;if(filterString[i]=="+"){keys.push(currentKey);currentKey="";continue;};if(filterString[i]==","){keys.push(currentKey);out.push(keys);keys=[];currentKey="";continue;};currentKey+=filterString[i];};if(currentKey!=""){keys.push(currentKey);out.push(keys);};return out;};function setKeybind(bindName,boundKeys){input.controls[bindName]=boundKeys;};function removeKeybind(bindName){if(bindName in input.controls)return;delete input.controls[bindName];};function isKeyPressed(bindName){if(!(bindName in input.controls)){console.error(`Unknown keybind '${bindName}'`);return false;};return _testKeyId(input.controls[bindName],input.keys.pressed);};function isKeyJustPressed(bindName){if(!(bindName in input.controls)){console.error(`Unknown keybind '${bindName}'`);return false;};return _testKeyId(input.controls[bindName],input.keys.justPressed);}class Particle{pos=new Vector();vel=new Vector();airResistance=0.99;colorStart="#ff0000";color="#ffffff";colorEnd="#00ff00";sizeStart=5;size=0;sizeEnd=1;age=0;maxAge=200;lifeProgress=0;disabled=false;constructor(x,y,vx,vy,maxAge){this.pos.x=x;this.pos.y=y;this.vel.x=vx;this.vel.y=vy;this.maxAge=maxAge??this.maxAge;this.disabled=false;objects.particles.push(this);};die(){};#updateEssentials(){if(this.maxAge>0)this.age++;this.lifeProgress=this.age/this.maxAge;let sizeDiff=this.sizeEnd-this.sizeStart;this.size=this.sizeStart+sizeDiff*this.lifeProgress;this.color=this.colorStart.replace(")",`,${1 - this.lifeProgress})`);if(this.maxAge>0&&this.age>this.maxAge){if(!this.disabled)this.die();this.disabled=true;};};update(){this.#updateEssentials();this.pos=this.pos.add(this.vel);this.vel.mult(this.airResistance);};render(){let camPos=cameraTransform(this.pos);ctx.fillStyle=this.color;ctx.beginPath();ctx.arc(camPos.x,camPos.y,this.size*camera.zoom,0,Math.PI*2);ctx.fill();};}class Path{points=[];agents=[];finishedAgents=[];constructor(pointList=[]){this.points=pointList;};get startPoint(){if(this.points.length==0)return null;return this.points[0];};get endPoint(){if(this.points.length==0)return null;return this.points[this.points.length-1];};addAgent(agent){if(!(agent instanceof PathFollow))throw Error("The agent must be an instance of 'PathFollow' !");agent.setPath(this);this.agents.push(agent);};addPointAtEnd(point){if(!(point instanceof Vector))throw Error("The point must be an instance of 'Vector' !");this.points.push(point);};addPointAtStart(point){if(!(point instanceof Vector))throw Error("The point must be an instance of 'Vector' !");this.points.unshift(point);};removePointFromStart(){this.points=this.points.slice(1,this.points.length);};removePointFromEnd(){this.points=this.points.slice(0,-1);};getPoint(index){if(index<0||index>this.points.length-1)return null;return this.points[index];};isValidPointIndex(pointIndex){return pointIndex>0&&pointIndex<this.points.length;};isFirstPointIndex(pointIndex){return pointIndex==0;};isLastPointIndex(pointIndex){return pointIndex==this.points.length-1;};addToFinished(agent){if(!(agent instanceof PathFollow))throw Error("The agent must be an instance of 'PathFollow' !");this.agents=this.agents.filter(a=>a!==agent);this.finishedAgents.push(agent);};removeFromFinished(agent){if(!(agent instanceof PathFollow))throw Error("The agent must be an instance of 'PathFollow' !");this.finishedAgents=this.finishedAgents.filter(a=>a!==agent);};clearFinishedAgents(){this.agents=this.agents.filter(a=>!this.finishedAgents.includes(a));this.finishedAgents=[];};removeAgent(agent){if(!(agent instanceof PathFollow))throw Error("The agent must be an instance of 'PathFollow' !");this.finishedAgents=this.finishedAgents.filter(a=>a!==agent);this.agents=this.agents.filter(a=>a!==agent);};update(){for(let a of this.agents){a.update();};};render(){ctx.fillStyle="#ffff00";for(let p of this.points){ctx.beginPath();ctx.arc(...camera.w2c(p,p).toArray(),camera.w2csX(10),0,Math.PI*2);ctx.fill();};ctx.strokeStyle="#ffff00";ctx.lineWidth=camera.w2csX(5);ctx.beginPath();ctx.moveTo(...camera.w2c(this.points[0]).toArray());for(let p of this.points){ctx.lineTo(...camera.w2c(p).toArray());};ctx.stroke();};};class PathConnection{inputs=[];outputs=[];selectedInput=0;selectedOutput=0;inputMode="all";outputMode="cycle";constructor(inputMode="all",outputMode="cycle",inputPaths=[],outputPaths=[]){this.inputMode=inputMode;this.outputMode=outputMode;this.inputs=inputPaths;this.outputs=outputPaths;};get inputBuffer(){let inputAgents=[];this.inputs.forEach(input=>{inputAgents=inputAgents.concat(input.finishedAgents);});return inputAgents;};addInputPath(inputPath){if(!(inputPath instanceof Path))throw Error("The input must be an instance of 'Path' !");this.inputs.push(inputPath);};addOutputPath(outputPath){if(!(outputPath instanceof Path))throw Error("The output must be an instance of 'Path' !");this.outputs.push(outputPath);};removeInputPath(inputPath){this.inputs=this.inputs.filter(p=>p!=inputPath);if(this.selectedInput>this.inputs.length-1)this.selectedInput=this.inputs.length-1;};removeOutputPath(inputPath){this.outputs=this.outputs.filter(p=>p!=inputPath);if(this.selectedOutput>this.outputs.length-1)this.selectedOutput=this.outputs.length-1;};selectInput(path){if(!(path instanceof Path))throw Error("The path must be an instance of 'Path' !");let inputSelectedIndex=this.inputs.indexOf(path);if(inputSelectedIndex<0||inputSelectedIndex>this.inputs.length-1)return false;this.selectedInput=inputSelectedIndex;return true;};selectInputByIndex(index){if(index<0||index>this.inputs.length-1)return false;this.selectedInput=index;return true;};selectOutput(path){if(!(path instanceof Path))throw Error("The path must be an instance of 'Path' !");let outputSelectedIndex=this.outputs.indexOf(path);if(outputSelectedIndex<0||outputSelectedIndex>this.outputs.length-1)return false;this.selectedOutput=outputSelectedIndex;return true;};selectInputByIndex(index){if(index<0||index>this.outputs.length-1)return false;this.selectedOutput=index;return true;};#cycleInput(){this.selectedInput=(this.selectedInput+1)%this.inputs.length;};#cycleOutput(){this.selectedOutput=(this.selectedOutput+1)%this.outputs.length;};update(){if(this.inputs.length==0)return;let inputAgents=[];if(this.inputMode=="all"){this.inputs.forEach(input=>{inputAgents=inputAgents.concat(input.finishedAgents);});};if(this.inputMode=="cycle"){inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents);this.#cycleInput();};if(this.inputMode=="cycleSingle"){inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents[0]??[]);this.#cycleInput();};if(this.inputMode=="cycleSmart"){let currentInputAgents=this.inputs[this.selectedInput].finishedAgents;if(currentInputAgents.length>0){inputAgents=inputAgents.concat(currentInputAgents);}else{this.#cycleInput();};};if(this.inputMode=="cycleSingleSmart"){let currentInputAgents=this.inputs[this.selectedInput].finishedAgents;if(currentInputAgents.length>0){inputAgents=inputAgents.concat(currentInputAgents[0]);}else{this.#cycleInput();};};if(this.inputMode=="max"){let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs.sort((a,b)=>b.bufferSize-a.bufferSize);this.selectedInput=numberedInputs[0].index;inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents);};if(this.inputMode=="maxSingle"){let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs.sort((a,b)=>b.bufferSize-a.bufferSize);this.selectedInput=numberedInputs[0].index;inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents[0]??[]);};if(this.inputMode=="maxSingleSmart"){let currentInputAgents=this.inputs[this.selectedInput].finishedAgents;if(currentInputAgents.length>0){inputAgents=inputAgents.concat(currentInputAgents[0]);}else{let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs.sort((a,b)=>b.bufferSize-a.bufferSize);this.selectedInput=numberedInputs[0].index;};};if(this.inputMode=="min"){let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs=numberedInputs.filter(a=>a.bufferSize>0);if(numberedInputs.length==0)return;numberedInputs.sort((a,b)=>a.bufferSize-b.bufferSize);this.selectedInput=numberedInputs[0].index;inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents);};if(this.inputMode=="minSingle"){let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs=numberedInputs.filter(a=>a.bufferSize>0);if(numberedInputs.length==0)return;numberedInputs.sort((a,b)=>a.bufferSize-b.bufferSize);this.selectedInput=numberedInputs[0].index;inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents[0]??[]);};if(this.inputMode=="minSingleSmart"){let currentInputAgents=this.inputs[this.selectedInput].finishedAgents;if(currentInputAgents.length>0){inputAgents=inputAgents.concat(currentInputAgents[0]);}else{let numberedInputs=this.inputs.map(function(inputPath,index){return{"bufferSize":inputPath.finishedAgents.length,"index":index}});numberedInputs=numberedInputs.filter(a=>a.bufferSize>0);if(numberedInputs.length==0)return;numberedInputs.sort((a,b)=>a.bufferSize-b.bufferSize);this.selectedInput=numberedInputs[0].index;};};if(this.inputMode=="random"){this.selectedInput=randInt(0,this.inputs.length-1);inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents);};if(this.inputMode=="randomSingle"){this.selectedInput=randInt(0,this.inputs.length-1);inputAgents=inputAgents.concat(this.inputs[this.selectedInput].finishedAgents[0]??[]);};if(this.outputMode=="delete"){inputAgents.forEach((agent,index)=>{agent.path.removeFromFinished(agent);agent.disabled=true;});};if(this.outputs.length==0)return;if(this.outputMode=="cycle"){inputAgents.forEach((agent,index)=>{agent.path.removeFromFinished(agent);this.outputs[this.selectedOutput].addAgent(agent);this.#cycleOutput();});};if(this.outputMode=="cycleSingle"&&inputAgents.length>0){inputAgents[0].path.removeFromFinished(inputAgents[0]);this.outputs[this.selectedOutput].addAgent(inputAgents[0]);this.#cycleOutput();};if(this.outputMode=="random"){inputAgents.forEach((agent,index)=>{this.selectedOutput=randInt(0,this.outputs.length-1);agent.path.removeFromFinished(agent);this.outputs[this.selectedOutput].addAgent(agent);});};if(this.outputMode=="randomSingle"&&inputAgents.length>0){let agentIndex=randInt(0,inputAgents.length-1);this.selectedOutput=randInt(0,this.outputs.length-1);inputAgents[agentIndex].path.removeFromFinished(inputAgents[agentIndex]);this.outputs[this.selectedOutput].addAgent(inputAgents[agentIndex]);};};render(){ctx.fillStyle="#ff000088";ctx.beginPath();ctx.arc(this.pos?.x??100,this.pos?.y??100,8,0,Math.PI*2);ctx.fill();if(this.inputs.length==0)return;let endPoint=this.inputs[this.selectedInput].endPoint;ctx.fillStyle="#00ddff88";ctx.beginPath();ctx.arc(endPoint.x,endPoint.y,10,0,Math.PI*2);ctx.fill();};};class PathFollow extends Object2D{speed=5;color="#00ff00";path=null;lastPointIndex=0;following=false;finished=false;canFinish=true;constructor(speed=5,color="#00ff00"){super(new Vector(),new Vector());this.speed=speed;this.color=color;this.following=false;this.finished=false;};setPath(path,startMode="start"){if(!(path instanceof Path))throw Error("The path must be an instance of 'Path' !");this.path=path;this.following=false;if(startMode=="start")this.startPath();if(startMode=="closest"){let closestpointOnPath=this.path.getClosestPoint(this.pos);if(closestpointOnPath==null)return;this.pos=closestpointOnPath;this.following=true;this.finished=false;this.lastPointIndex=0;};};removePath(){if(!this.path)return;this.path.removeAgent(this);this.path=null;this.following=false;};startPath(){let startingPoint=this.path.startPoint;if(startingPoint==null)return;this.pos=startingPoint.copy();this.lastPointIndex=0;this.following=true;this.finished=false;};update(){if(!this.following)return;if(!this.path){this.following=false;return;};let jumpSuccesful=false;let currentSpeed=this.speed;while(!jumpSuccesful){if(this.path.isLastPointIndex(this.lastPointIndex))break;let nextPoint=this.path.getPoint(this.lastPointIndex+1);let diffVec=nextPoint.sub(this.pos);let distToPoint=diffVec.length;let targetVector=diffVec.unit(Math.min(currentSpeed,distToPoint));this.pos=this.pos.add(targetVector);if(distToPoint<currentSpeed){jumpSuccesful=false;currentSpeed=currentSpeed-distToPoint;}else{jumpSuccesful=true;};if(distToPoint<=currentSpeed||!jumpSuccesful)this.lastPointIndex+=1;if(this.path.isLastPointIndex(this.lastPointIndex)&&this.canFinish){this.following=false;this.finished=true;this.path.addToFinished(this);};};};render(){ctx.fillStyle=this.following?this.color:"#ff000088";ctx.beginPath();ctx.arc(...camera.w2cXY(this.pos.x,this.pos.y),camera.w2csX(this.following?20:3),0,Math.PI*2);ctx.fill();};}class Collider extends PhysicsObject2D{offset=new Vector();constructor(position,size,offset=new Vector()){super(position,size);this.offset=offset;};setPos(position){this.pos=position.add(this.offset);};isColliding(point){};resolutionVector(point){};closestPointOnEdge(point){};closestPoint(point){};};class ColliderAABB extends Collider{constructor(position,size,offset){super(position,size,offset);};isColliding(point){return(point.x>=this.left&&point.x<=this.right&&point.y>=this.top&&point.y<=this.bottom)};resolutionVector(point){let distances=[point.y-this.top,this.right-point.x,this.bottom-point.y,point.x-this.left,];let closestSide=distances.indexOf(Math.min(...distances));switch(closestSide){default:case0:return new Vector(0,-distances[0]);case1:return new Vector(distances[1],0);case2:return new Vector(0,distances[2]);case3:return new Vector(-distances[3],0);};};closestPointOnEdge(point){if(this.isColliding(point)){return point.add(this.resolutionVector(point));}else{return this.closestPoint(point);};};closestPoint(point){return new Vector(Math.min(Math.max(point.x,this.left),this.right),Math.min(Math.max(point.y,this.top),this.bottom),);};render(){ctx.strokeStyle="hsla(189, 88%, 34%, 0.75)";ctx.fillStyle="hsla(189, 88%, 32%, 0.5)";ctx.lineWidth=camera.w2csX(2);ctx.lineJoin="box";ctx.beginPath();ctx.rect(...camera.w2cf(this.pos,this.size));ctx.stroke();ctx.fill();};};class ColliderCircle extends Collider{#rad=0;get radius(){return this.#rad;};set radius(value){this.#rad=value;};get left(){return this.pos.x-this.#rad;};get right(){return this.pos.x+this.#rad;};get top(){return this.pos.y-this.#rad;};get bottom(){return this.pos.y+this.#rad;};constructor(position,radius,offset){super(position,new Vector(radius*2),offset);this.#rad=radius;};isColliding(point){return distance(this.pos.x,this.pos.y,point.x,point.y)<=this.#rad;};resolutionVector(point){let diff=point.sub(this.pos);return diff.unit(this.#rad-diff.length);};closestPointOnEdge(point){let diff=point.sub(this.pos);return this.pos.add(diff.unit(this.#rad));};closestPoint(point){let diff=point.sub(this.pos);return this.pos.add(diff.unit(Math.min(this.#rad,diff.length)));};render(){ctx.strokeStyle="hsla(189, 88%, 34%, 0.75)";ctx.fillStyle="hsla(189, 88%, 32%, 0.5)";ctx.lineWidth=camera.w2csX(2);ctx.lineJoin="round";ctx.beginPath();ctx.arc(...camera.w2c(this.pos).toArray(),camera.w2csX(this.#rad),0,Math.PI*2);ctx.stroke();ctx.fill();};}const _pidData={};function resetPid(){_pidData={};};function clearPid(id="0000"){if(id in _pidData)delete _pidData[id];};function pid(id="0000",target,current,P,I,D){if(!(id in _pidData)){_pidData[id]={error:0,errorSum:0,errorRate:0,lastError:0,};};_pidData[id].error=target-current;_pidData[id].errorSum+=_pidData[id].error;_pidData[id].errorRate=_pidData[id].error-_pidData[id].lastError;_pidData[id].lastError=_pidData[id].error;return P*_pidData[id].error+I*_pidData[id].errorSum+D*_pidData[id].errorRate;};function pidPoint(id,targetPoint,currentPoint,P,I,D){return new Vector(pid(id+"px",targetPoint.x,currentPoint.x,P,I,D),pid(id+"py",targetPoint.y,currentPoint.y,P,I,D),);}const _audioCtx=new AudioContext();class Resource{static maxLoadables=0;static loaded=0;static textures={};static sounds={};static files={};static _parallelCache={};static _globalResourceId=0;static generateResourceUID(resourceId){Resource._globalResourceId+=1;return resourceId+"_"+Resource._globalResourceId+String(Math.random()).substring(2).substring(0,8);};static loadTexture(path,name,cropData,animData){Resource.maxLoadables++;let newImage=document.createElement("img");newImage.path=path;Resource.textures[name]={image:newImage,};if(cropData!=undefined){Resource.textures[name].cropData={x:cropData[0],y:cropData[1],width:cropData[2],height:cropData[3],};};if(animData!=undefined){Resource.textures[name].animData={length:animData[0],frameLength:animData[1],mode:animData[2]??"loop",wrap:animData[3]??0,direction:animData[4]??1,gapX:animData[5]??0,gapY:animData[6]??0,currentFrame:0,lastUpdate:0,playing:true,callback:null,};if(Resource.textures[name].animData.direction<0)Resource.textures[name].animData.currentFrame=Resource.textures[name].animData.length-1;};};static loadSound(path,name,playData){Resource.maxLoadables++;let newAudio=new Audio();newAudio.path=path;Resource.sounds[name]={audio:newAudio,};Resource.sounds[name].playData={duration:null,loopCount:0,volume:100,currentLoop:0,track:_audioCtx.createMediaElementSource(Resource.sounds[name].audio),gain:_audioCtx.createGain(),};Resource.sounds[name].playData.track.connect(Resource.sounds[name].playData.gain).connect(_audioCtx.destination);if(playData!=undefined){Resource.sounds[name].playData={volume:playData[0]??100,loopCount:playData[1]??0,};};};static loadFile(path,name){Resource.maxLoadables++;Resource.files[name]={data:null,metaData:{path:path,},};};static async loadFromFile(path){let importFile=await fetch(path);let importData=await importFile.json();if("textures" in importData){for(let resource of importData.textures){Resource.loadTexture(resource.path,resource.id,...resource.params);};};if("sounds" in importData){for(let resource of importData.sounds){Resource.loadSound(resource.path,resource.id,...resource.params);};};if("files" in importData){for(let resource of importData.files){Resource.loadFile(resource.path,resource.id,...resource.params);};};};static getTexture(textureId){if(!(textureId in Resource.textures))throw Error(`(${textureId}) Texture not found!`);return Resource.textures[textureId];};static getSound(soundId){if(!(soundId in Resource.sounds))throw Error(`(${soundId}) Sound not found!`);return Resource.sounds[soundId];};static getFile(fileId){if(!(fileId in Resource.files))throw Error(`(${fileId}) File not found!`);return Resource.files[fileId];};static getResourceInstance(resourceId){if(!(resourceId in Resource._parallelCache))throw Error(`(${fileId}) Resource not found!`);return Resource._parallelCache[resourceId];};static onTextureLoad(name){console.log(`Texture: %c${name}%c is loaded, total: ${Resource.loaded} / ${Resource.maxLoadables}`,"font-weight: bold; color: #0df","font-weight: normal");Resource._loaded();};static onSoundLoad(name){console.log(`Sound: %c${name}%c is loaded, total: ${Resource.loaded} / ${Resource.maxLoadables}`,"font-weight: bold; color: #f0d","font-weight: normal");Resource._loaded();};static async onFileLoad(name,blob){Resource.files[name].blob=blob;Resource.files[name].metaData.size=blob.size;Resource.files[name].metaData.type=blob.type;console.log(`File: %c${name}%c is loaded, total: ${Resource.loaded} / ${Resource.maxLoadables}`,"font-weight: bold; color: #fd0","font-weight: normal");Resource._loaded();};static _loaded(){Resource.loaded++;_loading();if(Resource.loaded>=Resource.maxLoadables)Resource._loadingDone();};static _loadingDone(){console.groupEnd();console.log(`%cAll resources loaded, starting the main loop!`,"font-weight: bold; color: #fff;");if(_audioCtx.state=="suspended")_audioCtx.resume();_start();};static startLoading(){console.groupCollapsed(`Loading %c${Resource.maxLoadables}%c resources... (%c${Object.keys(Resource.textures).length}%c ${Object.keys(Resource.sounds).length}%c ${Object.keys(Resource.files).length}%c)`,"font-weight: bold; color: #fff;","","color: #0df","color: #f0d","color: #fd0","");for(let name in Resource.files){fetch(Resource.files[name].metaData.path).then((response)=>response.blob()).then((blob)=>Resource.onFileLoad(name,blob));};for(let name in Resource.textures){Resource.textures[name].image.addEventListener("load",function(){Resource.onTextureLoad(name);});Resource.textures[name].image.src=Resource.textures[name].image.path;};for(let name in Resource.sounds){Resource.sounds[name].audio.src=Resource.sounds[name].audio.path;Resource.sounds[name].audio.preload="auto";Resource.sounds[name].audio.addEventListener("loadeddata",function(){Resource.onSoundLoad(name);});};if(Resource.maxLoadables==0){Resource._loadingDone();};};static _cleanUpParallelCache(){for(let resourceId in Resource._parallelCache){let resource=Resource._parallelCache[resourceId];if(resource instanceof Sound&&resourceId.includes("i")){if(resource.audio.currentTime==resource.audio.duration){resource.destroy();delete Resource._parallelCache[resourceId];};};if(resource.disabled){delete Resource._parallelCache[resourceId];};};};static eraseParallelCache(){for(let name in Resource._parallelCache){let resource=Resource._parallelCache[name];resource.destroy();delete Resource._parallelCache[name];};};static update(){Resource._cleanUpParallelCache();for(let name in Resource._parallelCache){Resource._parallelCache[name].update();};};};class Texture extends BaseResource{image;flipV=false;flipH=false;cropData={};animData={};#_onAnimationEnd=null;get isAnimated(){return this.animData&&this.animData instanceof Object&&Object.keys(this.animData).length!=0;};get isCropped(){return this.cropData&&this.cropData instanceof Object&&Object.keys(this.cropData).length!=0;};set onAnimationEnd(callback){if(typeof callback!="function")throw Error(`<callback> Must be a callable!`);this.#_onAnimationEnd=callback;};get onAnimationEnd(){return this.#_onAnimationEnd??null;};constructor(resourceId,continer=Resource._parallelCache){let textureData=Resource.getTexture(resourceId);if("mapData" in textureData)throw Error(`(${resourceId}) Texture is a tilemap!`);if(!("image" in textureData))throw Error(`(${resourceId}) Texture is missing the image data!`);super(resourceId);if("cropData" in textureData)this.cropData=structuredClone(textureData.cropData);if("animData" in textureData)this.animData=structuredClone(textureData.animData);this.image=Texture.canvasFromImage(textureData.image,this.cropData,this.animData);if(this.isAnimated){this.animData.wrap=0;}else{this.cropData=null;};if(continer!=null)continer[this.uid]=this;};static canvasFromImage(image,cropData=null,animData={}){let imageWidth=cropData?.width??image.width;let imageHeight=cropData?.height??image.height;let imageOffsetX=cropData?.x??0;let imageOffsetY=cropData?.y??0;if("currentFrame" in animData){let offCanvas=new OffscreenCanvas(animData.length*imageWidth,imageHeight);let offCtx=offCanvas.getContext("2d");offCtx.imageSmoothingEnabled=false;offCtx.imageSmoothingQuality="low";for(let frame=0;frame<animData.length;frame++){let newOffX=imageOffsetX;let newOffY=imageOffsetY;if(animData.wrap==0){newOffX+=frame*cropData.width+frame*animData.gapX;}else{let wrapX=(frame%animData.wrap);let wrapY=Math.floor(frame/animData.wrap);newOffX+=wrapX*cropData.width+wrapX*animData.gapX;newOffY+=wrapY*cropData.height+wrapY*animData.gapY;};offCtx.drawImage(image,newOffX,newOffY,imageWidth,imageHeight,frame*imageWidth,0,imageWidth,imageHeight);};return offCanvas;}else{let offCanvas=new OffscreenCanvas(imageWidth,imageHeight);let offCtx=offCanvas.getContext("2d");offCtx.imageSmoothingEnabled=false;offCtx.imageSmoothingQuality="low";offCtx.drawImage(image,imageOffsetX,imageOffsetY,imageWidth,imageHeight,0,0,imageWidth,imageHeight);return offCanvas;};};getAnimationLength(inSeconds=false){if(!this.isAnimated)return null;if(inSeconds){return this.animData.frameLength*this.animData.length;}else{return this.animData.frameLength*this.animData.length*1000;};};pause(){if(!this.isAnimated)return;this.animData.playing=false;};resume(){if(!this.isAnimated)return;this.animData.playing=true;};restart(){if(!this.isAnimated)return;this.animData.currentFrame=this.animData.direction>0?0:this.animData.length-1;this.animData.lastUpdate=0;this.animData.playing=true;};render(x,y,width,height,rotation=0,margin=0){if(this.isAnimated&&this.isCropped){let cropData=structuredClone(this.cropData);if(this.animData.wrap==0){cropData.x+=this.animData.currentFrame*cropData.width+((this.animData.currentFrame-1)*this.animData.gapX);}else{let wrapX=(this.animData.currentFrame%this.animData.wrap);let wrapY=Math.floor(this.animData.currentFrame/this.animData.wrap);cropData.x+=wrapX*cropData.width+((wrapX-1)*this.animData.gapX);cropData.y+=wrapY*cropData.height+((wrapY-1)*this.animData.gapY);};this.#drawImageRotated(x,y,[cropData.x,cropData.y,cropData.width,cropData.height],width,height,rotation,margin);}else if(this.isCropped){this.#drawImageRotated(x,y,[this.cropData.x,this.cropData.y,this.cropData.width,this.cropData.height],width,height,rotation,margin);}else{this.#drawImageRotated(x,y,[],width,height,rotation,margin);};};#drawImageRotated(x,y,cropData=[],width,height,rotation=0,margin=0){let imageCropData=cropData;if(cropData.length==0){imageCropData=[0,0,this.image.width,this.image.height,];};if(cropData.length==2){imageCropData=[cropData[0],cropData[1],this.image.width,this.image.height,];};let imageWidth=width??imageCropData[2];let imageHeight=height??imageCropData[3];let imageRenderData=[-imageWidth/2+margin/2,-imageHeight/2+margin/2,imageWidth-margin,imageHeight-margin,];if(this.flipV){imageRenderData[0]+=imageRenderData[2];imageRenderData[2]*=-1;};ctx.save();ctx.rotate(rotation*(Math.PI/180));ctx.translate(x+imageWidth/2,y+imageHeight/2);ctx.imageSmoothingEnabled=!c.isPixelPerfect;ctx.drawImage(this.image,...imageCropData,...imageRenderData);ctx.restore();};update(){if(!this.isAnimated)return;if(!this.animData.playing)return;let frameInMillis=this.animData.frameLength*1000;let lastUpdateTime=time.ups.elapsed-this.animData.lastUpdate;if(lastUpdateTime<frameInMillis)return;this.animData.lastUpdate=time.ups.elapsed;this.animData.currentFrame+=this.animData.direction;if(this.animData.direction>0){if(this.animData.currentFrame>=this.animData.length){if(this.animData.mode=="loop")this.animData.currentFrame=0;if(this.animData.mode=="stop")this.animData.currentFrame=this.animData.length-1;if(this.animData.mode=="reset")this.animData.currentFrame=0;if(["stop","reset"].includes(this.animData.mode))this.animData.playing=false;if(this.animData.mode=="pingpong"){this.animData.currentFrame=this.animData.length-2;this.animData.direction*=-1;};if(this.#_onAnimationEnd!=null)this.#_onAnimationEnd(this);};}else{if(this.animData.currentFrame<0){if(this.animData.mode=="loop")this.animData.currentFrame=this.animData.length-1;if(this.animData.mode=="stop")this.animData.currentFrame=0;if(this.animData.mode=="reset")this.animData.currentFrame=this.animData.length-1;if(["stop","reset"].includes(this.animData.mode))this.animData.playing=false;if(this.animData.mode=="pingpong"){this.animData.currentFrame=1;this.animData.direction*=-1;};if(this.#_onAnimationEnd!=null)this.#_onAnimationEnd(this);};};};destroy(){super.destroy();};};class Sound extends BaseResource{audio;playData={};effectData={};#onSoundEnd=null;#container;get isPlayable(){return this.playData!={};};set volume(value){this.playData.volume=value;this.update();};get volume(){return this.playData.volume;};constructor(resourceId,isInstance=false,continer=Resource._parallelCache){if(!settings.enableAudio)return false;let soundData=Resource.getSound(resourceId);if(!("audio" in soundData))throw Error(`(${resourceId}) Sound is missing the audio data!`);super(isInstance?resourceId+"_i":resourceId);this.audio=soundData.audio.cloneNode(true);if("playData" in soundData){this.playData={duration:soundData.playData.duration,loopCount:soundData.playData.loopCount,volume:soundData.playData.volume,currentLoop:soundData.playData.currentLoop,};this.effectData.track=_audioCtx.createMediaElementSource(this.audio);this.effectData.gain=_audioCtx.createGain();this.effectData.track.connect(this.effectData.gain).connect(_audioCtx.destination);this.effectData.gain.gain.value=clamp((this.playData.volume??1)/100,0,Infinity);};this.audio.play();this.#container=continer;if(continer!=null)continer[this.uid]=this;};pause(){this.audio.pause();};resume(){this.audio.play();};restart(interrupt=false){if(interrupt){this.audio.stop();this.audio.currentTime=0;this.audio.play();return null;}else{let newSound=new Sound(this.resourceId,true,this.#container);return newSound;};};update(){this.playData.duration=this.audio.duration;this.effectData.gain.gain.value=Math.max(0,(this.playData.volume??1)/100);};destroy(){this.audio.pause();super.destroy();};};class FileResource{static getText(fileId){let fileData=Resource.getFile(fileId);return fileData.blob.text();};static async getJson(fileId){let fileData=Resource.getFile(fileId);try{return JSON.parse(await fileData.blob.text());}catch(e){throw Error(`(${fileId}) File does not contain valid JSON data!\n[${e}]`);};};static getSize(fileId){let fileData=Resource.getFile(fileId);return fileData.metaData.size;};static getType(fileId){let fileData=Resource.getFile(fileId);return fileData.metaData.type;};static downloadFile(fileName,plainText){let blob=new Blob([plainText],{type:"text/plain"});let jsonObjectUrl=URL.createObjectURL(blob);const anchorEl=document.createElement("a");anchorEl.href=jsonObjectUrl;anchorEl.download=fileName;anchorEl.click();URL.revokeObjectURL(jsonObjectUrl);};}class SceneManager{};class Scene{id="";disabled=false;objects={cameras:[],static:[],dynamic:[],};constructor(id){};update(){this.objects.static.forEach(o=>{if("update" in o)o.update();});this.objects.dynamic.forEach(o=>{if("update" in o)o.update();});this.objects.cameras.forEach(c=>{c.update();});};render(){this.objects.static.forEach(o=>{if("render" in o)o.render();});this.objects.dynamic.forEach(o=>{if("render" in o)o.render();});};}class SimpleSprite extends Object2D{color="#dd00dd";texture=null;constructor(textureId,position,size=new Vector(32),color="#dd00dd"){super(position,size);if(textureId!==null)this.texture=new Texture(textureId);this.color=color;};renderColor(){ctx.fillStyle="#000000";ctx.beginPath();ctx.fillRect(...camera.w2cXY(this.pos.x,this.pos.y),...camera.w2csXY(this.size.x,this.size.y));ctx.fill();ctx.fillStyle=this.color;ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.right,this.top));ctx.lineTo(...camera.w2cXY(this.right,this.center.y));ctx.lineTo(...camera.w2cXY(this.left,this.center.y));ctx.lineTo(...camera.w2cXY(this.left,this.bottom));ctx.lineTo(...camera.w2cXY(this.center.x,this.bottom));ctx.lineTo(...camera.w2cXY(this.center.x,this.top));ctx.closePath();ctx.fill();};render(){camera.renderTexture(this.texture,this.pos.x,this.pos.y,this.size.x,this.size.y);};destroy(){this.texture.destroy();super.destroy();};};class Sprite extends SimpleSprite{scale=new Vector();origin=new Vector();rotation=0;constructor(textureId,position,size=new Vector(32),color="#dd00dd"){super(textureId,position,size,color);this.scale=new Vector(1,1);this.origin=new Vector(0,0);};setOrigin(x,y){this.origin=new Vector(clamp(x,0,this.size.x),clamp(y,0,this.size.y));};get transformOrigin(){return this.pos.add(new Vector(this.origin.x*(1-this.scale.x),this.origin.y*(1-this.scale.y)));};get left(){return this.scale.x<0?this.transformOrigin.x+this.size.x*this.scale.x:this.transformOrigin.x;};get leftOffset(){return this.scale.x<0?0:this.size.x*this.scale.x;};get right(){return this.scale.x<0?this.transformOrigin.x:this.transformOrigin.x+this.size.x*this.scale.x;};get rightOffset(){return this.scale.x>0?0:this.size.x*this.scale.x;};get top(){return this.scale.y<0?this.transformOrigin.y+this.size.y*this.scale.y:this.transformOrigin.y;};get topOffset(){return this.scale.y<0?0:this.size.y*this.scale.y;};get bottom(){return this.scale.y<0?this.transformOrigin.y:this.transformOrigin.y+this.size.y*this.scale.y;};get bottomOffset(){return this.scale.y>0?0:this.size.y*this.scale.y;};get center(){return this.pos.add(this.size.mult(this.scale).mult(0.5));};get centerOffset(){return(this.size).mult(this.scale).mult(0.5);};renderColor(){ctx.save();ctx.translate(-this.center.x,-this.center.y);ctx.rotate(this.rotation);ctx.fillStyle="#000000";ctx.beginPath();ctx.fillRect(...camera.w2cXY(this.left,this.top),...camera.w2csXY(this.rightOffset,this.bottomOffset));ctx.fill();ctx.fillStyle=this.color;ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.right,this.top));ctx.lineTo(...camera.w2cXY(this.right,this.center.y));ctx.lineTo(...camera.w2cXY(this.left,this.center.y));ctx.lineTo(...camera.w2cXY(this.left,this.bottom));ctx.lineTo(...camera.w2cXY(this.center.x,this.bottom));ctx.lineTo(...camera.w2cXY(this.center.x,this.top));ctx.closePath();ctx.fill();ctx.restore();};render(){let newSize=this.size.copy();newSize.x*=this.scale.x;newSize.y*=this.scale.y;let newPos=this.pos.copy();if(this.scale.x<0)newPos.x-=newSize.x;if(this.scale.y<0)newPos.y-=newSize.y;this.texture.flipV=this.scale.x<0;this.texture.flipH=this.scale.y<0;camera.renderTexture(this.texture,...newPos.toArray(),...newSize.toArray(),this.rotation);};};class AnimatedSprite extends Sprite{animations={};currentAnimation=null;defaultAnimation="";constructor(position,size=new Vector(32),animations={},color="#dd00dd"){super(null,position,size,color);this.animations=animations;this.defaultAnimation=Object.keys(this.animations)[0];this.currentAnimation=this.defaultAnimation;this.texture=animations[this.currentAnimation];};setDefualtAnimation(animaionId){this.defaultAnimation=animaionId;};play(animationId,animate=true){this.currentAnimation=animationId;if(!animate){this.animations[this.currentAnimation].pause();};};restart(animaionId){this.play(animaionId);this.animations[this.currentAnimation].restart();};resume(){this.animations[this.currentAnimation].resume();};pause(){this.animations[this.currentAnimation].pause();};default(){this.play(this.defaultAnimation);};update(){this.texture=this.animations[this.currentAnimation];};destroy(){for(let animName in this.animations){this.animations[animName].destroy();};super.destroy();};}class SimpleTile{id="";char=null;atlasPos=new Vector();meta={};texture;pattern;constructor(texture,tileId,atlasPos){this.texture=texture;this.id=tileId;this.atlasPos=atlasPos;this.meta={};this.pattern=ctx.createPattern(texture,"repeat");this.char=null;};toObject(){return{id:structuredClone(this.id),meta:structuredClone(this.meta),};};};class SimpleTileMap extends Object2D{atlasId="";atlasTexture;atlasData;tiles={};gridTileSize=new Vector(50,50);grid;constructor(textureId,atlasData,width,height){super(new Vector(),new Vector(1,1));this.atlasId=textureId;this.atlasTexture=new Texture(textureId);this.atlasData={rows:null,columns:null,tileWidth:16,tileHeight:16,gapX:0,gapY:0,};this._setAtlasData(atlasData);this.tiles=SimpleTileMap.sliceTiles(this.atlasTexture.image,this.atlasData);this.grid=new Grid(width,height,{id:Object.keys(this.tiles)[0],meta:{},},function(tile){return tile.id;});this._updateTileMapSize();this._updateTileSizes();};_setAtlasData(atlasData){for(let key in atlasData){this.atlasData[key]=atlasData[key];};if(this.atlasData.rows==null){this.atlasData.rows=(this.atlasTexture.image.height+this.atlasData.gapY)/(this.atlasData.tileHeight+this.atlasData.gapY);this.atlasData.columns=(this.atlasTexture.image.width+this.atlasData.gapX)/(this.atlasData.tileWidth+this.atlasData.gapX);};if(this.atlasData.tileWidth==null){this.atlasData.tileWidth=(this.atlasTexture.image.width+this.atlasData.gapX)/this.atlasData.columns;this.atlasData.tileHeight=(this.atlasTexture.image.height+this.atlasData.gapY)/this.atlasData.rows;};};_updateTileMapSize(){this.size.x=this.grid.width*this.gridTileSize.x;this.size.y=this.grid.height*this.gridTileSize.y;};_updateTileSizes(){for(let tileId in this.tiles){let tile=this.tiles[tileId];let offCanvas=new OffscreenCanvas(this.gridTileSize.x,this.gridTileSize.y);let offCtx=offCanvas.getContext("2d");offCtx.imageSmoothingEnabled=!c.isPixelPerfect;offCtx.drawImage(tile.texture,0,0,offCanvas.width,offCanvas.height);this.tiles[tileId].texture=offCanvas;this.tiles[tileId].pattern=offCtx.createPattern(offCanvas,"repeat");};};static _getTileIdFromCoords(x,y){return "tile_"+x+"_"+y;};static sliceTiles(image,atlasData){let tiles={};for(let y=0;y<atlasData.rows;y++){for(let x=0;x<atlasData.columns;x++){let tileId=SimpleTileMap._getTileIdFromCoords(x,y);let tileTexture=Texture.canvasFromImage(image,{width:atlasData.tileWidth,height:atlasData.tileHeight,x:atlasData.tileWidth*x+Math.min(0,atlasData.gapX*(x-1)),y:atlasData.tileHeight*y+Math.min(0,atlasData.gapY*(y-1)),},false);tiles[tileId]=new SimpleTile(tileTexture,tileId,new Vector(x,y));};};return tiles;};static importTilemap(atlasTextureId,width,height,importData){if(!("atlasData" in importData))throw Error('Missing property "atlasData" in importData!');let newTilemap=new SimpleTileMap(atlasTextureId,importData.atlasData,width,height);let tileChars={};if("tiles" in importData){for(let tileId in importData.tiles){let currentTile=importData.tiles[tileId];tileChars[currentTile.char]=currentTile.id;newTilemap.renameTile(tileId,currentTile.id);for(let key in currentTile.meta){newTilemap.setTileMeta(currentTile.id,key,currentTile.meta[key]);newTilemap.tiles[currentTile.id].char=currentTile?.char??null;};};newTilemap.grid.defaultValue=Object.values(newTilemap.tiles)[0].toObject();};if("grid" in importData){if("default" in importData.grid){newTilemap.grid.defaultValue=newTilemap.tiles[importData.grid.default].toObject();};newTilemap.grid.resize(importData.grid.width,importData.grid.height);for(let y=0;y<importData.grid.data.length;y++){let row=importData.grid.data[y];for(let i=0;i<row.length;i+=2){let tileChar=row[i]+row[i+1];let tilePos=new Vector(i/2,y);let tileId=tileChars[tileChar];newTilemap.setTileAt(tilePos,tileId);};};};return newTilemap;};static importFromTiled(atlasTextureId,importData){let atlasData={tileWidth:importData.tilewidth,tileHeight:importData.tileheight,gapX:0,gapY:0,};let newTilemap=new SimpleTileMap(atlasTextureId,atlasData,importData.width,importData.height);let layerName="tilelayer";let layerIndex=importData.layers.reduce(function(result,current,index){if(index==1){return result.type==layerName?0:(current.type==layerName?1:null);}else{return result===null?(current.type==layerName?index:null):result;};},);if(layerIndex===null){return newTilemap;};let tileLayer=importData.layers[layerIndex];newTilemap.grid.defaultValue={id:null,meta:{}};for(let i=0;i<tileLayer.data.length;i++){let tilePos=Grid.indexToCoordinate(i,tileLayer.width);let tileId=SimpleTileMap._getTileIdFromCoords(...Grid.indexToCoordinate(tileLayer.data[i]-1,newTilemap.atlasData.columns).toArray());newTilemap.setTileAt(tilePos,tileId);};return newTilemap;};exportTilemap(fileName=null){let out={atlasData:this.atlasData,tiles:{},grid:{width:this.grid.width,height:this.grid.height,default:this.grid.defaultValue.id,data:[],},};let tileChars={};let i=0;for(let tileId in this.tiles){let tile=this.tiles[tileId];let defaultTileId=SimpleTileMap._getTileIdFromCoords(tile.atlasPos.x,tile.atlasPos.y);if(tile.id==defaultTileId)continue;if(tile.char==null){tileChars[tileId]=String.fromCharCode(33+Math.floor(i/93))+String.fromCharCode(33+(i%93));}else{tileChars[tileId]=tile.char;};out.tiles[defaultTileId]={char:tileChars[tileId],id:tile.id,meta:tile.meta,};i++;};let oldY=0;let row="";this.grid.forEach(function(x,y,tile){if(y!=oldY){out.grid.data.push(row);row="";oldY=y;};row+=tileChars[tile.id];});if(row.length>0)out.grid.data.push(row);if(fileName){FileResource.downloadFile(fileName+".json",JSON.stringify(out));}else{return out;};};renameTile(tileId,newTileId){if(!(tileId in this.tiles))return;this.grid.map(function(x,y,tile){if(tile.id==tileId)tile.id=newTileId;return tile});this.tiles[newTileId]=this.tiles[tileId];this.tiles[newTileId].id=newTileId;delete this.tiles[tileId];};renameTilebyAtlasPos(atlasPos,newTileId){for(let currentTileId in this.tiles){let tile=this.tiles[currentTileId];if(tile.atlasPos.isEqual(atlasPos)){this.tiles[newTileId]=tile;this.tiles[newTileId].id=newTileId;delete this.tiles[currentTileId];};};};fill(tileId){this.grid.fill(this.getTileById(tileId).toObject());};setTileAt(tilePos,tileId,tileMeta=null){let tile=this.grid.getCell(tilePos.x,tilePos.y);tile.id=tileId;tile.meta=tileMeta??{};this.grid.setCell(tilePos.x,tilePos.y,tile);};setLocalTileMeta(tilePos,key,value){let tile=this.grid.getCell(tilePos.x,tilePos.y);tile.meta[key]=value;this.grid.setCell(tilePos.x,tilePos.y,tile);};setTileMeta(tileId,key,value){if(!(tileId in this.tiles))return;this.tiles[tileId].meta[key]=value;};setTileMetaAt(atlasPos,key,value){for(let tileId in this.tiles){let tile=this.tiles[tileId];if(tile.atlasPos.isEqual(atlasPos)){tile.meta[key].meta=value;};};};getTileById(tileId){if(!(tileId in this.tiles))return null;return this.tiles[tileId];};getTileByAtlasPos(atlasPos){for(let tileId in this.tiles){let tile=this.tiles[tileId];if(tile.atlasPos.isEqual(atlasPos))return tile;};return null;};getTileAt(tilePos){return this.grid.getCell(tilePos.x,tilePos.y,null)?.id??null;};getLocalTileMeta(tilePos){return this.grid.getCell(tilePos.x,tilePos.y,null)?.meta??null;};render(gridColor=null,gridThickness=null){let self=this;this.grid.forEach(function(x,y,tile){if(tile.id==null)return;let tilePos=self.pos.add(new Vector(x,y).mult(self.gridTileSize));ctx.drawImage(self.getTileById(tile.id).texture,...camera.w2cf(tilePos.round(settings.debug.a),self.gridTileSize.round(settings.debug.a)));});if(gridColor!=null){ctx.strokeStyle=gridColor;ctx.lineWidth=camera.w2csX(gridThickness);ctx.lineJoin="butt";ctx.lineCap="butt";for(let y=0;y<=this.grid.height;y++){ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.left,this.pos.y+y*this.gridTileSize.y));ctx.lineTo(...camera.w2cXY(this.right,this.pos.y+y*this.gridTileSize.y));ctx.stroke();};for(let x=0;x<=this.grid.width;x++){ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.pos.x+x*this.gridTileSize.x,this.top));ctx.lineTo(...camera.w2cXY(this.pos.x+x*this.gridTileSize.x,this.bottom));ctx.stroke();};};};update(){};};class Tile{autotile=[];id="";atlasPos=new Vector();meta={};texture;pattern;constructor(texture,tileId,atlasPos){this.texture=texture;this.id=tileId;this.atlasPos=atlasPos;this.meta={};this.updatePattern();};updatePattern(){this.pattern=ctx.createPattern(this.texture.image,"repeat");};setAutotile(array){this.autotile=array;};toObject(){return{id:structuredClone(this.id),meta:structuredClone(this.meta),};};update(){this.texture.update();};};class TileMap extends Object2D{#layers={};get layers(){return this.#layers;};#gridTileSize=new Vector(50,50);set tileSize(value){return this.#gridTileSize=value;};get tileSize(){return this.#gridTileSize;};get tileWidth(){return this.#gridTileSize.x;};get tileHeight(){return this.#gridTileSize.y;};#width=0;#height=0;get width(){return this.#width;};get height(){return this.#height;};#tiles={};get tiles(){return this.#tiles;};get tileCount(){return Object.keys(this.#tiles).length;};get tileIds(){return Object.keys(this.#tiles);};defaultTile=null;settings={autoUpdate:false,};constructor(atlasTextureId,atlasData,width,height){super(new Vector(),new Vector(1,1));this.settings={autoUpdate:false,};this.defaultTile=null;this.#width=width;this.#height=height;this.atlasId=atlasTextureId;this.atlasTexture=new Texture(atlasTextureId,null);this.atlasData={rows:null,columns:null,tileWidth:16,tileHeight:16,gapX:0,gapY:0,};this._setAtlasData(atlasData);if(this.atlasTexture.isAnimated){this.atlasTexture.animData.gapX=(this.atlasData.columns-1)*this.atlasData.tileWidth;this.atlasTexture.animData.gapY=(this.atlasData.rows-1)*this.atlasData.tileHeight;};this.#tiles=TileMap.sliceTiles(this.atlasTexture,this.atlasData);this.#layers={};this.addLayer("graphics");this.addLayer("collision");this.addLayer("navigation");this._updateSize();};tileToWorld(tilePos){return this.pos.add(tilePos.mult(this.#gridTileSize));};tileCenterToWorld(tilePos){return this.pos.add(tilePos.mult(this.#gridTileSize).add(this.#gridTileSize.mult(0.5)));};_setAtlasData(atlasData){for(let key in atlasData){this.atlasData[key]=atlasData[key];};let imageWidth=this.atlasTexture?.cropData?.width??this.atlasTexture.image.width;let imageHeight=this.atlasTexture?.cropData?.height??this.atlasTexture.image.height;if(!this.atlasData.rows){this.atlasData.rows=(imageHeight+this.atlasData.gapY)/(this.atlasData.tileHeight+this.atlasData.gapY);this.atlasData.columns=(imageWidth+this.atlasData.gapX)/(this.atlasData.tileWidth+this.atlasData.gapX);};if(!this.atlasData.tileWidth){this.atlasData.tileWidth=(this.atlasTexture.image.width+this.atlasData.gapX)/this.atlasData.columns;this.atlasData.tileHeight=(this.atlasTexture.image.height+this.atlasData.gapY)/this.atlasData.rows;};};_updateSize(){this.size=new Vector(this.#width,this.#height).mult(this.tileSize);};_updateTilePatterns(){for(let tileId in this.#tiles){let tile=this.#tiles[tileId];let offCanvas=new OffscreenCanvas(...camera.w2csXY(this.tileWidth,this.tileHeight));let offCtx=offCanvas.getContext("2d");offCtx.imageSmoothingEnabled=!c.isPixelPerfect;offCtx.imageSmoothingQuality="low";offCtx.drawImage(tile.texture,0,0,offCanvas.width,offCanvas.height);tile.pattern=offCtx.createPattern(offCanvas,"repeat");};};static sliceTiles(texture,atlasData){let tiles={};for(let y=0;y<atlasData.rows;y++){for(let x=0;x<atlasData.columns;x++){let tileId=SimpleTileMap._getTileIdFromCoords(x,y);let tileImage=Texture.canvasFromImage(texture.image,{width:atlasData.tileWidth,height:atlasData.tileHeight,x:atlasData.tileWidth*x+Math.min(0,atlasData.gapX*(x-1)),y:atlasData.tileHeight*y+Math.min(0,atlasData.gapY*(y-1)),},texture.animData);let tileTexture=new Texture(texture.resourceId,null);tileTexture.image=tileImage;if(texture.isAnimated){tileTexture.cropData={x:0,y:0,width:atlasData.tileWidth,height:atlasData.tileHeight};tileTexture.animData.wrap=0;tileTexture.animData.direction=1;};tiles[tileId]=new Tile(tileTexture,tileId,new Vector(x,y));};};return tiles;};static importFromTiled(atlasTextureId,importData){let atlasData={tileWidth:importData.tilewidth,tileHeight:importData.tileheight,gapX:0,gapY:0,};let newTilemap=new TileMap(atlasTextureId,atlasData,importData.width,importData.height);newTilemap.removeLayer("graphics_0");newTilemap.removeLayer("collision_0");newTilemap.removeLayer("navigation_0");for(let layer of importData.layers){if(layer.type=="tilelayer"){let newLayer=newTilemap.addLayer("graphics");let dataGrid=Grid.fromArray(layer.data,layer.width);dataGrid.map(function(x,y,tileId){let tilePos=Grid.indexToCoordinate(tileId-1,newTilemap.atlasData.columns);let correctTileId=SimpleTileMap._getTileIdFromCoords(tilePos.x,tilePos.y);return{id:tileId==0?null:correctTileId,meta:{},};});newTilemap.setGrid(newLayer,dataGrid);};function transformToWorldSpace(tilemap,layer,importData,x,y){return new Vector(((x/importData.tilewidth)+(layer.offsetx/importData.tilewidth))*tilemap.tileWidth+tilemap.pos.x,((y/importData.tileheight)+(layer.offsety/importData.tileheight))*tilemap.tileHeight+tilemap.pos.y,);};if(layer.type=="objectgroup"){let newLayer=newTilemap.addLayer("navigation");for(let object of layer.objects){if("point" in object){console.log("Point at: ",object.x,object.y,object.width,object.height);newTilemap.addObject(newLayer,new Point(...transformToWorldSpace(newTilemap,layer,importData,object.x,object.y).toArray()),);}else if("polygon" in object){console.log("Path at: ",object.x,object.y,object.width,object.height);for(let i in object.polygon){object.polygon[i]=transformToWorldSpace(newTilemap,layer,importData,object.polygon[i].x+object.x,object.polygon[i].y+object.y,);};let newPath=new Path(object.polygon);newTilemap.addObject(newLayer,newPath);}else{console.log("Rectangle at: ",object.x,object.y,object.width,object.height);};};};};return newTilemap;};static exportToTiled(fileName){throw Error("Not implemented")};addLayer(layerType){if(!["graphics","collision","navigation"].includes(layerType))return null;let sameTypeLayers=[];for(let layerId in this.#layers){if(layerId.search(new RegExp(`${layerType}_[0-9]+`))==0)sameTypeLayers.push(layerId);};sameTypeLayers.sort();let lastLayer=sameTypeLayers[sameTypeLayers.length-1]??"placeholder_-1";let lastLayerIndex=parseInt(lastLayer.split("_")[1]);let newLayerId=`${layerType}_${lastLayerIndex + 1}`;if(layerType=="graphics"){this.#layers[newLayerId]={grid:new Grid(this.#width,this.#height,{id:this.defaultTile,meta:{},},function(tile){return tile.id;}),objects:[],};this.#layers[newLayerId].grid.defaultValue={id:this.defaultTile,meta:{},};};if(layerType=="collision"){this.#layers[newLayerId]={grid:new Grid(this.#width,this.#height,false,function(tile){return tile;}),objects:[],};this.#layers[newLayerId].grid.defaultValue=false;};if(layerType=="navigation"){this.#layers[newLayerId]={grid:new Grid(this.#width,this.#height,0,function(tile){return tile;}),objects:[],};this.#layers[newLayerId].grid.defaultValue=0;};return newLayerId;};removeLayer(layerId){if(!(layerId in this.#layers))return;delete this.#layers[layerId];};getLayers(layerType=null){let out=[];if(layerType===null){let graphicsLayers=[];let collisionLayers=[];let navigationLayers=[];for(let layerId in this.#layers){if(layerId.search(/graphics_[0-9]+/g)==0)graphicsLayers.push(layerId);if(layerId.search(/collision_[0-9]+/g)==0)collisionLayers.push(layerId);if(layerId.search(/navigation_[0-9]+/g)==0)navigationLayers.push(layerId);};graphicsLayers.sort();collisionLayers.sort();navigationLayers.sort();out=out.concat(graphicsLayers).concat(collisionLayers).concat(navigationLayers);}else{for(let layerId in this.#layers){if(layerId.search(new RegExp(`${layerType}_[0-9]+`))==0)out.push(layerId);};out.sort();};return out;};getFirstLayer(){if(Object.keys(this.#layers).length==0)return null;return this.#layers[Object.keys(this.#layers)[0]];};setGrid(layerId,grid){if(!(layerId in this.#layers))return;this.#layers[layerId].grid=grid;};getGrid(layerId){return this.#layers[layerId]?.grid??null;};addObject(layerId,object){if(!(layerId in this.#layers))return;this.#layers[layerId].objects.push(object);};getObjects(layerId){if(!(layerId in this.#layers))return;return this.#layers[layerId].objects;};renameTile(tileId,newTileId){if(!(tileId in this.#tiles))return;this.#tiles[newTileId]=this.#tiles[tileId];this.#tiles[newTileId].id=newTileId;delete this.#tiles[tileId];};deleteTile(tileId){if(!(tileId in this.#tiles))return;delete this.#tiles[tileId];};setTileMeta(tileId,key,value){if(!(tileId in this.#tiles))return;this.#tiles[tileId].meta[key]=value;};getTileMeta(tileId,key=null){if(!(tileId in this.#tiles))return null;if(key===null){return this.#tiles[tileId].meta;}else{return this.#tiles[tileId].meta[key]??null;};};getTileById(tileId){if(!(tileId in this.#tiles))return null;return this.#tiles[tileId];};getTileByAtlasPos(atlasPos){for(let tileId in this.#tiles){if(this.#tiles[tileId].atlasPos.isEqual(atlasPos))return this.#tiles[tileId];return null;};};getFirstTile(){if(this.#tiles=={})return null;return this.#tiles[Object.keys(this.#tiles)[0]];};setTileAutotile(tileId,neighbors){throw Error("Not implemented")};setTileAutotileDirection(tileId,direction="top",connectionID){throw Error("Not implemented")};setTileAutotileIndex(tileId,index,connectionID){throw Error("Not implemented")};getTileAutotile(tileId){throw Error("Not implemented")};getAutotile(tileID,neighbors){throw Error("Not implemented")};getColumnAt(tilePos){throw Error("Not implemented")};setTileAt(graphicsLayer,tilePos,tileId,tileMeta){let grid=this.getGrid("graphics_"+graphicsLayer);if(!grid)return;if(!grid.isInGrid(tilePos.x,tilePos.y))return;let tile=grid.getCell(tilePos.x,tilePos.y);tile.id=tileId;tile.meta=tileMeta??this.getTileMeta(tileId)??{};grid.setCell(tilePos.x,tilePos.y,tile);};getTileAt(graphicsLayer,tilePos){return this.getGrid("graphics_"+graphicsLayer)?.getCell(tilePos.x,tilePos.y,null)?.id??null;};setTileMetaAt(graphicsLayer,tilePos,key,value){let grid=this.getGrid("graphics_"+graphicsLayer);if(!grid)return;if(!grid.isInGrid(tilePos.x,tilePos.y))return;let tile=grid.getCell(tilePos.x,tilePos.y);tile.meta[key]=value;};getTileMetaAt(graphicsLayer,tilePos,key=null){let grid=this.getGrid("graphics_"+graphicsLayer);if(!grid)return;if(!grid.isInGrid(tilePos.x,tilePos.y))return;let tile=grid.getCell(tilePos.x,tilePos.y);if(key===null){return tile.meta;}else{return tile.meta[key]??null;};};clear(layerId,tileId){if(layerId.search(/graphics_[0-9]+/g)==0){if(tileId===null){this.#layers[layerId].grid.fill({id:tileId,meta:{}});}else{let tileMeta=this.getTileMeta(tileId);if(!tileMeta)return;this.#layers[layerId].grid.fill({id:tileId,meta:structuredClone(tileMeta)});};}else{this.#layers[layerId].grid.fill(tileId);};};fill(layerId,tileId,tilePos){throw Error("Not implemented")};foreach(layerId,callback){this.getGrid(layerId)?.forEach(callback);};map(layerId,callback){this.getGrid(layerId)?.map(callback);};filter(layerId,callback){let grid=this.getGrid(layerId);if(!grid)return null;let out=new Grid(grid.width,grid.height,null,grid.hashFunction);grid.forEach(function(x,y,tile){if(callback(x,y,tile))out.setCell(x,y,tile);});return out;};getIslands(layerId,emptyTileFunction){throw Error("Not implemented")};setTileCollisionAt(collisionLayer,tilePos,value){if(typeof value!="boolean")return1;let grid=this.getGrid("collision_"+collisionLayer);if(!grid)return2;if(!grid.isInGrid(tilePos.x,tilePos.y))return3;grid.setCell(tilePos.x,tilePos.y,value);};setAllTileCollision(collisionLayer,tilePos,collisionsOnLayers){throw Error("Not implemented")};getTileCollision(collisionLayer,tilePos){throw Error("Not implemented")};getAllTileCollision(tilePos){throw Error("Not implemented")};isColliding(layerIds,point){if(layerIds.length==0)return false;for(let layerId of layerIds){let grid=this.getGrid(layerId);if(grid==null)continue;};return false;};setTileNavigationAt(navLayer,tilePos,travelCost){if(typeof travelCost!="number")return1;let grid=this.getGrid("navigation_"+navLayer);if(!grid)return2;if(!grid.isInGrid(tilePos.x,tilePos.y))return3;grid.setCell(tilePos.x,tilePos.y,travelCost);};getTileNavigationAt(navLayer,tilePos){let grid=this.getGrid("navigation_"+navLayer);if(!grid)return null;if(!grid.isInGrid(tilePos.x,tilePos.y))return null;return grid.getCell(tilePos.x,tilePos.y);};findPath(navLayer,startPos,endPos,algorithm="astar"){let self=this;function posToString(tilePos){return `${tilePos.x};${tilePos.y}`;};function stringToPos(string){return new Vector(parseInt(string.split(";")[0]),parseInt(string.split(";")[1]));};function generatePath(cameFrom,current){let tiles=[current];let points=[self.tileCenterToWorld(current)];current=posToString(current);let visited=new Set();while(current in cameFrom){if(visited.has(current))return null;let old=current;current=cameFrom[current];points.unshift(self.tileCenterToWorld(current));tiles.unshift(current);visited.add(old);current=posToString(current);};return{tiles:tiles,points:points};};function heuristics(tilePos){return Math.sqrt(Math.pow(Math.abs(endPos.x-tilePos.x),2)+Math.pow(Math.abs(endPos.y-tilePos.y),2))/2+randFloat(0,2);};let cameFrom={};let tilesToCheck=[posToString(startPos)];let gScore={};gScore[posToString(startPos)]=0;let fScore={};fScore[posToString(startPos)]=heuristics(startPos);let neighbors=[new Vector(0,-1),new Vector(1,0),new Vector(0,1),new Vector(-1,0),];let iter=10000;while(tilesToCheck.length&&iter-->0){let lowesF=tilesToCheck[0];for(let key in fScore){if(fScore[key]<fScore[lowesF])lowesF=key;};let currentTilePos=stringToPos(lowesF);if(currentTilePos.isEqual(endPos))return generatePath(cameFrom,currentTilePos);delete fScore[lowesF];tilesToCheck=tilesToCheck.filter(t=>t!=lowesF);for(let neighborOffset of neighbors){let neighborPos=currentTilePos.add(neighborOffset);this.setTileCollisionAt(0,neighborPos,true);let neighborTravelCost=this.getTileNavigationAt(navLayer,neighborPos);if(neighborTravelCost===null)continue;let tentative_neigborScore=(gScore[posToString(currentTilePos)]??Infinity)+neighborTravelCost;if(tentative_neigborScore<(gScore[posToString(neighborPos)]??Infinity)){cameFrom[posToString(neighborPos)]=currentTilePos;gScore[posToString(neighborPos)]=tentative_neigborScore;fScore[posToString(neighborPos)]=tentative_neigborScore+heuristics(neighborPos);let nPos=posToString(neighborPos);if(!tilesToCheck.includes(nPos))tilesToCheck.push(nPos);};};};return null;};_updateCollision(collisionLayer){throw Error("Not implemented")};_updateNavigation(navLayer){throw Error("Not implemented")};update(){for(let tileId in this.#tiles){this.#tiles[tileId].update();};};render(gridColor=null,gridThickness=null,collision=false,navigation=false){let self=this;for(let layerId of this.getLayers("graphics")){this.getGrid(layerId).forEach(function(x,y,tile){if(tile.id===null)return;let tilePos=new Vector(self.pos.x+x*self.tileWidth,self.pos.y+y*self.tileHeight);ctx.imageSmoothingEnabled=!c.isPixelPerfect;camera.renderTexture(self.getTileById(tile.id).texture,...tilePos.toArray(),self.tileWidth,self.tileHeight);});};if(collision){for(let layerId of this.getLayers("collision")){this.getGrid(layerId).forEach(function(x,y,tile){if(tile===null)return;let tilePos=new Vector(self.pos.x+x*self.tileWidth,self.pos.y+y*self.tileHeight);ctx.fillStyle=`rgba(0, 100, 255, ${tile / 2})`;ctx.fillRect(...camera.w2cf(tilePos,self.tileSize));});for(let obj of this.#layers[layerId].objects){obj.render();};};};if(navigation){let tileInset=1;for(let layerId of this.getLayers("navigation")){this.getGrid(layerId).forEach(function(x,y,tile){if(tile===null)return;let tilePos=new Vector(self.pos.x+x*self.tileWidth+(tileInset/2),self.pos.y+y*self.tileHeight+(tileInset/2));ctx.fillStyle=`rgba(255, 0, 0, ${tile / 2})`;ctx.fillRect(...camera.w2cf(tilePos,self.tileSize.sub(new Vector(tileInset))));});for(let obj of this.#layers[layerId].objects){obj.render();};};};if(gridColor!=null){ctx.strokeStyle=gridColor;ctx.lineWidth=camera.w2csX(gridThickness);ctx.lineJoin="butt";ctx.lineCap="butt";for(let y=0;y<=this.#height;y++){ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.left,this.pos.y+y*this.tileHeight));ctx.lineTo(...camera.w2cXY(this.right,this.pos.y+y*this.tileHeight));ctx.stroke();};for(let x=0;x<=this.#width;x++){ctx.beginPath();ctx.moveTo(...camera.w2cXY(this.pos.x+x*this.tileWidth,this.top));ctx.lineTo(...camera.w2cXY(this.pos.x+x*this.tileWidth,this.bottom));ctx.stroke();};};};}