tscratch 0.5.7 → 0.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var D=Object.defineProperty;var H=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var G=Object.prototype.hasOwnProperty;var U=(r,t)=>{for(var i in t)D(r,i,{get:t[i],enumerable:!0})},j=(r,t,i,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of $(t))!G.call(r,n)&&n!==i&&D(r,n,{get:()=>t[n],enumerable:!(e=H(t,n))||e.enumerable});return r};var J=r=>j(D({},"__esModule",{value:!0}),r);var Q={};U(Q,{Circle:()=>S,Engine:()=>b,ImageSprite:()=>M,Oval:()=>v,Pen:()=>C,Rectangle:()=>y,RegularPolygon:()=>P,Sprite:()=>l,Square:()=>w,Text:()=>B,canvas:()=>s,ctx:()=>h,default:()=>N,setAspectRatio:()=>X,setScale:()=>L});module.exports=J(Q);var s=document.getElementById("game-window")||document.createElement("canvas"),h=s.getContext("2d"),u=document.createElement("canvas"),o=u.getContext("2d");u.id="pen-canvas";var O=16/9,p;function L(r){p=r,s.width=O*p,s.height=p,u.width=O*p,u.height=p}function X(r){O=r,s.width=O*p,s.height=p,u.width=O*p,u.height=p}s.parentElement?.insertBefore(u,s);L(500);var l=class r{x;y;dir;scene;hidden;layer;cachedPath=null;pathDirty=!0;static collisionCanvas=null;static collisionCtx=null;refresh(){b.init().refresh()}invalidatePath(){this.pathDirty=!0,this.cachedPath=null}getCachedPath(){return(this.pathDirty||!this.cachedPath)&&(this.cachedPath=this.getPath(),this.pathDirty=!1),this.cachedPath}constructor(t){this.x=t?.x??0,this.y=t?.y??0,this.dir=t?.dir??0,this.scene=t?.scene??"main",this.hidden=t?.hidden??!1,this.layer=t?.layer??0,b.init().addSprite(this)}touching(t){let i=this.getBoundingBox(),e=t.getBoundingBox();if(!(Math.abs(i.x-e.x)<(i.width+e.width)/2&&Math.abs(i.y-e.y)<(i.height+e.height)/2))return!1;let a=i.x-i.width/2,m=i.y+i.height/2,f=i.x+i.width/2,x=i.y-i.height/2,W=e.x-e.width/2,k=e.y+e.height/2,I=e.x+e.width/2,A=e.y-e.height/2,T=Math.max(a,W),F=Math.min(x,A),z=Math.min(f,I),E=Math.max(m,k),g=z-T,d=E-F;if(g<=1||d<=1)return!1;r.collisionCanvas||(r.collisionCanvas=document.createElement("canvas"),r.collisionCtx=r.collisionCanvas.getContext("2d",{willReadFrequently:!0})),(r.collisionCanvas.width<g||r.collisionCanvas.height<d)&&(r.collisionCanvas.width=Math.max(g,r.collisionCanvas.width),r.collisionCanvas.height=Math.max(d,r.collisionCanvas.height));let c=r.collisionCtx;c.clearRect(0,0,g,d),c.save(),c.translate(this.x-T,d-this.y+F),c.rotate(this.toRadians(this.dir)),c.fillStyle="red",c.fill(this.getCachedPath()),c.restore();let Y=c.getImageData(0,0,g,d).data;c.clearRect(0,0,g,d),c.save(),c.translate(t.x-T,d-t.y+F),c.rotate(this.toRadians(t.dir)),c.fillStyle="blue",c.fill(t.getCachedPath()),c.restore();let q=c.getImageData(0,0,g,d).data;for(let R=3;R<Y.length;R+=4)if(Y[R]>0&&q[R]>0)return!0;return!1}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}move(t){this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.refresh()}turn(t){this.dir+=t,this.refresh()}point(t){this.dir=t,this.refresh()}pointTowards(t,i){this.dir=90-this.toDegrees(Math.atan2(i,t)),this.refresh()}setX(t){this.x=t,this.refresh()}setY(t){this.y=t,this.refresh()}goTo(t,i){this.x=t,this.y=i,this.refresh()}changeX(t){this.x+=t,this.refresh()}changeY(t){this.y+=t,this.refresh()}show(){this.hidden=!1,this.refresh()}hide(){this.hidden=!0,this.refresh()}goToLayer(t){this.layer=t,this.refresh()}changeLayer(t){this.layer+=t,this.refresh()}};var b=class r{static instance;loopRunning=!1;gameLoop=null;maxFPS=24;deltaTime=1/this.maxFPS;lastFrame=performance.now();refreshScheduled=!1;animationFrameId=null;sounds=[];mouseX=0;mouseY=0;mouseDown=!1;mouseClicked=!1;keysPressed=new Set;currentScene="main";sceneMap={};static init(){return this.instance||(this.instance=new r),this.instance}changeScene(t){this.sceneMap[t]||(this.sceneMap[t]={sprites:[],loop:null}),this.loopRunning=!1,this.currentScene=t,this.gameLoop=this.sceneMap[t].loop,this.setMaxFramesPerSecond(this.maxFPS)}setLoop(t,i){if(!this.sceneMap[t]){this.sceneMap[t]={sprites:[],loop:i},t===this.currentScene&&this.changeScene(t);return}this.sceneMap[t].loop=i,t===this.currentScene&&this.changeScene(t)}pauseLoop(){this.loopRunning=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}resumeLoop(){this.loopRunning=!0,this.setMaxFramesPerSecond(this.maxFPS)}addSprite(t){let{scene:i,layer:e}=t;if(!this.sceneMap[i]){this.sceneMap[i]={sprites:[t],loop:null};return}let n=this.sceneMap[i].sprites.findIndex(a=>a.layer>e);if(n===-1){this.sceneMap[i].sprites.push(t);return}this.sceneMap[i].sprites.splice(n,0,t),this.refresh()}removeSprite(t){let{scene:i}=t;this.sceneMap[i]&&(this.sceneMap[i].sprites=this.sceneMap[i].sprites.filter(e=>e!==t),this.refresh())}async setMaxFramesPerSecond(t){this.maxFPS=t;let i=this.gameLoop;if(!i)return;this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.loopRunning=!0;let e=1e3/t,n=0,a=async m=>{if(!this.loopRunning)return;let f=m-this.lastFrame;this.lastFrame=m,n+=f,n>=e&&(this.deltaTime=n/1e3,n=n%e,i&&await i()),this.animationFrameId=requestAnimationFrame(a)};this.lastFrame=performance.now(),this.animationFrameId=requestAnimationFrame(a)}refresh(){this.refreshScheduled||(this.refreshScheduled=!0,requestAnimationFrame(()=>{this.refreshScheduled=!1,h.clearRect(0,0,s.width,s.height),[...this.sceneMap[this.currentScene]?.sprites??[],...this.sceneMap["*"]?.sprites??[]].forEach(i=>{i.hidden||i.draw()})}))}async wait(t){return new Promise(i=>setTimeout(i,t))}async waitUntil(t){return new Promise(i=>{let e=()=>{t()?i():setTimeout(e,1e3/this.maxFPS)};e()})}hovering(t){let{mouseX:i,mouseY:e}=this,n=i+s.width/2,a=s.height/2-e,m=n-(t.x+s.width/2),f=a-(s.height/2-t.y),x=-this.toRadians(t.dir),W=m*Math.cos(x)-f*Math.sin(x),k=m*Math.sin(x)+f*Math.cos(x);return h.isPointInPath(t.getPath(),W,k)}keyPressed(t){return this.keysPressed.has(t)}playSound(t){let i=new Audio(t);return this.sounds.push(i),i.play(),i}stopSound(t){t.pause(),t.currentTime=0,this.sounds=this.sounds.filter(i=>i!==t)}stopAllSounds(){this.sounds.forEach(t=>{t.pause(),t.currentTime=0}),this.sounds=[]}pickRandom(t,i){return t>i&&([t,i]=[i,t]),Math.floor(Math.random()*(i-t+1)+t)}sin(t){return Math.sin(this.toRadians(t))}cos(t){return Math.cos(this.toRadians(t))}tan(t){return Math.tan(this.toRadians(t))}csc(t){return 1/Math.sin(this.toRadians(t))}sec(t){return 1/Math.cos(this.toRadians(t))}cot(t){return 1/Math.tan(this.toRadians(t))}asin(t){return this.toDegrees(Math.asin(t))}acos(t){return this.toDegrees(Math.acos(t))}acsc(t){return this.toDegrees(Math.asin(1/t))}asec(t){return this.toDegrees(Math.acos(1/t))}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}constructor(){this.setMaxFramesPerSecond(24),u.addEventListener("mousemove",t=>{this.mouseX=t.clientX-u.offsetLeft-u.width/2,this.mouseY=-(t.clientY-u.offsetTop-u.height/2)}),u.addEventListener("mousedown",t=>{this.mouseDown=!0}),u.addEventListener("mouseup",t=>{this.mouseDown=!1}),u.addEventListener("click",t=>{this.mouseClicked=!0,setTimeout(()=>this.mouseClicked=!1,0)}),addEventListener("keydown",t=>{t.repeat||this.keysPressed.add(t.key)}),addEventListener("keyup",t=>{this.keysPressed.delete(t.key)})}};var y=class extends l{discriminant="rectangle";width;height;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.width,this.height),height:Math.hypot(this.width,this.height)}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.width=t?.width??50,this.height=t?.height??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var w=class extends l{discriminant="square";sideLength;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.sideLength,this.sideLength),height:Math.hypot(this.sideLength,this.sideLength)}}getPath(){let t=new Path2D;return t.rect(-this.sideLength/2,-this.sideLength/2,this.sideLength,this.sideLength),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setSideLength(t){this.sideLength=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sideLength=t?.sideLength??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var v=class extends l{discriminant="circle";radX;radY;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.radX*2,this.radY*2),height:Math.hypot(this.radX*2,this.radY*2)}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radX,this.radY,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setRadX(t){this.radX=t,this.invalidatePath(),this.refresh()}setRadY(t){this.radY=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radX=t?.radX??25,this.radY=t?.radY??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var S=class extends l{discriminant="circle";radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radius,this.radius,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var P=class extends l{discriminant="regularpolygon";sides;radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D,i=2*Math.PI/this.sides;t.moveTo(this.radius,0);for(let e=1;e<this.sides;e++)t.lineTo(this.radius*Math.cos(i*e),this.radius*Math.sin(i*e));return t.closePath(),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setSides(t){this.sides=t,this.invalidatePath(),this.refresh()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sides=t?.sides??5,this.radius=t?.radius??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var C=class extends l{discriminant="pen";drawing;size;color;getBoundingBox(){return{x:this.x,y:this.y,width:this.size,height:this.size}}getPath(){return new Path2D}draw(){}up(){this.drawing=!1}down(){this.drawing=!0}stamp(t){t.draw(!0)}eraseAll(){o.clearRect(0,0,s.width,s.height)}dot(){o.fillStyle=this.color,o.fillRect(this.x-this.size/2+s.width/2,-this.y-this.size/2+s.height/2,this.size,this.size)}drawLine(t,i){o.beginPath(),o.moveTo(t+s.width/2,-i+s.height/2),o.lineTo(this.x+s.width/2,-this.y+s.height/2),o.lineWidth=this.size,o.strokeStyle=this.color,o.stroke()}move(t){let i=this.x,e=this.y;this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.drawing&&this.drawLine(i,e),this.refresh()}setX(t){let i=this.x,e=this.y;this.x=t,this.drawing&&this.drawLine(i,e),this.refresh()}setY(t){let i=this.x,e=this.y;this.y=t,this.drawing&&this.drawLine(i,e),this.refresh()}goTo(t,i){let e=this.x,n=this.y;this.x=t,this.y=i,this.drawing&&this.drawLine(e,n),this.refresh()}changeX(t){let i=this.x,e=this.y;this.x+=t,this.drawing&&this.drawLine(i,e),this.refresh()}changeY(t){let i=this.x,e=this.y;this.y+=t,this.drawing&&this.drawLine(i,e),this.refresh()}constructor(t){super(t),this.drawing=t?.drawing??!1,this.size=t?.size??5,this.color=t?.color??"black"}};var B=class extends l{discriminant="text";content;color;fontFamily;fontSize;align;baseline;font;getBoundingBox(){let t=h.measureText(this.content),i=t.width,e=t.actualBoundingBoxAscent+t.actualBoundingBoxDescent;return{x:this.x,y:this.y,width:i,height:e}}getPath(){let t=new Path2D;h.save(),h.font=this.font;let i=h.measureText(this.content),e=i.width,n=i.actualBoundingBoxAscent+i.actualBoundingBoxDescent;return h.restore(),t.rect(-e/2,-n/2,e,n),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.font=this.font,i.fillStyle=this.color,i.textAlign=this.align,i.textBaseline=this.baseline,i.fillText(this.content,0,0),i.restore()}setContent(t){this.content=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}setFontSize(t){this.fontSize=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setFontFamily(t){this.fontFamily=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setAlign(t){this.align=t,this.invalidatePath(),this.refresh()}setBaseline(t){this.baseline=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.content=t?.content??"",this.color=t?.color??"black",this.fontFamily=t?.fontFamily??"Arial",this.fontSize=t?.fontSize??16,this.align=t?.align??"center",this.baseline=t?.baseline??"middle",this.font=`${this.fontSize}px ${this.fontFamily}`,this.draw()}};var M=class extends l{discriminant="imagesprite";src;width;height;outlineColor;outlineWidth;img;getBoundingBox(){return{x:this.x,y:this.y,width:this.width,height:this.height}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height),this.outlineWidth&&i.stroke(this.getCachedPath()),i.restore()}setSrc(t){this.src=t,this.refresh()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.src=t?.src??"",this.img=new Image,this.img.src=this.src,this.width=t?.width??this.img.width,this.height=t?.height??this.img.height,this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var K={Engine:b,Sprite:l,Rectangle:y,Square:w,Oval:v,Circle:S,RegularPolygon:P,Pen:C,Text:B,ImageSprite:M,setScale:L,setAspectRatio:X,canvas:s,ctx:h},N=K;0&&(module.exports={Circle,Engine,ImageSprite,Oval,Pen,Rectangle,RegularPolygon,Sprite,Square,Text,canvas,ctx,setAspectRatio,setScale});
1
+ "use strict";var Y=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var j=(r,t)=>{for(var i in t)Y(r,i,{get:t[i],enumerable:!0})},J=(r,t,i,e)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of G(t))!U.call(r,n)&&n!==i&&Y(r,n,{get:()=>t[n],enumerable:!(e=$(t,n))||e.enumerable});return r};var K=r=>J(Y({},"__esModule",{value:!0}),r);var Z={};j(Z,{Arc:()=>S,Circle:()=>C,CustomPolygon:()=>B,Engine:()=>b,ImageSprite:()=>W,Oval:()=>v,Pen:()=>M,Rectangle:()=>y,RegularPolygon:()=>P,Sprite:()=>l,Square:()=>w,Text:()=>O,canvas:()=>s,ctx:()=>o,default:()=>Q,setAspectRatio:()=>I,setScale:()=>L});module.exports=K(Z);var s=document.getElementById("game-window")||document.createElement("canvas"),o=s.getContext("2d"),u=document.createElement("canvas"),a=u.getContext("2d");u.id="pen-canvas";var R=16/9,p;function L(r){p=r,s.width=R*p,s.height=p,u.width=R*p,u.height=p}function I(r){R=r,s.width=R*p,s.height=p,u.width=R*p,u.height=p}s.parentElement?.insertBefore(u,s);L(500);var l=class r{x;y;dir;scene;hidden;layer;cachedPath=null;pathDirty=!0;static collisionCanvas=null;static collisionCtx=null;refresh(){b.init().refresh()}invalidatePath(){this.pathDirty=!0,this.cachedPath=null}getCachedPath(){return(this.pathDirty||!this.cachedPath)&&(this.cachedPath=this.getPath(),this.pathDirty=!1),this.cachedPath}constructor(t){this.x=t?.x??0,this.y=t?.y??0,this.dir=t?.dir??0,this.scene=t?.scene??"main",this.hidden=t?.hidden??!1,this.layer=t?.layer??0,b.init().addSprite(this)}touching(t){let i=this.getBoundingBox(),e=t.getBoundingBox();if(!(Math.abs(i.x-e.x)<(i.width+e.width)/2&&Math.abs(i.y-e.y)<(i.height+e.height)/2))return!1;let h=i.x-i.width/2,m=i.y+i.height/2,f=i.x+i.width/2,x=i.y-i.height/2,T=e.x-e.width/2,D=e.y+e.height/2,V=e.x+e.width/2,z=e.y-e.height/2,F=Math.max(h,T),X=Math.min(x,z),E=Math.min(f,V),q=Math.max(m,D),g=E-F,d=q-X;if(g<=1||d<=1)return!1;r.collisionCanvas||(r.collisionCanvas=document.createElement("canvas"),r.collisionCtx=r.collisionCanvas.getContext("2d",{willReadFrequently:!0})),(r.collisionCanvas.width<g||r.collisionCanvas.height<d)&&(r.collisionCanvas.width=Math.max(g,r.collisionCanvas.width),r.collisionCanvas.height=Math.max(d,r.collisionCanvas.height));let c=r.collisionCtx;c.clearRect(0,0,g,d),c.save(),c.translate(this.x-F,d-this.y+X),c.rotate(this.toRadians(this.dir)),c.fillStyle="red",c.fill(this.getCachedPath()),c.restore();let A=c.getImageData(0,0,g,d).data;c.clearRect(0,0,g,d),c.save(),c.translate(t.x-F,d-t.y+X),c.rotate(this.toRadians(t.dir)),c.fillStyle="blue",c.fill(t.getCachedPath()),c.restore();let H=c.getImageData(0,0,g,d).data;for(let k=3;k<A.length;k+=4)if(A[k]>0&&H[k]>0)return!0;return!1}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}move(t){this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.refresh()}turn(t){this.dir+=t,this.refresh()}point(t){this.dir=t,this.refresh()}pointTowards(t,i){this.dir=90-this.toDegrees(Math.atan2(i,t)),this.refresh()}setX(t){this.x=t,this.refresh()}setY(t){this.y=t,this.refresh()}goTo(t,i){this.x=t,this.y=i,this.refresh()}changeX(t){this.x+=t,this.refresh()}changeY(t){this.y+=t,this.refresh()}show(){this.hidden=!1,this.refresh()}hide(){this.hidden=!0,this.refresh()}goToLayer(t){this.layer=t,this.refresh()}changeLayer(t){this.layer+=t,this.refresh()}};var b=class r{static instance;loopRunning=!1;gameLoop=null;maxFPS=24;deltaTime=1/this.maxFPS;lastFrame=performance.now();refreshScheduled=!1;animationFrameId=null;sounds=[];mouseX=0;mouseY=0;mouseDown=!1;mouseClicked=!1;keysPressed=new Set;currentScene="main";sceneMap={};static init(){return this.instance||(this.instance=new r),this.instance}changeScene(t){this.sceneMap[t]||(this.sceneMap[t]={sprites:[],loop:null}),this.loopRunning=!1,this.currentScene=t,this.gameLoop=this.sceneMap[t].loop,this.setMaxFramesPerSecond(this.maxFPS)}setLoop(t,i){if(!this.sceneMap[t]){this.sceneMap[t]={sprites:[],loop:i},t===this.currentScene&&this.changeScene(t);return}this.sceneMap[t].loop=i,t===this.currentScene&&this.changeScene(t)}pauseLoop(){this.loopRunning=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}resumeLoop(){this.loopRunning=!0,this.setMaxFramesPerSecond(this.maxFPS)}addSprite(t){let{scene:i,layer:e}=t;if(!this.sceneMap[i]){this.sceneMap[i]={sprites:[t],loop:null};return}let n=this.sceneMap[i].sprites.findIndex(h=>h.layer>e);if(n===-1){this.sceneMap[i].sprites.push(t);return}this.sceneMap[i].sprites.splice(n,0,t),this.refresh()}removeSprite(t){let{scene:i}=t;this.sceneMap[i]&&(this.sceneMap[i].sprites=this.sceneMap[i].sprites.filter(e=>e!==t),this.refresh())}async setMaxFramesPerSecond(t){this.maxFPS=t;let i=this.gameLoop;if(!i)return;this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.loopRunning=!0;let e=1e3/t,n=0,h=async m=>{if(!this.loopRunning)return;let f=m-this.lastFrame;this.lastFrame=m,n+=f,n>=e&&(this.deltaTime=n/1e3,n=n%e,i&&await i()),this.animationFrameId=requestAnimationFrame(h)};this.lastFrame=performance.now(),this.animationFrameId=requestAnimationFrame(h)}refresh(){this.refreshScheduled||(this.refreshScheduled=!0,requestAnimationFrame(()=>{this.refreshScheduled=!1,o.clearRect(0,0,s.width,s.height),[...this.sceneMap[this.currentScene]?.sprites??[],...this.sceneMap["*"]?.sprites??[]].forEach(i=>{i.hidden||i.draw()})}))}async wait(t){return new Promise(i=>setTimeout(i,t))}async waitUntil(t){return new Promise(i=>{let e=()=>{t()?i():setTimeout(e,1e3/this.maxFPS)};e()})}hovering(t){let{mouseX:i,mouseY:e}=this,n=i+s.width/2,h=s.height/2-e,m=n-(t.x+s.width/2),f=h-(s.height/2-t.y),x=-this.toRadians(t.dir),T=m*Math.cos(x)-f*Math.sin(x),D=m*Math.sin(x)+f*Math.cos(x);return o.isPointInPath(t.getPath(),T,D)}keyPressed(t){return this.keysPressed.has(t)}playSound(t){let i=new Audio(t);return this.sounds.push(i),i.play(),i}stopSound(t){t.pause(),t.currentTime=0,this.sounds=this.sounds.filter(i=>i!==t)}stopAllSounds(){this.sounds.forEach(t=>{t.pause(),t.currentTime=0}),this.sounds=[]}pickRandom(t,i){return t>i&&([t,i]=[i,t]),Math.floor(Math.random()*(i-t+1)+t)}dotProduct(t){let[i,e]=t;switch(i.length){case 2:return i[0]*e[0]+i[1]*e[1];case 3:return i[0]*e[0]+i[1]*e[1]+i[2]*e[2];case 4:return i[0]*e[0]+i[1]*e[1]+i[2]*e[2]+i[3]*e[3]}}sin(t){return Math.sin(this.toRadians(t))}cos(t){return Math.cos(this.toRadians(t))}tan(t){return Math.tan(this.toRadians(t))}csc(t){return 1/Math.sin(this.toRadians(t))}sec(t){return 1/Math.cos(this.toRadians(t))}cot(t){return 1/Math.tan(this.toRadians(t))}asin(t){return this.toDegrees(Math.asin(t))}acos(t){return this.toDegrees(Math.acos(t))}acsc(t){return this.toDegrees(Math.asin(1/t))}asec(t){return this.toDegrees(Math.acos(1/t))}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}constructor(){this.setMaxFramesPerSecond(24),u.addEventListener("mousemove",t=>{this.mouseX=t.clientX-u.offsetLeft-u.width/2,this.mouseY=-(t.clientY-u.offsetTop-u.height/2)}),u.addEventListener("mousedown",t=>{this.mouseDown=!0}),u.addEventListener("mouseup",t=>{this.mouseDown=!1}),u.addEventListener("click",t=>{this.mouseClicked=!0,setTimeout(()=>this.mouseClicked=!1,0)}),addEventListener("keydown",t=>{t.repeat||this.keysPressed.add(t.key)}),addEventListener("keyup",t=>{this.keysPressed.delete(t.key)})}};var y=class extends l{discriminant="rectangle";width;height;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.width,this.height),height:Math.hypot(this.width,this.height)}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.width=t?.width??50,this.height=t?.height??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var w=class extends l{discriminant="square";sideLength;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.sideLength,this.sideLength),height:Math.hypot(this.sideLength,this.sideLength)}}getPath(){let t=new Path2D;return t.rect(-this.sideLength/2,-this.sideLength/2,this.sideLength,this.sideLength),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setSideLength(t){this.sideLength=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sideLength=t?.sideLength??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var v=class extends l{discriminant="oval";radX;radY;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.radX*2,this.radY*2),height:Math.hypot(this.radX*2,this.radY*2)}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radX,this.radY,0,0,Math.PI*2),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setRadX(t){this.radX=t,this.invalidatePath(),this.refresh()}setRadY(t){this.radY=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radX=t?.radX??25,this.radY=t?.radY??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var C=class extends l{discriminant="circle";radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radius,this.radius,0,0,Math.PI*2),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var S=class extends l{discriminant="arc";radius;angle;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.arc(0,0,this.radius,this.toRadians(this.angle/2-90),this.toRadians(-this.angle/2-90)),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setAngle(t){this.angle=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.angle=t?.angle??270,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var P=class extends l{discriminant="regularpolygon";sides;radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D,i=2*Math.PI/this.sides;t.moveTo(this.radius,0);for(let e=1;e<this.sides;e++)t.lineTo(this.radius*Math.cos(i*e),this.radius*Math.sin(i*e));return t.closePath(),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setSides(t){this.sides=t,this.invalidatePath(),this.refresh()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sides=t?.sides??5,this.radius=t?.radius??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var B=class extends l{discriminant="custompolygon";vertices;color;outlineColor;outlineWidth;getBoundingBox(){let t=0;for(let i of this.vertices){let e=Math.hypot(i[0],i[1]);e>t&&(t=e)}return{x:this.x,y:this.y,width:t,height:t}}getPath(){let t=new Path2D,i=this.vertices;if(i.length<2)return t;t.moveTo(i[0][0],i[0][1]);for(let e=1;e<i.length;e++)t.lineTo(i[e][0],i[e][1]);return t.closePath(),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let h=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(h),this.outlineWidth&&i.stroke(h),i.restore()}setVertices(t){this.vertices=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.vertices=t?.vertices??[],this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var M=class extends l{discriminant="pen";drawing;size;color;getBoundingBox(){return{x:this.x,y:this.y,width:this.size,height:this.size}}getPath(){return new Path2D}draw(){}up(){this.drawing=!1}down(){this.drawing=!0}stamp(t){t.draw(!0)}eraseAll(){a.clearRect(0,0,s.width,s.height)}dot(){a.fillStyle=this.color,a.fillRect(this.x-this.size/2+s.width/2,-this.y-this.size/2+s.height/2,this.size,this.size)}drawLine(t,i){a.beginPath(),a.moveTo(t+s.width/2,-i+s.height/2),a.lineTo(this.x+s.width/2,-this.y+s.height/2),a.lineWidth=this.size,a.strokeStyle=this.color,a.stroke()}move(t){let i=this.x,e=this.y;this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.drawing&&this.drawLine(i,e),this.refresh()}setX(t){let i=this.x,e=this.y;this.x=t,this.drawing&&this.drawLine(i,e),this.refresh()}setY(t){let i=this.x,e=this.y;this.y=t,this.drawing&&this.drawLine(i,e),this.refresh()}goTo(t,i){let e=this.x,n=this.y;this.x=t,this.y=i,this.drawing&&this.drawLine(e,n),this.refresh()}changeX(t){let i=this.x,e=this.y;this.x+=t,this.drawing&&this.drawLine(i,e),this.refresh()}changeY(t){let i=this.x,e=this.y;this.y+=t,this.drawing&&this.drawLine(i,e),this.refresh()}constructor(t){super(t),this.drawing=t?.drawing??!1,this.size=t?.size??5,this.color=t?.color??"black"}};var O=class extends l{discriminant="text";content;color;fontFamily;fontSize;align;baseline;font;getBoundingBox(){let t=o.measureText(this.content),i=t.width,e=t.actualBoundingBoxAscent+t.actualBoundingBoxDescent;return{x:this.x,y:this.y,width:i,height:e}}getPath(){let t=new Path2D;o.save(),o.font=this.font;let i=o.measureText(this.content),e=i.width,n=i.actualBoundingBoxAscent+i.actualBoundingBoxDescent;return o.restore(),t.rect(-e/2,-n/2,e,n),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.font=this.font,i.fillStyle=this.color,i.textAlign=this.align,i.textBaseline=this.baseline,i.fillText(this.content,0,0),i.restore()}setContent(t){this.content=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}setFontSize(t){this.fontSize=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setFontFamily(t){this.fontFamily=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setAlign(t){this.align=t,this.invalidatePath(),this.refresh()}setBaseline(t){this.baseline=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.content=t?.content??"",this.color=t?.color??"black",this.fontFamily=t?.fontFamily??"Arial",this.fontSize=t?.fontSize??16,this.align=t?.align??"center",this.baseline=t?.baseline??"middle",this.font=`${this.fontSize}px ${this.fontFamily}`,this.draw()}};var W=class extends l{discriminant="imagesprite";src;width;height;outlineColor;outlineWidth;img;getBoundingBox(){return{x:this.x,y:this.y,width:this.width,height:this.height}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?a:o;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height),this.outlineWidth&&i.stroke(this.getCachedPath()),i.restore()}setSrc(t){this.src=t,this.refresh()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.src=t?.src??"",this.img=new Image,this.img.src=this.src,this.width=t?.width??this.img.width,this.height=t?.height??this.img.height,this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var N={Engine:b,Sprite:l,Rectangle:y,Square:w,Oval:v,Circle:C,Arc:S,RegularPolygon:P,CustomPolygon:B,Pen:M,Text:O,ImageSprite:W,setScale:L,setAspectRatio:I,canvas:s,ctx:o},Q=N;0&&(module.exports={Arc,Circle,CustomPolygon,Engine,ImageSprite,Oval,Pen,Rectangle,RegularPolygon,Sprite,Square,Text,canvas,ctx,setAspectRatio,setScale});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/canvas.ts","../src/Sprite.ts","../src/Engine.ts","../src/sprites/Rectangle.ts","../src/sprites/Square.ts","../src/sprites/Oval.ts","../src/sprites/Circle.ts","../src/sprites/RegularPolygon.ts","../src/sprites/Pen.ts","../src/sprites/Text.ts","../src/sprites/ImageSprite.ts"],"sourcesContent":["import Engine from './Engine.ts';\r\nimport Sprite, { type SpriteOptions } from './Sprite.ts';\r\nimport { setScale, setAspectRatio, canvas, ctx } from './canvas.ts';\r\n\r\nimport Rectangle, { type RectangleOptions } from './sprites/Rectangle.ts';\r\nimport Square, { type SquareOptions } from './sprites/Square.ts';\r\nimport Oval, { type OvalOptions } from './sprites/Oval.ts';\r\nimport Circle, { type CircleOptions } from './sprites/Circle.ts';\r\nimport RegularPolygon, { type RegularPolygonOptions } from './sprites/RegularPolygon.ts';\r\nimport Pen, { type PenOptions } from './sprites/Pen.ts';\r\nimport Text, { type TextOptions, type CanvasTextAlign, type CanvasTextBaseline } from './sprites/Text.ts';\r\nimport ImageSprite, { type ImageSpriteOptions } from './sprites/ImageSprite.ts';\r\n\r\nconst TScratch = {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n RegularPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};\r\n\r\nexport default TScratch;\r\nexport {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n RegularPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Options\r\n type SpriteOptions,\r\n type RectangleOptions,\r\n type SquareOptions,\r\n type OvalOptions,\r\n type CircleOptions,\r\n type RegularPolygonOptions,\r\n type PenOptions,\r\n type TextOptions,\r\n type ImageSpriteOptions,\r\n\r\n // Other types\r\n type CanvasTextAlign,\r\n type CanvasTextBaseline,\r\n \r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};","export const canvas = document.getElementById('game-window') as HTMLCanvasElement || document.createElement('canvas'); // For testing\r\nexport const ctx = canvas.getContext('2d')!;\r\n\r\nexport const penCanvas = document.createElement('canvas');\r\nexport const penCtx = penCanvas.getContext('2d')!;\r\npenCanvas.id = 'pen-canvas';\r\n\r\nlet ratio: number = 16 / 9;\r\nlet scale: number;\r\n\r\nexport function setScale(newScale: number) {\r\n scale = newScale;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\nexport function setAspectRatio(newAspectRatio: number) {\r\n ratio = newAspectRatio;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\ncanvas.parentElement?.insertBefore(penCanvas, canvas);\r\n\r\nsetScale(500);","import Engine from './Engine.ts';\r\n\r\nexport interface BoundingBox {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface SpriteOptions {\r\n x?: number;\r\n y?: number;\r\n dir?: number;\r\n scene?: string;\r\n hidden?: boolean;\r\n layer?: number;\r\n}\r\n\r\nexport default abstract class Sprite {\r\n\r\n public x: number;\r\n public y: number;\r\n public dir: number;\r\n public scene: string;\r\n public hidden: boolean;\r\n public layer: number;\r\n\r\n private cachedPath: Path2D | null = null;\r\n private pathDirty: boolean = true;\r\n\r\n // Reusable collision detection canvas\r\n private static collisionCanvas: HTMLCanvasElement | null = null;\r\n private static collisionCtx: CanvasRenderingContext2D | null = null;\r\n\r\n // Rendering\r\n\r\n public abstract getBoundingBox(): BoundingBox;\r\n public abstract getPath(): Path2D;\r\n public abstract draw(stamping?: boolean): void;\r\n\r\n protected refresh() {\r\n Engine.init().refresh();\r\n }\r\n\r\n protected invalidatePath() {\r\n this.pathDirty = true;\r\n this.cachedPath = null;\r\n }\r\n\r\n protected getCachedPath(): Path2D {\r\n if (this.pathDirty || !this.cachedPath) {\r\n this.cachedPath = this.getPath();\r\n this.pathDirty = false;\r\n }\r\n return this.cachedPath;\r\n }\r\n\r\n constructor(options?: SpriteOptions) {\r\n this.x = options?.x ?? 0;\r\n this.y = options?.y ?? 0;\r\n this.dir = options?.dir ?? 0;\r\n this.scene = options?.scene ?? 'main';\r\n this.hidden = options?.hidden ?? false;\r\n this.layer = options?.layer ?? 0;\r\n Engine.init().addSprite(this);\r\n }\r\n\r\n // Sensing\r\n\r\n public touching(sprite: Sprite): boolean {\r\n\r\n // AABB (bounding boxes)\r\n const bBox1 = this.getBoundingBox();\r\n const bBox2 = sprite.getBoundingBox();\r\n\r\n const aabbOverlap =\r\n Math.abs(bBox1.x - bBox2.x) < (bBox1.width + bBox2.width) / 2 &&\r\n Math.abs(bBox1.y - bBox2.y) < (bBox1.height + bBox2.height) / 2;\r\n\r\n if (!aabbOverlap) return false;\r\n\r\n // Image data (pixel perfect)\r\n\r\n // Compute intersection bounding box\r\n const b1Left = bBox1.x - bBox1.width / 2;\r\n const b1Top = bBox1.y + bBox1.height / 2;\r\n const b1Right = bBox1.x + bBox1.width / 2;\r\n const b1Bottom = bBox1.y - bBox1.height / 2;\r\n\r\n const b2Left = bBox2.x - bBox2.width / 2;\r\n const b2Top = bBox2.y + bBox2.height / 2;\r\n const b2Right = bBox2.x + bBox2.width / 2;\r\n const b2Bottom = bBox2.y - bBox2.height / 2;\r\n\r\n const xMin = Math.max(b1Left, b2Left);\r\n const yMin = Math.min(b1Bottom, b2Bottom);\r\n const xMax = Math.min(b1Right, b2Right);\r\n const yMax = Math.max(b1Top, b2Top);\r\n\r\n const width = xMax - xMin;\r\n const height = yMax - yMin;\r\n\r\n if (width <= 1 || height <= 1) return false;\r\n\r\n // Reuse or create offscreen canvas for collision detection\r\n if (!Sprite.collisionCanvas) {\r\n Sprite.collisionCanvas = document.createElement('canvas');\r\n Sprite.collisionCtx = Sprite.collisionCanvas.getContext('2d', { willReadFrequently: true })!;\r\n }\r\n\r\n // Resize if needed\r\n if (Sprite.collisionCanvas.width < width || Sprite.collisionCanvas.height < height) {\r\n Sprite.collisionCanvas.width = Math.max(width, Sprite.collisionCanvas.width);\r\n Sprite.collisionCanvas.height = Math.max(height, Sprite.collisionCanvas.height);\r\n }\r\n\r\n const ctx = Sprite.collisionCtx!;\r\n ctx.clearRect(0, 0, width, height);\r\n\r\n // Draw first sprite\r\n ctx.save();\r\n ctx.translate(this.x - xMin, height - this.y + yMin);\r\n ctx.rotate(this.toRadians(this.dir));\r\n ctx.fillStyle = 'red';\r\n ctx.fill(this.getCachedPath());\r\n ctx.restore();\r\n const img1 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Draw second sprite\r\n ctx.clearRect(0, 0, width, height);\r\n ctx.save();\r\n ctx.translate(sprite.x - xMin, height - sprite.y + yMin);\r\n ctx.rotate(this.toRadians(sprite.dir));\r\n ctx.fillStyle = 'blue';\r\n ctx.fill(sprite.getCachedPath());\r\n ctx.restore();\r\n const img2 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Check for overlapping non-transparent pixels\r\n for (let i = 3; i < img1.length; i += 4) // alpha channel\r\n if (img1[i]! > 0 && img2[i]! > 0) return true;\r\n\r\n return false;\r\n }\r\n\r\n // Helpers\r\n\r\n protected toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n protected toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Methods\r\n\r\n // Motion\r\n public move(steps: number) {\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n this.refresh();\r\n }\r\n\r\n public turn(deg: number) {\r\n this.dir += deg;\r\n this.refresh();\r\n }\r\n\r\n public point(dir: number) {\r\n this.dir = dir;\r\n this.refresh();\r\n }\r\n\r\n public pointTowards(x: number, y: number) {\r\n this.dir = 90 - this.toDegrees(Math.atan2(y, x));\r\n this.refresh();\r\n }\r\n\r\n public setX(x: number) {\r\n this.x = x;\r\n this.refresh();\r\n }\r\n\r\n public setY(y: number) {\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public goTo(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public changeX(dX: number) {\r\n this.x += dX;\r\n this.refresh();\r\n }\r\n\r\n public changeY(dY: number) {\r\n this.y += dY;\r\n this.refresh();\r\n }\r\n\r\n // Looks\r\n\r\n public show() {\r\n this.hidden = false;\r\n this.refresh();\r\n }\r\n\r\n public hide() {\r\n this.hidden = true;\r\n this.refresh();\r\n }\r\n\r\n public goToLayer(layer: number) {\r\n this.layer = layer;\r\n this.refresh();\r\n }\r\n\r\n public changeLayer(dL: number) {\r\n this.layer += dL;\r\n this.refresh();\r\n }\r\n}","import { canvas, ctx, penCanvas } from './canvas.ts';\r\nimport Sprite from './Sprite.ts';\r\n\r\ntype GameLoop = (() => any) | (() => Promise<any>);\r\n\r\ntype SceneMap = {\r\n [scene: string]: {\r\n sprites: Sprite[];\r\n loop: GameLoop | null;\r\n };\r\n};\r\n\r\nexport default class Engine {\r\n\r\n private static instance: Engine;\r\n\r\n private loopRunning: boolean = false;\r\n public gameLoop: GameLoop | null = null;\r\n\r\n public maxFPS: number = 24;\r\n public deltaTime: number = 1 / this.maxFPS;\r\n private lastFrame: number = performance.now();\r\n private refreshScheduled: boolean = false;\r\n private animationFrameId: number | null = null;\r\n\r\n public sounds: HTMLAudioElement[] = [];\r\n\r\n public mouseX: number = 0;\r\n public mouseY: number = 0;\r\n\r\n public mouseDown: boolean = false;\r\n public mouseClicked: boolean = false;\r\n\r\n private keysPressed: Set<string> = new Set<string>();\r\n\r\n public currentScene: string = 'main';\r\n public sceneMap: SceneMap = {};\r\n\r\n // Singleton initialization\r\n\r\n public static init() {\r\n if (!this.instance)\r\n this.instance = new Engine();\r\n\r\n return this.instance;\r\n }\r\n\r\n // Change the scene\r\n\r\n public changeScene(scene: string) {\r\n if (!this.sceneMap[scene])\r\n this.sceneMap[scene] = { sprites: [], loop: null };\r\n\r\n this.loopRunning = false;\r\n this.currentScene = scene;\r\n this.gameLoop = this.sceneMap[scene].loop;\r\n this.setMaxFramesPerSecond(this.maxFPS); // Update the interval function\r\n }\r\n\r\n // Loops\r\n\r\n public setLoop(scene: string, loop: GameLoop) {\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [], loop };\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].loop = loop;\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n }\r\n\r\n public pauseLoop() {\r\n this.loopRunning = false;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n }\r\n\r\n public resumeLoop() {\r\n this.loopRunning = true;\r\n void this.setMaxFramesPerSecond(this.maxFPS);\r\n }\r\n\r\n // Internal\r\n\r\n public addSprite(sprite: Sprite) {\r\n const { scene, layer } = sprite;\r\n\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [sprite], loop: null };\r\n return;\r\n }\r\n\r\n let targetIndex = this.sceneMap[scene].sprites.findIndex(s => s.layer > layer);\r\n if (targetIndex === -1) {\r\n this.sceneMap[scene].sprites.push(sprite);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].sprites.splice(targetIndex, 0, sprite);\r\n this.refresh();\r\n }\r\n\r\n public removeSprite(sprite: Sprite) {\r\n const { scene } = sprite;\r\n\r\n if (!this.sceneMap[scene]) return;\r\n\r\n this.sceneMap[scene].sprites = this.sceneMap[scene].sprites.filter(s => s !== sprite);\r\n this.refresh();\r\n }\r\n\r\n public async setMaxFramesPerSecond(maxFPS: number) {\r\n this.maxFPS = maxFPS;\r\n\r\n let loop = this.gameLoop;\r\n if (!loop) return;\r\n\r\n // Cancel existing animation frame if any\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n\r\n this.loopRunning = true;\r\n const frameInterval = 1000 / maxFPS;\r\n let accumulator = 0;\r\n\r\n const tick = async (currentTime: number) => {\r\n if (!this.loopRunning) return;\r\n\r\n const deltaTime = currentTime - this.lastFrame;\r\n this.lastFrame = currentTime;\r\n accumulator += deltaTime;\r\n\r\n // Fixed timestep: only run loop when enough time has passed\r\n if (accumulator >= frameInterval) {\r\n this.deltaTime = accumulator / 1000;\r\n accumulator = accumulator % frameInterval;\r\n\r\n if (loop) await loop();\r\n }\r\n\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n };\r\n\r\n this.lastFrame = performance.now();\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n }\r\n\r\n public refresh() {\r\n if (this.refreshScheduled) return;\r\n this.refreshScheduled = true;\r\n\r\n requestAnimationFrame(() => {\r\n this.refreshScheduled = false;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n const sprites = [\r\n ...(this.sceneMap[this.currentScene]?.sprites ?? []),\r\n ...(this.sceneMap['*']?.sprites ?? [])\r\n ];\r\n sprites.forEach(sprite => {\r\n if (!sprite.hidden)\r\n sprite.draw();\r\n });\r\n });\r\n }\r\n\r\n // Wait functions\r\n\r\n public async wait(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n\r\n public async waitUntil(conditionGetter: () => boolean): Promise<void> {\r\n return new Promise(resolve => {\r\n const check = () => {\r\n if (conditionGetter()) resolve();\r\n else setTimeout(check, 1000 / this.maxFPS);\r\n }\r\n check();\r\n });\r\n }\r\n\r\n // Events\r\n\r\n public hovering(sprite: Sprite) {\r\n const { mouseX, mouseY } = this;\r\n\r\n const canvasMouseX = mouseX + canvas.width / 2;\r\n const canvasMouseY = canvas.height / 2 - mouseY;\r\n\r\n // Mouse relative to sprite center\r\n const localX = canvasMouseX - (sprite.x + canvas.width / 2);\r\n const localY = canvasMouseY - (canvas.height / 2 - sprite.y);\r\n\r\n // Rotate mouse point by -dir to align with the path's local coordinates\r\n const angle = -this.toRadians(sprite.dir);\r\n const rotatedX = localX * Math.cos(angle) - localY * Math.sin(angle);\r\n const rotatedY = localX * Math.sin(angle) + localY * Math.cos(angle);\r\n\r\n return ctx.isPointInPath(sprite.getPath(), rotatedX, rotatedY);\r\n }\r\n\r\n public keyPressed(key: string) {\r\n return this.keysPressed.has(key);\r\n }\r\n\r\n // Sound\r\n\r\n public playSound(src: string) {\r\n const audio = new Audio(src);\r\n this.sounds.push(audio);\r\n\r\n audio.play();\r\n\r\n return audio;\r\n }\r\n\r\n public stopSound(sound: HTMLAudioElement) {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n this.sounds = this.sounds.filter(s => s !== sound);\r\n }\r\n\r\n public stopAllSounds() {\r\n this.sounds.forEach(sound => {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n });\r\n this.sounds = [];\r\n }\r\n\r\n // Math\r\n\r\n public pickRandom(min: number, max: number) {\r\n if (min > max)\r\n [min, max] = [max, min];\r\n return Math.floor(Math.random() * (max - min + 1) + min);\r\n }\r\n\r\n // Trigonometric functions\r\n public sin(deg: number) {\r\n return Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public cos(deg: number) {\r\n return Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public tan(deg: number) {\r\n return Math.tan(this.toRadians(deg));\r\n }\r\n\r\n public csc(deg: number) {\r\n return 1 / Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public sec(deg: number) {\r\n return 1 / Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public cot(deg: number) {\r\n return 1 / Math.tan(this.toRadians(deg));\r\n }\r\n\r\n // Inverse Trigonometric functions\r\n public asin(val: number) {\r\n return this.toDegrees(Math.asin(val));\r\n }\r\n\r\n public acos(val: number) {\r\n return this.toDegrees(Math.acos(val));\r\n }\r\n\r\n public acsc(val: number) {\r\n return this.toDegrees(Math.asin(1 / val));\r\n }\r\n\r\n public asec(val: number) {\r\n return this.toDegrees(Math.acos(1 / val));\r\n }\r\n\r\n // Helpers\r\n\r\n public toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n public toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Private constructor\r\n\r\n private constructor() {\r\n void this.setMaxFramesPerSecond(24);\r\n\r\n // Events\r\n\r\n // Mouse\r\n penCanvas.addEventListener('mousemove', e => {\r\n this.mouseX = e.clientX - penCanvas.offsetLeft - penCanvas.width / 2;\r\n this.mouseY = -(e.clientY - penCanvas.offsetTop - penCanvas.height / 2);\r\n });\r\n penCanvas.addEventListener('mousedown', e => {\r\n this.mouseDown = true;\r\n });\r\n penCanvas.addEventListener('mouseup', e => {\r\n this.mouseDown = false;\r\n });\r\n penCanvas.addEventListener('click', e => {\r\n this.mouseClicked = true;\r\n setTimeout(() => this.mouseClicked = false, 0);\r\n });\r\n\r\n // Keys\r\n addEventListener('keydown', e => {\r\n if (e.repeat) return;\r\n this.keysPressed.add(e.key);\r\n });\r\n\r\n addEventListener('keyup', e => {\r\n this.keysPressed.delete(e.key);\r\n });\r\n }\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface RectangleOptions extends SpriteOptions {\r\n width?: number;\r\n height?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Rectangle extends Sprite {\r\n\r\n public discriminant = 'rectangle';\r\n\r\n public width: number;\r\n public height: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.width, this.height),\r\n height: Math.hypot(this.width, this.height)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RectangleOptions) {\r\n super(options);\r\n this.width = options?.width ?? 50;\r\n this.height = options?.height ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface SquareOptions extends SpriteOptions {\r\n sideLength?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Square extends Sprite {\r\n\r\n public discriminant = 'square';\r\n\r\n public sideLength: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.sideLength, this.sideLength),\r\n height: Math.hypot(this.sideLength, this.sideLength)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.sideLength / 2,\r\n -this.sideLength / 2,\r\n this.sideLength,\r\n this.sideLength\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSideLength(sideLength: number) {\r\n this.sideLength = sideLength;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: SquareOptions) {\r\n super(options);\r\n this.sideLength = options?.sideLength ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface OvalOptions extends SpriteOptions {\r\n radX?: number;\r\n radY?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Oval extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radX: number;\r\n public radY: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.radX * 2, this.radY * 2),\r\n height: Math.hypot(this.radX * 2, this.radY * 2)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radX,\r\n this.radY,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadX(radX: number) {\r\n this.radX = radX;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadY(radY: number) {\r\n this.radY = radY;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: OvalOptions) {\r\n super(options);\r\n this.radX = options?.radX ?? 25;\r\n this.radY = options?.radY ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface CircleOptions extends SpriteOptions {\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Circle extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radius,\r\n this.radius,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CircleOptions) {\r\n super(options);\r\n this.radius = options?.radius ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface RegularPolygonOptions extends SpriteOptions {\r\n sides?: number;\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n}\r\n\r\nexport default class RegularPolygon extends Sprite {\r\n\r\n public discriminant = 'regularpolygon';\r\n\r\n public sides: number;\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const step = (2 * Math.PI) / this.sides;\r\n path.moveTo(this.radius, 0);\r\n for (let i = 1; i < this.sides; i++) {\r\n path.lineTo(this.radius * Math.cos(step * i), this.radius * Math.sin(step * i));\r\n }\r\n path.closePath();\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n\r\n c.translate(cX, cY);\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSides(sides: number) {\r\n this.sides = sides;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RegularPolygonOptions) {\r\n super(options);\r\n this.sides = options?.sides ?? 5;\r\n this.radius = options?.radius ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface PenOptions extends SpriteOptions {\r\n drawing?: boolean;\r\n size?: number;\r\n color?: string;\r\n}\r\n\r\nexport default class Pen extends Sprite {\r\n\r\n public discriminant = 'pen';\r\n\r\n public drawing: boolean;\r\n public size: number;\r\n public color: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.size,\r\n height: this.size\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n return new Path2D();\r\n }\r\n public draw() {}\r\n\r\n public up() {\r\n this.drawing = false;\r\n }\r\n\r\n public down() {\r\n this.drawing = true;\r\n }\r\n\r\n public stamp(sprite: Sprite) {\r\n sprite.draw(true);\r\n }\r\n\r\n public eraseAll() {\r\n penCtx.clearRect(0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n public dot() {\r\n penCtx.fillStyle = this.color;\r\n penCtx.fillRect(\r\n this.x - this.size / 2 + canvas.width / 2,\r\n -this.y - this.size / 2 + canvas.height / 2,\r\n this.size,\r\n this.size\r\n );\r\n }\r\n\r\n private drawLine(lastX: number, lastY: number) {\r\n penCtx.beginPath();\r\n\r\n penCtx.moveTo(lastX + canvas.width / 2, -lastY + canvas.height / 2);\r\n penCtx.lineTo(this.x + canvas.width / 2, -this.y + canvas.height / 2);\r\n\r\n penCtx.lineWidth = this.size;\r\n penCtx.strokeStyle = this.color;\r\n penCtx.stroke();\r\n }\r\n\r\n // Overriding methods to include drawing\r\n\r\n public override move(steps: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setX(x: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setY(y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override goTo(x: number, y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeX(dX: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += dX;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeY(dY: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y += dY;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: PenOptions) {\r\n super(options);\r\n this.drawing = options?.drawing ?? false;\r\n this.size = options?.size ?? 5;\r\n this.color = options?.color ?? 'black';\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport type CanvasTextAlign =\r\n | 'left'\r\n | 'right'\r\n | 'center'\r\n | 'start'\r\n | 'end';\r\n\r\nexport type CanvasTextBaseline =\r\n | 'top'\r\n | 'hanging'\r\n | 'middle'\r\n | 'alphabetic'\r\n | 'ideographic'\r\n | 'bottom';\r\n\r\nexport interface TextOptions extends SpriteOptions {\r\n content?: string;\r\n color?: string;\r\n fontFamily?: string;\r\n fontSize?: number;\r\n align?: CanvasTextAlign;\r\n baseline?: CanvasTextBaseline;\r\n}\r\n\r\nexport default class Text extends Sprite {\r\n\r\n public discriminant = 'text';\r\n\r\n public content: string;\r\n public color: string;\r\n public fontFamily: string;\r\n public fontSize: number;\r\n public align: CanvasTextAlign;\r\n public baseline: CanvasTextBaseline;\r\n\r\n private font: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width, height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n ctx.save();\r\n \r\n ctx.font = this.font;\r\n\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n ctx.restore();\r\n\r\n path.rect(-width / 2, -height / 2, width, height);\r\n\r\n return path\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.font = this.font;\r\n c.fillStyle = this.color;\r\n c.textAlign = this.align;\r\n c.textBaseline = this.baseline;\r\n\r\n c.fillText(this.content, 0, 0);\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setContent(content: string) {\r\n this.content = content;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n public setFontSize(fontSize: number) {\r\n this.fontSize = fontSize;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setFontFamily(fontFamily: string) {\r\n this.fontFamily = fontFamily;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAlign(align: CanvasTextAlign) {\r\n this.align = align;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setBaseline(baseline: CanvasTextBaseline) {\r\n this.baseline = baseline;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: TextOptions) {\r\n super(options);\r\n\r\n this.content = options?.content ?? '';\r\n this.color = options?.color ?? 'black';\r\n this.fontFamily = options?.fontFamily ?? 'Arial';\r\n this.fontSize = options?.fontSize ?? 16;\r\n this.align = options?.align ?? 'center';\r\n this.baseline = options?.baseline ?? 'middle';\r\n\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n\r\n this.draw();\r\n }\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface ImageSpriteOptions extends SpriteOptions {\r\n src?: string;\r\n width: number;\r\n height: number;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class ImageSprite extends Sprite {\r\n\r\n public discriminant = 'imagesprite';\r\n\r\n public src: string;\r\n public width: number;\r\n public height: number;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n protected img: HTMLImageElement;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.width,\r\n height: this.height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.drawImage(\r\n this.img,\r\n 0, 0,\r\n this.img.width,\r\n this.img.height,\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width, this.height\r\n );\r\n if (this.outlineWidth)\r\n c.stroke(this.getCachedPath());\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setSrc(src: string) {\r\n this.src = src;\r\n this.refresh();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: ImageSpriteOptions) {\r\n super(options);\r\n\r\n this.src = options?.src ?? '';\r\n this.img = new Image();\r\n this.img.src = this.src;\r\n\r\n this.width = options?.width ?? this.img.width;\r\n this.height = options?.height ?? this.img.height;\r\n\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n \r\n this.draw();\r\n }\r\n}"],"mappings":"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","names":["index_exports","__export","Circle","Engine","ImageSprite","Oval","Pen","Rectangle","RegularPolygon","Sprite","Square","Text","canvas","ctx","index_default","setAspectRatio","setScale","__toCommonJS","canvas","ctx","penCanvas","penCtx","ratio","scale","setScale","newScale","setAspectRatio","newAspectRatio","Sprite","_Sprite","Engine","options","sprite","bBox1","bBox2","b1Left","b1Top","b1Right","b1Bottom","b2Left","b2Top","b2Right","b2Bottom","xMin","yMin","xMax","yMax","width","height","ctx","img1","img2","i","deg","rad","steps","dir","x","y","dX","dY","layer","dL","Engine","_Engine","scene","loop","sprite","layer","targetIndex","s","maxFPS","frameInterval","accumulator","tick","currentTime","deltaTime","ctx","canvas","ms","resolve","conditionGetter","check","mouseX","mouseY","canvasMouseX","canvasMouseY","localX","localY","angle","rotatedX","rotatedY","key","src","audio","sound","min","max","deg","val","rad","penCanvas","e","Rectangle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","width","height","color","options","Square","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","sideLength","color","options","Oval","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radX","radY","color","options","Circle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","color","options","RegularPolygon","Sprite","path","step","i","stamping","c","penCtx","ctx","cX","canvas","cY","sides","radius","color","options","Pen","Sprite","sprite","penCtx","canvas","lastX","lastY","steps","x","y","dX","dY","options","Text","Sprite","metrics","ctx","width","height","path","stamping","c","penCtx","cX","canvas","cY","content","color","fontSize","fontFamily","align","baseline","options","ImageSprite","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","src","width","height","options","TScratch","Engine","Sprite","Rectangle","Square","Oval","Circle","RegularPolygon","Pen","Text","ImageSprite","setScale","setAspectRatio","canvas","ctx","index_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/canvas.ts","../src/Sprite.ts","../src/Engine.ts","../src/sprites/Rectangle.ts","../src/sprites/Square.ts","../src/sprites/Oval.ts","../src/sprites/Circle.ts","../src/sprites/Arc.ts","../src/sprites/RegularPolygon.ts","../src/sprites/CustomPolygon.ts","../src/sprites/Pen.ts","../src/sprites/Text.ts","../src/sprites/ImageSprite.ts"],"sourcesContent":["import Engine from './Engine.ts';\r\nimport Sprite, { type SpriteOptions } from './Sprite.ts';\r\nimport { setScale, setAspectRatio, canvas, ctx } from './canvas.ts';\r\n\r\nimport Rectangle, { type RectangleOptions } from './sprites/Rectangle.ts';\r\nimport Square, { type SquareOptions } from './sprites/Square.ts';\r\nimport Oval, { type OvalOptions } from './sprites/Oval.ts';\r\nimport Circle, { type CircleOptions } from './sprites/Circle.ts';\r\nimport Arc, { type ArcOptions } from './sprites/Arc.ts';\r\nimport RegularPolygon, { type RegularPolygonOptions } from './sprites/RegularPolygon.ts';\r\nimport CustomPolygon, { type CustomPolygonOptions } from './sprites/CustomPolygon.ts';\r\nimport Pen, { type PenOptions } from './sprites/Pen.ts';\r\nimport Text, { type TextOptions, type CanvasTextAlign, type CanvasTextBaseline } from './sprites/Text.ts';\r\nimport ImageSprite, { type ImageSpriteOptions } from './sprites/ImageSprite.ts';\r\n\r\nimport type { Vec2, Vec3, Vec4 } from './types/Vectors.ts';\r\n\r\nconst TScratch = {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n Arc,\r\n RegularPolygon,\r\n CustomPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};\r\n\r\nexport default TScratch;\r\nexport {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n Arc,\r\n RegularPolygon,\r\n CustomPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Options\r\n type SpriteOptions,\r\n type RectangleOptions,\r\n type SquareOptions,\r\n type OvalOptions,\r\n type CircleOptions,\r\n type ArcOptions,\r\n type RegularPolygonOptions,\r\n type CustomPolygonOptions,\r\n type PenOptions,\r\n type TextOptions,\r\n type ImageSpriteOptions,\r\n\r\n // Other types\r\n type CanvasTextAlign,\r\n type CanvasTextBaseline,\r\n type Vec2,\r\n type Vec3,\r\n type Vec4,\r\n \r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};","export const canvas = document.getElementById('game-window') as HTMLCanvasElement || document.createElement('canvas'); // For testing\r\nexport const ctx = canvas.getContext('2d')!;\r\n\r\nexport const penCanvas = document.createElement('canvas');\r\nexport const penCtx = penCanvas.getContext('2d')!;\r\npenCanvas.id = 'pen-canvas';\r\n\r\nlet ratio: number = 16 / 9;\r\nlet scale: number;\r\n\r\nexport function setScale(newScale: number) {\r\n scale = newScale;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\nexport function setAspectRatio(newAspectRatio: number) {\r\n ratio = newAspectRatio;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\ncanvas.parentElement?.insertBefore(penCanvas, canvas);\r\n\r\nsetScale(500);","import Engine from './Engine.ts';\r\n\r\nexport interface BoundingBox {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface SpriteOptions {\r\n x?: number;\r\n y?: number;\r\n dir?: number;\r\n scene?: string;\r\n hidden?: boolean;\r\n layer?: number;\r\n}\r\n\r\nexport default abstract class Sprite {\r\n\r\n public x: number;\r\n public y: number;\r\n public dir: number;\r\n public scene: string;\r\n public hidden: boolean;\r\n public layer: number;\r\n\r\n private cachedPath: Path2D | null = null;\r\n private pathDirty: boolean = true;\r\n\r\n // Reusable collision detection canvas\r\n private static collisionCanvas: HTMLCanvasElement | null = null;\r\n private static collisionCtx: CanvasRenderingContext2D | null = null;\r\n\r\n // Rendering\r\n\r\n public abstract getBoundingBox(): BoundingBox;\r\n public abstract getPath(): Path2D;\r\n public abstract draw(stamping?: boolean): void;\r\n\r\n protected refresh() {\r\n Engine.init().refresh();\r\n }\r\n\r\n protected invalidatePath() {\r\n this.pathDirty = true;\r\n this.cachedPath = null;\r\n }\r\n\r\n protected getCachedPath(): Path2D {\r\n if (this.pathDirty || !this.cachedPath) {\r\n this.cachedPath = this.getPath();\r\n this.pathDirty = false;\r\n }\r\n return this.cachedPath;\r\n }\r\n\r\n constructor(options?: SpriteOptions) {\r\n this.x = options?.x ?? 0;\r\n this.y = options?.y ?? 0;\r\n this.dir = options?.dir ?? 0;\r\n this.scene = options?.scene ?? 'main';\r\n this.hidden = options?.hidden ?? false;\r\n this.layer = options?.layer ?? 0;\r\n Engine.init().addSprite(this);\r\n }\r\n\r\n // Sensing\r\n\r\n public touching(sprite: Sprite): boolean {\r\n\r\n // AABB (bounding boxes)\r\n const bBox1 = this.getBoundingBox();\r\n const bBox2 = sprite.getBoundingBox();\r\n\r\n const aabbOverlap =\r\n Math.abs(bBox1.x - bBox2.x) < (bBox1.width + bBox2.width) / 2 &&\r\n Math.abs(bBox1.y - bBox2.y) < (bBox1.height + bBox2.height) / 2;\r\n\r\n if (!aabbOverlap) return false;\r\n\r\n // Image data (pixel perfect)\r\n\r\n // Compute intersection bounding box\r\n const b1Left = bBox1.x - bBox1.width / 2;\r\n const b1Top = bBox1.y + bBox1.height / 2;\r\n const b1Right = bBox1.x + bBox1.width / 2;\r\n const b1Bottom = bBox1.y - bBox1.height / 2;\r\n\r\n const b2Left = bBox2.x - bBox2.width / 2;\r\n const b2Top = bBox2.y + bBox2.height / 2;\r\n const b2Right = bBox2.x + bBox2.width / 2;\r\n const b2Bottom = bBox2.y - bBox2.height / 2;\r\n\r\n const xMin = Math.max(b1Left, b2Left);\r\n const yMin = Math.min(b1Bottom, b2Bottom);\r\n const xMax = Math.min(b1Right, b2Right);\r\n const yMax = Math.max(b1Top, b2Top);\r\n\r\n const width = xMax - xMin;\r\n const height = yMax - yMin;\r\n\r\n if (width <= 1 || height <= 1) return false;\r\n\r\n // Reuse or create offscreen canvas for collision detection\r\n if (!Sprite.collisionCanvas) {\r\n Sprite.collisionCanvas = document.createElement('canvas');\r\n Sprite.collisionCtx = Sprite.collisionCanvas.getContext('2d', { willReadFrequently: true })!;\r\n }\r\n\r\n // Resize if needed\r\n if (Sprite.collisionCanvas.width < width || Sprite.collisionCanvas.height < height) {\r\n Sprite.collisionCanvas.width = Math.max(width, Sprite.collisionCanvas.width);\r\n Sprite.collisionCanvas.height = Math.max(height, Sprite.collisionCanvas.height);\r\n }\r\n\r\n const ctx = Sprite.collisionCtx!;\r\n ctx.clearRect(0, 0, width, height);\r\n\r\n // Draw first sprite\r\n ctx.save();\r\n ctx.translate(this.x - xMin, height - this.y + yMin);\r\n ctx.rotate(this.toRadians(this.dir));\r\n ctx.fillStyle = 'red';\r\n ctx.fill(this.getCachedPath());\r\n ctx.restore();\r\n const img1 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Draw second sprite\r\n ctx.clearRect(0, 0, width, height);\r\n ctx.save();\r\n ctx.translate(sprite.x - xMin, height - sprite.y + yMin);\r\n ctx.rotate(this.toRadians(sprite.dir));\r\n ctx.fillStyle = 'blue';\r\n ctx.fill(sprite.getCachedPath());\r\n ctx.restore();\r\n const img2 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Check for overlapping non-transparent pixels\r\n for (let i = 3; i < img1.length; i += 4) // alpha channel\r\n if (img1[i]! > 0 && img2[i]! > 0) return true;\r\n\r\n return false;\r\n }\r\n\r\n // Helpers\r\n\r\n protected toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n protected toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Methods\r\n\r\n // Motion\r\n public move(steps: number) {\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n this.refresh();\r\n }\r\n\r\n public turn(deg: number) {\r\n this.dir += deg;\r\n this.refresh();\r\n }\r\n\r\n public point(dir: number) {\r\n this.dir = dir;\r\n this.refresh();\r\n }\r\n\r\n public pointTowards(x: number, y: number) {\r\n this.dir = 90 - this.toDegrees(Math.atan2(y, x));\r\n this.refresh();\r\n }\r\n\r\n public setX(x: number) {\r\n this.x = x;\r\n this.refresh();\r\n }\r\n\r\n public setY(y: number) {\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public goTo(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public changeX(dX: number) {\r\n this.x += dX;\r\n this.refresh();\r\n }\r\n\r\n public changeY(dY: number) {\r\n this.y += dY;\r\n this.refresh();\r\n }\r\n\r\n // Looks\r\n\r\n public show() {\r\n this.hidden = false;\r\n this.refresh();\r\n }\r\n\r\n public hide() {\r\n this.hidden = true;\r\n this.refresh();\r\n }\r\n\r\n public goToLayer(layer: number) {\r\n this.layer = layer;\r\n this.refresh();\r\n }\r\n\r\n public changeLayer(dL: number) {\r\n this.layer += dL;\r\n this.refresh();\r\n }\r\n}","import { canvas, ctx, penCanvas } from './canvas.ts';\r\nimport Sprite from './Sprite.ts';\r\nimport type { Vec2, Vec3, Vec4 } from './types/Vectors.ts';\r\n\r\ntype GameLoop = (() => any) | (() => Promise<any>);\r\n\r\ntype SceneMap = {\r\n [scene: string]: {\r\n sprites: Sprite[];\r\n loop: GameLoop | null;\r\n };\r\n};\r\n\r\nexport default class Engine {\r\n\r\n private static instance: Engine;\r\n\r\n private loopRunning: boolean = false;\r\n public gameLoop: GameLoop | null = null;\r\n\r\n public maxFPS: number = 24;\r\n public deltaTime: number = 1 / this.maxFPS;\r\n private lastFrame: number = performance.now();\r\n private refreshScheduled: boolean = false;\r\n private animationFrameId: number | null = null;\r\n\r\n public sounds: HTMLAudioElement[] = [];\r\n\r\n public mouseX: number = 0;\r\n public mouseY: number = 0;\r\n\r\n public mouseDown: boolean = false;\r\n public mouseClicked: boolean = false;\r\n\r\n private keysPressed: Set<string> = new Set<string>();\r\n\r\n public currentScene: string = 'main';\r\n public sceneMap: SceneMap = {};\r\n\r\n // Singleton initialization\r\n\r\n public static init() {\r\n if (!this.instance)\r\n this.instance = new Engine();\r\n\r\n return this.instance;\r\n }\r\n\r\n // Change the scene\r\n\r\n public changeScene(scene: string) {\r\n if (!this.sceneMap[scene])\r\n this.sceneMap[scene] = { sprites: [], loop: null };\r\n\r\n this.loopRunning = false;\r\n this.currentScene = scene;\r\n this.gameLoop = this.sceneMap[scene].loop;\r\n this.setMaxFramesPerSecond(this.maxFPS); // Update the interval function\r\n }\r\n\r\n // Loops\r\n\r\n public setLoop(scene: string, loop: GameLoop) {\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [], loop };\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].loop = loop;\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n }\r\n\r\n public pauseLoop() {\r\n this.loopRunning = false;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n }\r\n\r\n public resumeLoop() {\r\n this.loopRunning = true;\r\n void this.setMaxFramesPerSecond(this.maxFPS);\r\n }\r\n\r\n // Internal\r\n\r\n public addSprite(sprite: Sprite) {\r\n const { scene, layer } = sprite;\r\n\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [sprite], loop: null };\r\n return;\r\n }\r\n\r\n let targetIndex = this.sceneMap[scene].sprites.findIndex(s => s.layer > layer);\r\n if (targetIndex === -1) {\r\n this.sceneMap[scene].sprites.push(sprite);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].sprites.splice(targetIndex, 0, sprite);\r\n this.refresh();\r\n }\r\n\r\n public removeSprite(sprite: Sprite) {\r\n const { scene } = sprite;\r\n\r\n if (!this.sceneMap[scene]) return;\r\n\r\n this.sceneMap[scene].sprites = this.sceneMap[scene].sprites.filter(s => s !== sprite);\r\n this.refresh();\r\n }\r\n\r\n public async setMaxFramesPerSecond(maxFPS: number) {\r\n this.maxFPS = maxFPS;\r\n\r\n let loop = this.gameLoop;\r\n if (!loop) return;\r\n\r\n // Cancel existing animation frame if any\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n\r\n this.loopRunning = true;\r\n const frameInterval = 1000 / maxFPS;\r\n let accumulator = 0;\r\n\r\n const tick = async (currentTime: number) => {\r\n if (!this.loopRunning) return;\r\n\r\n const deltaTime = currentTime - this.lastFrame;\r\n this.lastFrame = currentTime;\r\n accumulator += deltaTime;\r\n\r\n // Fixed timestep: only run loop when enough time has passed\r\n if (accumulator >= frameInterval) {\r\n this.deltaTime = accumulator / 1000;\r\n accumulator = accumulator % frameInterval;\r\n\r\n if (loop) await loop();\r\n }\r\n\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n };\r\n\r\n this.lastFrame = performance.now();\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n }\r\n\r\n public refresh() {\r\n if (this.refreshScheduled) return;\r\n this.refreshScheduled = true;\r\n\r\n requestAnimationFrame(() => {\r\n this.refreshScheduled = false;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n const sprites = [\r\n ...(this.sceneMap[this.currentScene]?.sprites ?? []),\r\n ...(this.sceneMap['*']?.sprites ?? [])\r\n ];\r\n sprites.forEach(sprite => {\r\n if (!sprite.hidden)\r\n sprite.draw();\r\n });\r\n });\r\n }\r\n\r\n // Wait functions\r\n\r\n public async wait(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n\r\n public async waitUntil(conditionGetter: () => boolean): Promise<void> {\r\n return new Promise(resolve => {\r\n const check = () => {\r\n if (conditionGetter()) resolve();\r\n else setTimeout(check, 1000 / this.maxFPS);\r\n }\r\n check();\r\n });\r\n }\r\n\r\n // Events\r\n\r\n public hovering(sprite: Sprite) {\r\n const { mouseX, mouseY } = this;\r\n\r\n const canvasMouseX = mouseX + canvas.width / 2;\r\n const canvasMouseY = canvas.height / 2 - mouseY;\r\n\r\n // Mouse relative to sprite center\r\n const localX = canvasMouseX - (sprite.x + canvas.width / 2);\r\n const localY = canvasMouseY - (canvas.height / 2 - sprite.y);\r\n\r\n // Rotate mouse point by -dir to align with the path's local coordinates\r\n const angle = -this.toRadians(sprite.dir);\r\n const rotatedX = localX * Math.cos(angle) - localY * Math.sin(angle);\r\n const rotatedY = localX * Math.sin(angle) + localY * Math.cos(angle);\r\n\r\n return ctx.isPointInPath(sprite.getPath(), rotatedX, rotatedY);\r\n }\r\n\r\n public keyPressed(key: string) {\r\n return this.keysPressed.has(key);\r\n }\r\n\r\n // Sound\r\n\r\n public playSound(src: string) {\r\n const audio = new Audio(src);\r\n this.sounds.push(audio);\r\n\r\n audio.play();\r\n\r\n return audio;\r\n }\r\n\r\n public stopSound(sound: HTMLAudioElement) {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n this.sounds = this.sounds.filter(s => s !== sound);\r\n }\r\n\r\n public stopAllSounds() {\r\n this.sounds.forEach(sound => {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n });\r\n this.sounds = [];\r\n }\r\n\r\n // Math\r\n\r\n public pickRandom(min: number, max: number) {\r\n if (min > max)\r\n [min, max] = [max, min];\r\n return Math.floor(Math.random() * (max - min + 1) + min);\r\n }\r\n\r\n public dotProduct(vectors: [Vec2, Vec2] | [Vec3, Vec3] | [Vec4, Vec4]) {\r\n const [a, b] = vectors;\r\n\r\n switch (a.length) {\r\n case 2: return a[0] * b[0] + a[1] * b[1];\r\n case 3: return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]!;\r\n case 4: return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]! + a[3] * b[3]!; // TypeScript doesn't narrow down the types on b\r\n }\r\n }\r\n\r\n // Trigonometric functions\r\n public sin(deg: number) {\r\n return Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public cos(deg: number) {\r\n return Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public tan(deg: number) {\r\n return Math.tan(this.toRadians(deg));\r\n }\r\n\r\n public csc(deg: number) {\r\n return 1 / Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public sec(deg: number) {\r\n return 1 / Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public cot(deg: number) {\r\n return 1 / Math.tan(this.toRadians(deg));\r\n }\r\n\r\n // Inverse Trigonometric functions\r\n public asin(val: number) {\r\n return this.toDegrees(Math.asin(val));\r\n }\r\n\r\n public acos(val: number) {\r\n return this.toDegrees(Math.acos(val));\r\n }\r\n\r\n public acsc(val: number) {\r\n return this.toDegrees(Math.asin(1 / val));\r\n }\r\n\r\n public asec(val: number) {\r\n return this.toDegrees(Math.acos(1 / val));\r\n }\r\n\r\n // Helpers\r\n\r\n public toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n public toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Private constructor\r\n\r\n private constructor() {\r\n void this.setMaxFramesPerSecond(24);\r\n\r\n // Events\r\n\r\n // Mouse\r\n penCanvas.addEventListener('mousemove', e => {\r\n this.mouseX = e.clientX - penCanvas.offsetLeft - penCanvas.width / 2;\r\n this.mouseY = -(e.clientY - penCanvas.offsetTop - penCanvas.height / 2);\r\n });\r\n penCanvas.addEventListener('mousedown', e => {\r\n this.mouseDown = true;\r\n });\r\n penCanvas.addEventListener('mouseup', e => {\r\n this.mouseDown = false;\r\n });\r\n penCanvas.addEventListener('click', e => {\r\n this.mouseClicked = true;\r\n setTimeout(() => this.mouseClicked = false, 0);\r\n });\r\n\r\n // Keys\r\n addEventListener('keydown', e => {\r\n if (e.repeat) return;\r\n this.keysPressed.add(e.key);\r\n });\r\n\r\n addEventListener('keyup', e => {\r\n this.keysPressed.delete(e.key);\r\n });\r\n }\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface RectangleOptions extends SpriteOptions {\r\n width?: number;\r\n height?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Rectangle extends Sprite {\r\n\r\n public discriminant = 'rectangle';\r\n\r\n public width: number;\r\n public height: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.width, this.height),\r\n height: Math.hypot(this.width, this.height)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RectangleOptions) {\r\n super(options);\r\n this.width = options?.width ?? 50;\r\n this.height = options?.height ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface SquareOptions extends SpriteOptions {\r\n sideLength?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Square extends Sprite {\r\n\r\n public discriminant = 'square';\r\n\r\n public sideLength: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.sideLength, this.sideLength),\r\n height: Math.hypot(this.sideLength, this.sideLength)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.sideLength / 2,\r\n -this.sideLength / 2,\r\n this.sideLength,\r\n this.sideLength\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSideLength(sideLength: number) {\r\n this.sideLength = sideLength;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: SquareOptions) {\r\n super(options);\r\n this.sideLength = options?.sideLength ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface OvalOptions extends SpriteOptions {\r\n radX?: number;\r\n radY?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Oval extends Sprite {\r\n\r\n public discriminant = 'oval';\r\n\r\n public radX: number;\r\n public radY: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.radX * 2, this.radY * 2),\r\n height: Math.hypot(this.radX * 2, this.radY * 2)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radX,\r\n this.radY,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadX(radX: number) {\r\n this.radX = radX;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadY(radY: number) {\r\n this.radY = radY;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: OvalOptions) {\r\n super(options);\r\n this.radX = options?.radX ?? 25;\r\n this.radY = options?.radY ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface CircleOptions extends SpriteOptions {\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Circle extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radius,\r\n this.radius,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CircleOptions) {\r\n super(options);\r\n this.radius = options?.radius ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface ArcOptions extends SpriteOptions {\r\n radius?: number;\r\n angle?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Arc extends Sprite {\r\n\r\n public discriminant = 'arc';\r\n\r\n public radius: number;\r\n public angle: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.arc(\r\n 0, 0,\r\n this.radius,\r\n this.toRadians(this.angle / 2 - 90),\r\n this.toRadians(-this.angle / 2 - 90)\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAngle(angle: number) {\r\n this.angle = angle;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: ArcOptions) {\r\n super(options);\r\n\r\n this.radius = options?.radius ?? 25;\r\n this.angle = options?.angle ?? 270;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface RegularPolygonOptions extends SpriteOptions {\r\n sides?: number;\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n}\r\n\r\nexport default class RegularPolygon extends Sprite {\r\n\r\n public discriminant = 'regularpolygon';\r\n\r\n public sides: number;\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const step = (2 * Math.PI) / this.sides;\r\n path.moveTo(this.radius, 0);\r\n for (let i = 1; i < this.sides; i++) {\r\n path.lineTo(this.radius * Math.cos(step * i), this.radius * Math.sin(step * i));\r\n }\r\n path.closePath();\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n\r\n c.translate(cX, cY);\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSides(sides: number) {\r\n this.sides = sides;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RegularPolygonOptions) {\r\n super(options);\r\n this.sides = options?.sides ?? 5;\r\n this.radius = options?.radius ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport type { Vec2 } from '../types/Vectors.ts';\r\n\r\nexport interface CustomPolygonOptions extends SpriteOptions {\r\n vertices?: Vec2[];\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class CustomPolygon extends Sprite {\r\n\r\n public discriminant = 'custompolygon';\r\n\r\n public vertices: Vec2[];\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n\r\n let furthestVertexSize = 0;\r\n\r\n for (const v of this.vertices) {\r\n\r\n const size = Math.hypot(v[0], v[1]);\r\n\r\n if (size > furthestVertexSize)\r\n furthestVertexSize = size;\r\n }\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: furthestVertexSize,\r\n height: furthestVertexSize\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const vertices = this.vertices;\r\n\r\n if (vertices.length < 2) return path;\r\n\r\n path.moveTo(vertices[0]![0], vertices[0]![1]);\r\n\r\n for (let i = 1; i < vertices.length; i++)\r\n path.lineTo(vertices[i]![0], vertices[i]![1]);\r\n\r\n path.closePath();\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setVertices(vertices: Vec2[]) {\r\n this.vertices = vertices;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CustomPolygonOptions) {\r\n super(options);\r\n\r\n this.vertices = options?.vertices ?? [];\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface PenOptions extends SpriteOptions {\r\n drawing?: boolean;\r\n size?: number;\r\n color?: string;\r\n}\r\n\r\nexport default class Pen extends Sprite {\r\n\r\n public discriminant = 'pen';\r\n\r\n public drawing: boolean;\r\n public size: number;\r\n public color: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.size,\r\n height: this.size\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n return new Path2D();\r\n }\r\n public draw() {}\r\n\r\n public up() {\r\n this.drawing = false;\r\n }\r\n\r\n public down() {\r\n this.drawing = true;\r\n }\r\n\r\n public stamp(sprite: Sprite) {\r\n sprite.draw(true);\r\n }\r\n\r\n public eraseAll() {\r\n penCtx.clearRect(0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n public dot() {\r\n penCtx.fillStyle = this.color;\r\n penCtx.fillRect(\r\n this.x - this.size / 2 + canvas.width / 2,\r\n -this.y - this.size / 2 + canvas.height / 2,\r\n this.size,\r\n this.size\r\n );\r\n }\r\n\r\n private drawLine(lastX: number, lastY: number) {\r\n penCtx.beginPath();\r\n\r\n penCtx.moveTo(lastX + canvas.width / 2, -lastY + canvas.height / 2);\r\n penCtx.lineTo(this.x + canvas.width / 2, -this.y + canvas.height / 2);\r\n\r\n penCtx.lineWidth = this.size;\r\n penCtx.strokeStyle = this.color;\r\n penCtx.stroke();\r\n }\r\n\r\n // Overriding methods to include drawing\r\n\r\n public override move(steps: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setX(x: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setY(y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override goTo(x: number, y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeX(dX: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += dX;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeY(dY: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y += dY;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: PenOptions) {\r\n super(options);\r\n this.drawing = options?.drawing ?? false;\r\n this.size = options?.size ?? 5;\r\n this.color = options?.color ?? 'black';\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport type CanvasTextAlign =\r\n | 'left'\r\n | 'right'\r\n | 'center'\r\n | 'start'\r\n | 'end';\r\n\r\nexport type CanvasTextBaseline =\r\n | 'top'\r\n | 'hanging'\r\n | 'middle'\r\n | 'alphabetic'\r\n | 'ideographic'\r\n | 'bottom';\r\n\r\nexport interface TextOptions extends SpriteOptions {\r\n content?: string;\r\n color?: string;\r\n fontFamily?: string;\r\n fontSize?: number;\r\n align?: CanvasTextAlign;\r\n baseline?: CanvasTextBaseline;\r\n}\r\n\r\nexport default class Text extends Sprite {\r\n\r\n public discriminant = 'text';\r\n\r\n public content: string;\r\n public color: string;\r\n public fontFamily: string;\r\n public fontSize: number;\r\n public align: CanvasTextAlign;\r\n public baseline: CanvasTextBaseline;\r\n\r\n private font: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width, height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n ctx.save();\r\n \r\n ctx.font = this.font;\r\n\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n ctx.restore();\r\n\r\n path.rect(-width / 2, -height / 2, width, height);\r\n\r\n return path\r\n }\r\n\r\n public override draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.font = this.font;\r\n c.fillStyle = this.color;\r\n c.textAlign = this.align;\r\n c.textBaseline = this.baseline;\r\n\r\n c.fillText(this.content, 0, 0);\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setContent(content: string) {\r\n this.content = content;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n public setFontSize(fontSize: number) {\r\n this.fontSize = fontSize;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setFontFamily(fontFamily: string) {\r\n this.fontFamily = fontFamily;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAlign(align: CanvasTextAlign) {\r\n this.align = align;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setBaseline(baseline: CanvasTextBaseline) {\r\n this.baseline = baseline;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: TextOptions) {\r\n super(options);\r\n\r\n this.content = options?.content ?? '';\r\n this.color = options?.color ?? 'black';\r\n this.fontFamily = options?.fontFamily ?? 'Arial';\r\n this.fontSize = options?.fontSize ?? 16;\r\n this.align = options?.align ?? 'center';\r\n this.baseline = options?.baseline ?? 'middle';\r\n\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n\r\n this.draw();\r\n }\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface ImageSpriteOptions extends SpriteOptions {\r\n src?: string;\r\n width: number;\r\n height: number;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class ImageSprite extends Sprite {\r\n\r\n public discriminant = 'imagesprite';\r\n\r\n public src: string;\r\n public width: number;\r\n public height: number;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n protected img: HTMLImageElement;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.width,\r\n height: this.height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public override draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.drawImage(\r\n this.img,\r\n 0, 0,\r\n this.img.width,\r\n this.img.height,\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width, this.height\r\n );\r\n if (this.outlineWidth)\r\n c.stroke(this.getCachedPath());\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setSrc(src: string) {\r\n this.src = src;\r\n this.refresh();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: ImageSpriteOptions) {\r\n super(options);\r\n\r\n this.src = options?.src ?? '';\r\n this.img = new Image();\r\n this.img.src = this.src;\r\n\r\n this.width = options?.width ?? this.img.width;\r\n this.height = options?.height ?? this.img.height;\r\n\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n \r\n this.draw();\r\n }\r\n}"],"mappings":"yaAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,SAAAE,EAAA,WAAAC,EAAA,kBAAAC,EAAA,WAAAC,EAAA,gBAAAC,EAAA,SAAAC,EAAA,QAAAC,EAAA,cAAAC,EAAA,mBAAAC,EAAA,WAAAC,EAAA,WAAAC,EAAA,SAAAC,EAAA,WAAAC,EAAA,QAAAC,EAAA,YAAAC,EAAA,mBAAAC,EAAA,aAAAC,IAAA,eAAAC,EAAAnB,GCAO,IAAMoB,EAAS,SAAS,eAAe,aAAa,GAA0B,SAAS,cAAc,QAAQ,EACvGC,EAAMD,EAAO,WAAW,IAAI,EAE5BE,EAAY,SAAS,cAAc,QAAQ,EAC3CC,EAASD,EAAU,WAAW,IAAI,EAC/CA,EAAU,GAAK,aAEf,IAAIE,EAAgB,GAAK,EACrBC,EAEG,SAASC,EAASC,EAAkB,CACvCF,EAAQE,EAERP,EAAO,MAAQI,EAAQC,EACvBL,EAAO,OAASK,EAEhBH,EAAU,MAAQE,EAAQC,EAC1BH,EAAU,OAASG,CACvB,CAEO,SAASG,EAAeC,EAAwB,CACnDL,EAAQK,EAERT,EAAO,MAAQI,EAAQC,EACvBL,EAAO,OAASK,EAEhBH,EAAU,MAAQE,EAAQC,EAC1BH,EAAU,OAASG,CACvB,CAEAL,EAAO,eAAe,aAAaE,EAAWF,CAAM,EAEpDM,EAAS,GAAG,ECdZ,IAA8BI,EAA9B,MAA8BC,CAAO,CAE1B,EACA,EACA,IACA,MACA,OACA,MAEC,WAA4B,KAC5B,UAAqB,GAG7B,OAAe,gBAA4C,KAC3D,OAAe,aAAgD,KAQrD,SAAU,CAChBC,EAAO,KAAK,EAAE,QAAQ,CAC1B,CAEU,gBAAiB,CACvB,KAAK,UAAY,GACjB,KAAK,WAAa,IACtB,CAEU,eAAwB,CAC9B,OAAI,KAAK,WAAa,CAAC,KAAK,cACxB,KAAK,WAAa,KAAK,QAAQ,EAC/B,KAAK,UAAY,IAEd,KAAK,UAChB,CAEA,YAAYC,EAAyB,CACjC,KAAK,EAAIA,GAAS,GAAK,EACvB,KAAK,EAAIA,GAAS,GAAK,EACvB,KAAK,IAAMA,GAAS,KAAO,EAC3B,KAAK,MAAQA,GAAS,OAAS,OAC/B,KAAK,OAASA,GAAS,QAAU,GACjC,KAAK,MAAQA,GAAS,OAAS,EAC/BD,EAAO,KAAK,EAAE,UAAU,IAAI,CAChC,CAIO,SAASE,EAAyB,CAGrC,IAAMC,EAAQ,KAAK,eAAe,EAC5BC,EAAQF,EAAO,eAAe,EAMpC,GAAI,EAHA,KAAK,IAAIC,EAAM,EAAIC,EAAM,CAAC,GAAKD,EAAM,MAAQC,EAAM,OAAS,GAC5D,KAAK,IAAID,EAAM,EAAIC,EAAM,CAAC,GAAKD,EAAM,OAASC,EAAM,QAAU,GAEhD,MAAO,GAKzB,IAAMC,EAASF,EAAM,EAAIA,EAAM,MAAQ,EACjCG,EAAQH,EAAM,EAAIA,EAAM,OAAS,EACjCI,EAAUJ,EAAM,EAAIA,EAAM,MAAQ,EAClCK,EAAWL,EAAM,EAAIA,EAAM,OAAS,EAEpCM,EAASL,EAAM,EAAIA,EAAM,MAAQ,EACjCM,EAAQN,EAAM,EAAIA,EAAM,OAAS,EACjCO,EAAUP,EAAM,EAAIA,EAAM,MAAQ,EAClCQ,EAAWR,EAAM,EAAIA,EAAM,OAAS,EAEpCS,EAAO,KAAK,IAAIR,EAAQI,CAAM,EAC9BK,EAAO,KAAK,IAAIN,EAAUI,CAAQ,EAClCG,EAAO,KAAK,IAAIR,EAASI,CAAO,EAChCK,EAAO,KAAK,IAAIV,EAAOI,CAAK,EAE5BO,EAAQF,EAAOF,EACfK,EAASF,EAAOF,EAEtB,GAAIG,GAAS,GAAKC,GAAU,EAAG,MAAO,GAGjCnB,EAAO,kBACRA,EAAO,gBAAkB,SAAS,cAAc,QAAQ,EACxDA,EAAO,aAAeA,EAAO,gBAAgB,WAAW,KAAM,CAAE,mBAAoB,EAAK,CAAC,IAI1FA,EAAO,gBAAgB,MAAQkB,GAASlB,EAAO,gBAAgB,OAASmB,KACxEnB,EAAO,gBAAgB,MAAQ,KAAK,IAAIkB,EAAOlB,EAAO,gBAAgB,KAAK,EAC3EA,EAAO,gBAAgB,OAAS,KAAK,IAAImB,EAAQnB,EAAO,gBAAgB,MAAM,GAGlF,IAAMoB,EAAMpB,EAAO,aACnBoB,EAAI,UAAU,EAAG,EAAGF,EAAOC,CAAM,EAGjCC,EAAI,KAAK,EACTA,EAAI,UAAU,KAAK,EAAIN,EAAMK,EAAS,KAAK,EAAIJ,CAAI,EACnDK,EAAI,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EACnCA,EAAI,UAAY,MAChBA,EAAI,KAAK,KAAK,cAAc,CAAC,EAC7BA,EAAI,QAAQ,EACZ,IAAMC,EAAOD,EAAI,aAAa,EAAG,EAAGF,EAAOC,CAAM,EAAE,KAGnDC,EAAI,UAAU,EAAG,EAAGF,EAAOC,CAAM,EACjCC,EAAI,KAAK,EACTA,EAAI,UAAUjB,EAAO,EAAIW,EAAMK,EAAShB,EAAO,EAAIY,CAAI,EACvDK,EAAI,OAAO,KAAK,UAAUjB,EAAO,GAAG,CAAC,EACrCiB,EAAI,UAAY,OAChBA,EAAI,KAAKjB,EAAO,cAAc,CAAC,EAC/BiB,EAAI,QAAQ,EACZ,IAAME,EAAOF,EAAI,aAAa,EAAG,EAAGF,EAAOC,CAAM,EAAE,KAGnD,QAASI,EAAI,EAAGA,EAAIF,EAAK,OAAQE,GAAK,EAClC,GAAIF,EAAKE,CAAC,EAAK,GAAKD,EAAKC,CAAC,EAAK,EAAG,MAAO,GAE7C,MAAO,EACX,CAIU,UAAUC,EAAa,CAC7B,OAAOA,EAAM,KAAK,GAAK,GAC3B,CAEU,UAAUC,EAAa,CAC7B,OAAOA,EAAM,IAAM,KAAK,EAC5B,CAKO,KAAKC,EAAe,CACvB,KAAK,GAAKA,EAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,GAAG,CAAC,EACnD,KAAK,GAAKA,EAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,GAAG,CAAC,EACnD,KAAK,QAAQ,CACjB,CAEO,KAAKF,EAAa,CACrB,KAAK,KAAOA,EACZ,KAAK,QAAQ,CACjB,CAEO,MAAMG,EAAa,CACtB,KAAK,IAAMA,EACX,KAAK,QAAQ,CACjB,CAEO,aAAaC,EAAWC,EAAW,CACtC,KAAK,IAAM,GAAK,KAAK,UAAU,KAAK,MAAMA,EAAGD,CAAC,CAAC,EAC/C,KAAK,QAAQ,CACjB,CAEO,KAAKA,EAAW,CACnB,KAAK,EAAIA,EACT,KAAK,QAAQ,CACjB,CAEO,KAAKC,EAAW,CACnB,KAAK,EAAIA,EACT,KAAK,QAAQ,CACjB,CAEO,KAAKD,EAAWC,EAAW,CAC9B,KAAK,EAAID,EACT,KAAK,EAAIC,EACT,KAAK,QAAQ,CACjB,CAEO,QAAQC,EAAY,CACvB,KAAK,GAAKA,EACV,KAAK,QAAQ,CACjB,CAEO,QAAQC,EAAY,CACvB,KAAK,GAAKA,EACV,KAAK,QAAQ,CACjB,CAIO,MAAO,CACV,KAAK,OAAS,GACd,KAAK,QAAQ,CACjB,CAEO,MAAO,CACV,KAAK,OAAS,GACd,KAAK,QAAQ,CACjB,CAEO,UAAUC,EAAe,CAC5B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEO,YAAYC,EAAY,CAC3B,KAAK,OAASA,EACd,KAAK,QAAQ,CACjB,CACJ,ECrNA,IAAqBC,EAArB,MAAqBC,CAAO,CAExB,OAAe,SAEP,YAAuB,GACxB,SAA4B,KAE5B,OAAiB,GACjB,UAAoB,EAAI,KAAK,OAC5B,UAAoB,YAAY,IAAI,EACpC,iBAA4B,GAC5B,iBAAkC,KAEnC,OAA6B,CAAC,EAE9B,OAAiB,EACjB,OAAiB,EAEjB,UAAqB,GACrB,aAAwB,GAEvB,YAA2B,IAAI,IAEhC,aAAuB,OACvB,SAAqB,CAAC,EAI7B,OAAc,MAAO,CACjB,OAAK,KAAK,WACN,KAAK,SAAW,IAAIA,GAEjB,KAAK,QAChB,CAIO,YAAYC,EAAe,CACzB,KAAK,SAASA,CAAK,IACpB,KAAK,SAASA,CAAK,EAAI,CAAE,QAAS,CAAC,EAAG,KAAM,IAAK,GAErD,KAAK,YAAc,GACnB,KAAK,aAAeA,EACpB,KAAK,SAAW,KAAK,SAASA,CAAK,EAAE,KACrC,KAAK,sBAAsB,KAAK,MAAM,CAC1C,CAIO,QAAQA,EAAeC,EAAgB,CAC1C,GAAI,CAAC,KAAK,SAASD,CAAK,EAAG,CACvB,KAAK,SAASA,CAAK,EAAI,CAAE,QAAS,CAAC,EAAG,KAAAC,CAAK,EACvCD,IAAU,KAAK,cACf,KAAK,YAAYA,CAAK,EAC1B,MACJ,CAEA,KAAK,SAASA,CAAK,EAAE,KAAOC,EACxBD,IAAU,KAAK,cACf,KAAK,YAAYA,CAAK,CAC9B,CAEO,WAAY,CACf,KAAK,YAAc,GACf,KAAK,mBAAqB,OAC1B,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,KAEhC,CAEO,YAAa,CAChB,KAAK,YAAc,GACd,KAAK,sBAAsB,KAAK,MAAM,CAC/C,CAIO,UAAUE,EAAgB,CAC7B,GAAM,CAAE,MAAAF,EAAO,MAAAG,CAAM,EAAID,EAEzB,GAAI,CAAC,KAAK,SAASF,CAAK,EAAG,CACvB,KAAK,SAASA,CAAK,EAAI,CAAE,QAAS,CAACE,CAAM,EAAG,KAAM,IAAK,EACvD,MACJ,CAEA,IAAIE,EAAc,KAAK,SAASJ,CAAK,EAAE,QAAQ,UAAUK,GAAKA,EAAE,MAAQF,CAAK,EAC7E,GAAIC,IAAgB,GAAI,CACpB,KAAK,SAASJ,CAAK,EAAE,QAAQ,KAAKE,CAAM,EACxC,MACJ,CAEA,KAAK,SAASF,CAAK,EAAE,QAAQ,OAAOI,EAAa,EAAGF,CAAM,EAC1D,KAAK,QAAQ,CACjB,CAEO,aAAaA,EAAgB,CAChC,GAAM,CAAE,MAAAF,CAAM,EAAIE,EAEb,KAAK,SAASF,CAAK,IAExB,KAAK,SAASA,CAAK,EAAE,QAAU,KAAK,SAASA,CAAK,EAAE,QAAQ,OAAOK,GAAKA,IAAMH,CAAM,EACpF,KAAK,QAAQ,EACjB,CAEA,MAAa,sBAAsBI,EAAgB,CAC/C,KAAK,OAASA,EAEd,IAAIL,EAAO,KAAK,SAChB,GAAI,CAACA,EAAM,OAGP,KAAK,mBAAqB,OAC1B,qBAAqB,KAAK,gBAAgB,EAC1C,KAAK,iBAAmB,MAG5B,KAAK,YAAc,GACnB,IAAMM,EAAgB,IAAOD,EACzBE,EAAc,EAEZC,EAAO,MAAOC,GAAwB,CACxC,GAAI,CAAC,KAAK,YAAa,OAEvB,IAAMC,EAAYD,EAAc,KAAK,UACrC,KAAK,UAAYA,EACjBF,GAAeG,EAGXH,GAAeD,IACf,KAAK,UAAYC,EAAc,IAC/BA,EAAcA,EAAcD,EAExBN,GAAM,MAAMA,EAAK,GAGzB,KAAK,iBAAmB,sBAAsBQ,CAAI,CACtD,EAEA,KAAK,UAAY,YAAY,IAAI,EACjC,KAAK,iBAAmB,sBAAsBA,CAAI,CACtD,CAEO,SAAU,CACT,KAAK,mBACT,KAAK,iBAAmB,GAExB,sBAAsB,IAAM,CACxB,KAAK,iBAAmB,GACxBG,EAAI,UAAU,EAAG,EAAGC,EAAO,MAAOA,EAAO,MAAM,EAC/B,CACZ,GAAI,KAAK,SAAS,KAAK,YAAY,GAAG,SAAW,CAAC,EAClD,GAAI,KAAK,SAAS,GAAG,GAAG,SAAW,CAAC,CACxC,EACQ,QAAQX,GAAU,CACjBA,EAAO,QACRA,EAAO,KAAK,CACpB,CAAC,CACL,CAAC,EACL,CAIA,MAAa,KAAKY,EAA2B,CACzC,OAAO,IAAI,QAAQC,GAAW,WAAWA,EAASD,CAAE,CAAC,CACzD,CAEA,MAAa,UAAUE,EAA+C,CAClE,OAAO,IAAI,QAAQD,GAAW,CAC1B,IAAME,EAAQ,IAAM,CACZD,EAAgB,EAAGD,EAAQ,EAC1B,WAAWE,EAAO,IAAO,KAAK,MAAM,CAC7C,EACAA,EAAM,CACV,CAAC,CACL,CAIO,SAASf,EAAgB,CAC5B,GAAM,CAAE,OAAAgB,EAAQ,OAAAC,CAAO,EAAI,KAErBC,EAAeF,EAASL,EAAO,MAAQ,EACvCQ,EAAeR,EAAO,OAAS,EAAIM,EAGnCG,EAASF,GAAgBlB,EAAO,EAAIW,EAAO,MAAQ,GACnDU,EAASF,GAAgBR,EAAO,OAAS,EAAIX,EAAO,GAGpDsB,EAAQ,CAAC,KAAK,UAAUtB,EAAO,GAAG,EAClCuB,EAAWH,EAAS,KAAK,IAAIE,CAAK,EAAID,EAAS,KAAK,IAAIC,CAAK,EAC7DE,EAAWJ,EAAS,KAAK,IAAIE,CAAK,EAAID,EAAS,KAAK,IAAIC,CAAK,EAEnE,OAAOZ,EAAI,cAAcV,EAAO,QAAQ,EAAGuB,EAAUC,CAAQ,CACjE,CAEO,WAAWC,EAAa,CAC3B,OAAO,KAAK,YAAY,IAAIA,CAAG,CACnC,CAIO,UAAUC,EAAa,CAC1B,IAAMC,EAAQ,IAAI,MAAMD,CAAG,EAC3B,YAAK,OAAO,KAAKC,CAAK,EAEtBA,EAAM,KAAK,EAEJA,CACX,CAEO,UAAUC,EAAyB,CACtCA,EAAM,MAAM,EACZA,EAAM,YAAc,EACpB,KAAK,OAAS,KAAK,OAAO,OAAOzB,GAAKA,IAAMyB,CAAK,CACrD,CAEO,eAAgB,CACnB,KAAK,OAAO,QAAQA,GAAS,CACzBA,EAAM,MAAM,EACZA,EAAM,YAAc,CACxB,CAAC,EACD,KAAK,OAAS,CAAC,CACnB,CAIO,WAAWC,EAAaC,EAAa,CACxC,OAAID,EAAMC,IACN,CAACD,EAAKC,CAAG,EAAI,CAACA,EAAKD,CAAG,GACnB,KAAK,MAAM,KAAK,OAAO,GAAKC,EAAMD,EAAM,GAAKA,CAAG,CAC3D,CAEO,WAAWE,EAAqD,CACnE,GAAM,CAACC,EAAGC,CAAC,EAAIF,EAEf,OAAQC,EAAE,OAAQ,CACd,IAAK,GAAG,OAAOA,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAID,EAAE,CAAC,EAAIC,EAAE,CAAC,EACvC,IAAK,GAAG,OAAOD,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAID,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAID,EAAE,CAAC,EAAIC,EAAE,CAAC,EACrD,IAAK,GAAG,OAAOD,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAID,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAID,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAKD,EAAE,CAAC,EAAIC,EAAE,CAAC,CACxE,CACJ,CAGO,IAAIC,EAAa,CACpB,OAAO,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CACvC,CAEO,IAAIA,EAAa,CACpB,OAAO,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CACvC,CAEO,IAAIA,EAAa,CACpB,OAAO,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CACvC,CAEO,IAAIA,EAAa,CACpB,MAAO,GAAI,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CAC3C,CAEO,IAAIA,EAAa,CACpB,MAAO,GAAI,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CAC3C,CAEO,IAAIA,EAAa,CACpB,MAAO,GAAI,KAAK,IAAI,KAAK,UAAUA,CAAG,CAAC,CAC3C,CAGO,KAAKC,EAAa,CACrB,OAAO,KAAK,UAAU,KAAK,KAAKA,CAAG,CAAC,CACxC,CAEO,KAAKA,EAAa,CACrB,OAAO,KAAK,UAAU,KAAK,KAAKA,CAAG,CAAC,CACxC,CAEO,KAAKA,EAAa,CACrB,OAAO,KAAK,UAAU,KAAK,KAAK,EAAIA,CAAG,CAAC,CAC5C,CAEO,KAAKA,EAAa,CACrB,OAAO,KAAK,UAAU,KAAK,KAAK,EAAIA,CAAG,CAAC,CAC5C,CAIO,UAAUD,EAAa,CAC1B,OAAOA,EAAM,KAAK,GAAK,GAC3B,CAEO,UAAUE,EAAa,CAC1B,OAAOA,EAAM,IAAM,KAAK,EAC5B,CAIQ,aAAc,CACb,KAAK,sBAAsB,EAAE,EAKlCC,EAAU,iBAAiB,YAAaC,GAAK,CACzC,KAAK,OAASA,EAAE,QAAUD,EAAU,WAAaA,EAAU,MAAQ,EACnE,KAAK,OAAS,EAAEC,EAAE,QAAUD,EAAU,UAAYA,EAAU,OAAS,EACzE,CAAC,EACDA,EAAU,iBAAiB,YAAaC,GAAK,CACzC,KAAK,UAAY,EACrB,CAAC,EACDD,EAAU,iBAAiB,UAAWC,GAAK,CACvC,KAAK,UAAY,EACrB,CAAC,EACDD,EAAU,iBAAiB,QAASC,GAAK,CACrC,KAAK,aAAe,GACpB,WAAW,IAAM,KAAK,aAAe,GAAO,CAAC,CACjD,CAAC,EAGD,iBAAiB,UAAWA,GAAK,CACzBA,EAAE,QACN,KAAK,YAAY,IAAIA,EAAE,GAAG,CAC9B,CAAC,EAED,iBAAiB,QAASA,GAAK,CAC3B,KAAK,YAAY,OAAOA,EAAE,GAAG,CACjC,CAAC,CACL,CACJ,EC1UA,IAAqBC,EAArB,cAAuCC,CAAO,CAEnC,aAAe,YAEf,MACA,OACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,MAAM,KAAK,MAAO,KAAK,MAAM,EACzC,OAAQ,KAAK,MAAM,KAAK,MAAO,KAAK,MAAM,CAC9C,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,KACD,CAAC,KAAK,MAAQ,EACd,CAAC,KAAK,OAAS,EACf,KAAK,MACL,KAAK,MACT,EAEOA,CACX,CAEO,KAAKC,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMF,EAAO,KAAK,cAAc,EAEhCE,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKF,CAAI,EACP,KAAK,cACLE,EAAE,OAAOF,CAAI,EAEjBE,EAAE,QAAQ,CACd,CAEO,SAASM,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,UAAUC,EAAgB,CAC7B,KAAK,OAASA,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAA4B,CACpC,MAAMA,CAAO,EACb,KAAK,MAAQA,GAAS,OAAS,GAC/B,KAAK,OAASA,GAAS,QAAU,GACjC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAC7C,KAAK,KAAK,CACd,CAEJ,ECnFA,IAAqBC,EAArB,cAAoCC,CAAO,CAEhC,aAAe,SAEf,WACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,MAAM,KAAK,WAAY,KAAK,UAAU,EAClD,OAAQ,KAAK,MAAM,KAAK,WAAY,KAAK,UAAU,CACvD,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,KACD,CAAC,KAAK,WAAa,EACnB,CAAC,KAAK,WAAa,EACnB,KAAK,WACL,KAAK,UACT,EAEOA,CACX,CAEO,KAAKC,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMF,EAAO,KAAK,cAAc,EAEhCE,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKF,CAAI,EACP,KAAK,cACLE,EAAE,OAAOF,CAAI,EAEjBE,EAAE,QAAQ,CACd,CAEO,cAAcM,EAAoB,CACrC,KAAK,WAAaA,EAClB,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAyB,CACjC,MAAMA,CAAO,EACb,KAAK,WAAaA,GAAS,YAAc,GACzC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAC7C,KAAK,KAAK,CACd,CAEJ,ECzEA,IAAqBC,EAArB,cAAkCC,CAAO,CAE9B,aAAe,OAEf,KACA,KACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,MAAM,KAAK,KAAO,EAAG,KAAK,KAAO,CAAC,EAC9C,OAAQ,KAAK,MAAM,KAAK,KAAO,EAAG,KAAK,KAAO,CAAC,CACnD,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,QACD,EAAG,EACH,KAAK,KACL,KAAK,KACL,EAAG,EACH,KAAK,GAAK,CACd,EAEOA,CACX,CAEO,KAAKC,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMF,EAAO,KAAK,cAAc,EAEhCE,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKF,CAAI,EACP,KAAK,cACLE,EAAE,OAAOF,CAAI,EAEjBE,EAAE,QAAQ,CACd,CAEO,QAAQM,EAAc,CACzB,KAAK,KAAOA,EACZ,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,QAAQC,EAAc,CACzB,KAAK,KAAOA,EACZ,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAuB,CAC/B,MAAMA,CAAO,EACb,KAAK,KAAOA,GAAS,MAAQ,GAC7B,KAAK,KAAOA,GAAS,MAAQ,GAC7B,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAC7C,KAAK,KAAK,CACd,CAEJ,ECpFA,IAAqBC,EAArB,cAAoCC,CAAO,CAEhC,aAAe,SAEf,OACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,OAAS,EACrB,OAAQ,KAAK,OAAS,CAC1B,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,QACD,EAAG,EACH,KAAK,OACL,KAAK,OACL,EAAG,EACH,KAAK,GAAK,CACd,EAEOA,CACX,CAEO,KAAKC,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMF,EAAO,KAAK,cAAc,EAEhCE,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKF,CAAI,EACP,KAAK,cACLE,EAAE,OAAOF,CAAI,EAEjBE,EAAE,QAAQ,CACd,CAEO,UAAUM,EAAgB,CAC7B,KAAK,OAASA,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAyB,CACjC,MAAMA,CAAO,EACb,KAAK,OAASA,GAAS,QAAU,GACjC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAC7C,KAAK,KAAK,CACd,CAEJ,EC1EA,IAAqBC,EAArB,cAAiCC,CAAO,CAE7B,aAAe,MAEf,OACA,MACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,OAAS,EACrB,OAAQ,KAAK,OAAS,CAC1B,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,IACD,EAAG,EACH,KAAK,OACL,KAAK,UAAU,KAAK,MAAQ,EAAI,EAAE,EAClC,KAAK,UAAU,CAAC,KAAK,MAAQ,EAAI,EAAE,CACvC,EAEOA,CACX,CAEO,KAAKC,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMF,EAAO,KAAK,cAAc,EAEhCE,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKF,CAAI,EACP,KAAK,cACLE,EAAE,OAAOF,CAAI,EAEjBE,EAAE,QAAQ,CACd,CAEO,UAAUM,EAAgB,CAC7B,KAAK,OAASA,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAsB,CAC9B,MAAMA,CAAO,EAEb,KAAK,OAASA,GAAS,QAAU,GACjC,KAAK,MAAQA,GAAS,OAAS,IAC/B,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAE7C,KAAK,KAAK,CACd,CAEJ,ECpFA,IAAqBC,EAArB,cAA4CC,CAAO,CAExC,aAAe,iBAEf,MACA,OACA,MACA,aACA,aAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,OAAS,EACrB,OAAQ,KAAK,OAAS,CAC1B,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OACXC,EAAQ,EAAI,KAAK,GAAM,KAAK,MAClCD,EAAK,OAAO,KAAK,OAAQ,CAAC,EAC1B,QAASE,EAAI,EAAGA,EAAI,KAAK,MAAOA,IAC5BF,EAAK,OAAO,KAAK,OAAS,KAAK,IAAIC,EAAOC,CAAC,EAAG,KAAK,OAAS,KAAK,IAAID,EAAOC,CAAC,CAAC,EAElF,OAAAF,EAAK,UAAU,EACRA,CACX,CAEO,KAAKG,EAAoB,CAC5B,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EAErCJ,EAAE,UAAUG,EAAIE,CAAE,EAClBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMJ,EAAO,KAAK,cAAc,EAEhCI,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKJ,CAAI,EACP,KAAK,cACLI,EAAE,OAAOJ,CAAI,EAEjBI,EAAE,QAAQ,CACd,CAEO,SAASM,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,UAAUC,EAAgB,CAC7B,KAAK,OAASA,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAiC,CACzC,MAAMA,CAAO,EACb,KAAK,MAAQA,GAAS,OAAS,EAC/B,KAAK,OAASA,GAAS,QAAU,GACjC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAC7C,KAAK,KAAK,CACd,CAEJ,EChFA,IAAqBC,EAArB,cAA2CC,CAAO,CAEvC,aAAe,gBAEf,SACA,MACA,aACA,aAEA,gBAA8B,CAEjC,IAAIC,EAAqB,EAEzB,QAAWC,KAAK,KAAK,SAAU,CAE3B,IAAMC,EAAO,KAAK,MAAMD,EAAE,CAAC,EAAGA,EAAE,CAAC,CAAC,EAE9BC,EAAOF,IACPA,EAAqBE,EAC7B,CAEA,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAOF,EACP,OAAQA,CACZ,CACJ,CAEO,SAAkB,CACrB,IAAMG,EAAO,IAAI,OACXC,EAAW,KAAK,SAEtB,GAAIA,EAAS,OAAS,EAAG,OAAOD,EAEhCA,EAAK,OAAOC,EAAS,CAAC,EAAG,CAAC,EAAGA,EAAS,CAAC,EAAG,CAAC,CAAC,EAE5C,QAASC,EAAI,EAAGA,EAAID,EAAS,OAAQC,IACjCF,EAAK,OAAOC,EAASC,CAAC,EAAG,CAAC,EAAGD,EAASC,CAAC,EAAG,CAAC,CAAC,EAEhD,OAAAF,EAAK,UAAU,EAERA,CACX,CAEO,KAAKG,EAA0B,CAClC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjC,IAAMJ,EAAO,KAAK,cAAc,EAEhCI,EAAE,UAAY,KAAK,MACnBA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,KAAKJ,CAAI,EACP,KAAK,cACLI,EAAE,OAAOJ,CAAI,EAEjBI,EAAE,QAAQ,CACd,CAEO,YAAYH,EAAkB,CACjC,KAAK,SAAWA,EAChB,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASS,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEA,YAAYC,EAAgC,CACxC,MAAMA,CAAO,EAEb,KAAK,SAAWA,GAAS,UAAY,CAAC,EACtC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAE7C,KAAK,KAAK,CACd,CAEJ,EC5FA,IAAqBC,EAArB,cAAiCC,CAAO,CAE7B,aAAe,MAEf,QACA,KACA,MAEA,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,KACZ,OAAQ,KAAK,IACjB,CACJ,CAEO,SAAkB,CACrB,OAAO,IAAI,MACf,CACO,MAAO,CAAC,CAER,IAAK,CACR,KAAK,QAAU,EACnB,CAEO,MAAO,CACV,KAAK,QAAU,EACnB,CAEO,MAAMC,EAAgB,CACzBA,EAAO,KAAK,EAAI,CACpB,CAEO,UAAW,CACdC,EAAO,UAAU,EAAG,EAAGC,EAAO,MAAOA,EAAO,MAAM,CACtD,CAEO,KAAM,CACTD,EAAO,UAAY,KAAK,MACxBA,EAAO,SACH,KAAK,EAAI,KAAK,KAAO,EAAIC,EAAO,MAAQ,EACxC,CAAC,KAAK,EAAI,KAAK,KAAO,EAAIA,EAAO,OAAS,EAC1C,KAAK,KACL,KAAK,IACT,CACJ,CAEQ,SAASC,EAAeC,EAAe,CAC3CH,EAAO,UAAU,EAEjBA,EAAO,OAAOE,EAAQD,EAAO,MAAQ,EAAG,CAACE,EAAQF,EAAO,OAAS,CAAC,EAClED,EAAO,OAAO,KAAK,EAAIC,EAAO,MAAQ,EAAG,CAAC,KAAK,EAAIA,EAAO,OAAS,CAAC,EAEpED,EAAO,UAAY,KAAK,KACxBA,EAAO,YAAc,KAAK,MAC1BA,EAAO,OAAO,CAClB,CAIgB,KAAKI,EAAe,CAChC,IAAMF,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,GAAKC,EAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,GAAG,CAAC,EACnD,KAAK,GAAKA,EAAQ,KAAK,IAAI,KAAK,UAAU,KAAK,GAAG,CAAC,EAC/C,KAAK,SACL,KAAK,SAASF,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAEgB,KAAKE,EAAW,CAC5B,IAAMH,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,EAAIE,EACL,KAAK,SACL,KAAK,SAASH,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAEgB,KAAKG,EAAW,CAC5B,IAAMJ,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,EAAIG,EACL,KAAK,SACL,KAAK,SAASJ,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAEgB,KAAKE,EAAWC,EAAW,CACvC,IAAMJ,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,EAAIE,EACT,KAAK,EAAIC,EACL,KAAK,SACL,KAAK,SAASJ,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAEgB,QAAQI,EAAY,CAChC,IAAML,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,GAAKI,EACN,KAAK,SACL,KAAK,SAASL,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAEgB,QAAQK,EAAY,CAChC,IAAMN,EAAQ,KAAK,EACbC,EAAQ,KAAK,EAEnB,KAAK,GAAKK,EACN,KAAK,SACL,KAAK,SAASN,EAAOC,CAAK,EAC9B,KAAK,QAAQ,CACjB,CAIA,YAAYM,EAAsB,CAC9B,MAAMA,CAAO,EACb,KAAK,QAAUA,GAAS,SAAW,GACnC,KAAK,KAAOA,GAAS,MAAQ,EAC7B,KAAK,MAAQA,GAAS,OAAS,OACnC,CAEJ,EClHA,IAAqBC,EAArB,cAAkCC,CAAO,CAE9B,aAAe,OAEf,QACA,MACA,WACA,SACA,MACA,SAEC,KAED,gBAA8B,CACjC,IAAMC,EAAUC,EAAI,YAAY,KAAK,OAAO,EACtCC,EAAQF,EAAQ,MAChBG,EAASH,EAAQ,wBAA0BA,EAAQ,yBAEzD,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAAE,EAAO,OAAAC,CACX,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjBH,EAAI,KAAK,EAETA,EAAI,KAAO,KAAK,KAEhB,IAAMD,EAAUC,EAAI,YAAY,KAAK,OAAO,EACtCC,EAAQF,EAAQ,MAChBG,EAASH,EAAQ,wBAA0BA,EAAQ,yBAEzD,OAAAC,EAAI,QAAQ,EAEZG,EAAK,KAAK,CAACF,EAAQ,EAAG,CAACC,EAAS,EAAGD,EAAOC,CAAM,EAEzCC,CACX,CAEgB,KAAKC,EAAoB,CACrC,IAAMC,EAAID,EAAWE,EAASN,EAE9BK,EAAE,KAAK,EAEP,IAAME,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCH,EAAE,UAAUE,EAAIE,CAAE,EAElBJ,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjCA,EAAE,KAAO,KAAK,KACdA,EAAE,UAAY,KAAK,MACnBA,EAAE,UAAY,KAAK,MACnBA,EAAE,aAAe,KAAK,SAEtBA,EAAE,SAAS,KAAK,QAAS,EAAG,CAAC,EAE7BA,EAAE,QAAQ,CACd,CAIO,WAAWK,EAAiB,CAC/B,KAAK,QAAUA,EACf,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,QAAQ,CACjB,CAEO,YAAYC,EAAkB,CACjC,KAAK,SAAWA,EAChB,KAAK,KAAO,GAAG,KAAK,QAAQ,MAAM,KAAK,UAAU,GACjD,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,cAAcC,EAAoB,CACrC,KAAK,WAAaA,EAClB,KAAK,KAAO,GAAG,KAAK,QAAQ,MAAM,KAAK,UAAU,GACjD,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAwB,CACpC,KAAK,MAAQA,EACb,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,YAAYC,EAA8B,CAC7C,KAAK,SAAWA,EAChB,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAIA,YAAYC,EAAuB,CAC/B,MAAMA,CAAO,EAEb,KAAK,QAAUA,GAAS,SAAW,GACnC,KAAK,MAAQA,GAAS,OAAS,QAC/B,KAAK,WAAaA,GAAS,YAAc,QACzC,KAAK,SAAWA,GAAS,UAAY,GACrC,KAAK,MAAQA,GAAS,OAAS,SAC/B,KAAK,SAAWA,GAAS,UAAY,SAErC,KAAK,KAAO,GAAG,KAAK,QAAQ,MAAM,KAAK,UAAU,GAEjD,KAAK,KAAK,CACd,CACJ,ECvIA,IAAqBC,EAArB,cAAyCC,CAAO,CAErC,aAAe,cAEf,IACA,MACA,OACA,aACA,aAEG,IAEH,gBAA8B,CACjC,MAAO,CACH,EAAG,KAAK,EACR,EAAG,KAAK,EACR,MAAO,KAAK,MACZ,OAAQ,KAAK,MACjB,CACJ,CAEO,SAAkB,CACrB,IAAMC,EAAO,IAAI,OAEjB,OAAAA,EAAK,KACD,CAAC,KAAK,MAAQ,EACd,CAAC,KAAK,OAAS,EACf,KAAK,MACL,KAAK,MACT,EAEOA,CACX,CAEgB,KAAKC,EAAoB,CACrC,IAAMC,EAAID,EAAWE,EAASC,EAE9BF,EAAE,KAAK,EAEP,IAAMG,EAAK,KAAK,EAAIC,EAAO,MAAQ,EAC7BC,EAAK,CAAC,KAAK,EAAID,EAAO,OAAS,EACrCJ,EAAE,UAAUG,EAAIE,CAAE,EAElBL,EAAE,OAAO,KAAK,UAAU,KAAK,GAAG,CAAC,EAEjCA,EAAE,YAAc,KAAK,aACrBA,EAAE,UAAY,KAAK,aACnBA,EAAE,UACE,KAAK,IACL,EAAG,EACH,KAAK,IAAI,MACT,KAAK,IAAI,OACT,CAAC,KAAK,MAAQ,EACd,CAAC,KAAK,OAAS,EACf,KAAK,MAAO,KAAK,MACrB,EACI,KAAK,cACLA,EAAE,OAAO,KAAK,cAAc,CAAC,EAEjCA,EAAE,QAAQ,CACd,CAIO,OAAOM,EAAa,CACvB,KAAK,IAAMA,EACX,KAAK,QAAQ,CACjB,CAEO,SAASC,EAAe,CAC3B,KAAK,MAAQA,EACb,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAEO,UAAUC,EAAgB,CAC7B,KAAK,OAASA,EACd,KAAK,eAAe,EACpB,KAAK,QAAQ,CACjB,CAIA,YAAYC,EAA8B,CACtC,MAAMA,CAAO,EAEb,KAAK,IAAMA,GAAS,KAAO,GAC3B,KAAK,IAAM,IAAI,MACf,KAAK,IAAI,IAAM,KAAK,IAEpB,KAAK,MAAQA,GAAS,OAAS,KAAK,IAAI,MACxC,KAAK,OAASA,GAAS,QAAU,KAAK,IAAI,OAE1C,KAAK,aAAeA,GAAS,cAAgB,QAC7C,KAAK,aAAeA,GAAS,cAAgB,EAE7C,KAAK,KAAK,CACd,CACJ,Eb5FA,IAAMC,EAAW,CAEb,OAAAC,EACA,OAAAC,EAGA,UAAAC,EACA,OAAAC,EACA,KAAAC,EACA,OAAAC,EACA,IAAAC,EACA,eAAAC,EACA,cAAAC,EACA,IAAAC,EACA,KAAAC,EACA,YAAAC,EAGA,SAAAC,EACA,eAAAC,EACA,OAAAC,EACA,IAAAC,CACJ,EAEOC,EAAQjB","names":["index_exports","__export","Arc","Circle","CustomPolygon","Engine","ImageSprite","Oval","Pen","Rectangle","RegularPolygon","Sprite","Square","Text","canvas","ctx","index_default","setAspectRatio","setScale","__toCommonJS","canvas","ctx","penCanvas","penCtx","ratio","scale","setScale","newScale","setAspectRatio","newAspectRatio","Sprite","_Sprite","Engine","options","sprite","bBox1","bBox2","b1Left","b1Top","b1Right","b1Bottom","b2Left","b2Top","b2Right","b2Bottom","xMin","yMin","xMax","yMax","width","height","ctx","img1","img2","i","deg","rad","steps","dir","x","y","dX","dY","layer","dL","Engine","_Engine","scene","loop","sprite","layer","targetIndex","s","maxFPS","frameInterval","accumulator","tick","currentTime","deltaTime","ctx","canvas","ms","resolve","conditionGetter","check","mouseX","mouseY","canvasMouseX","canvasMouseY","localX","localY","angle","rotatedX","rotatedY","key","src","audio","sound","min","max","vectors","a","b","deg","val","rad","penCanvas","e","Rectangle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","width","height","color","options","Square","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","sideLength","color","options","Oval","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radX","radY","color","options","Circle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","color","options","Arc","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","angle","color","options","RegularPolygon","Sprite","path","step","i","stamping","c","penCtx","ctx","cX","canvas","cY","sides","radius","color","options","CustomPolygon","Sprite","furthestVertexSize","v","size","path","vertices","i","stamping","c","penCtx","ctx","cX","canvas","cY","color","options","Pen","Sprite","sprite","penCtx","canvas","lastX","lastY","steps","x","y","dX","dY","options","Text","Sprite","metrics","ctx","width","height","path","stamping","c","penCtx","cX","canvas","cY","content","color","fontSize","fontFamily","align","baseline","options","ImageSprite","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","src","width","height","options","TScratch","Engine","Sprite","Rectangle","Square","Oval","Circle","Arc","RegularPolygon","CustomPolygon","Pen","Text","ImageSprite","setScale","setAspectRatio","canvas","ctx","index_default"]}
package/dist/index.d.cts CHANGED
@@ -48,6 +48,10 @@ declare abstract class Sprite {
48
48
  changeLayer(dL: number): void;
49
49
  }
50
50
 
51
+ type Vec2 = [number, number];
52
+ type Vec3 = [number, number, number];
53
+ type Vec4 = [number, number, number, number];
54
+
51
55
  type GameLoop = (() => any) | (() => Promise<any>);
52
56
  type SceneMap = {
53
57
  [scene: string]: {
@@ -89,6 +93,7 @@ declare class Engine {
89
93
  stopSound(sound: HTMLAudioElement): void;
90
94
  stopAllSounds(): void;
91
95
  pickRandom(min: number, max: number): number;
96
+ dotProduct(vectors: [Vec2, Vec2] | [Vec3, Vec3] | [Vec4, Vec4]): number;
92
97
  sin(deg: number): number;
93
98
  cos(deg: number): number;
94
99
  tan(deg: number): number;
@@ -195,6 +200,29 @@ declare class Circle extends Sprite {
195
200
  constructor(options?: CircleOptions);
196
201
  }
197
202
 
203
+ interface ArcOptions extends SpriteOptions {
204
+ radius?: number;
205
+ angle?: number;
206
+ color?: string;
207
+ outlineColor?: string;
208
+ outlineWidth?: number;
209
+ }
210
+ declare class Arc extends Sprite {
211
+ discriminant: string;
212
+ radius: number;
213
+ angle: number;
214
+ color: string;
215
+ outlineColor: string;
216
+ outlineWidth: number;
217
+ getBoundingBox(): BoundingBox;
218
+ getPath(): Path2D;
219
+ draw(stamping?: boolean): void;
220
+ setRadius(radius: number): void;
221
+ setAngle(angle: number): void;
222
+ setColor(color: string): void;
223
+ constructor(options?: ArcOptions);
224
+ }
225
+
198
226
  interface RegularPolygonOptions extends SpriteOptions {
199
227
  sides?: number;
200
228
  radius?: number;
@@ -218,6 +246,26 @@ declare class RegularPolygon extends Sprite {
218
246
  constructor(options?: RegularPolygonOptions);
219
247
  }
220
248
 
249
+ interface CustomPolygonOptions extends SpriteOptions {
250
+ vertices?: Vec2[];
251
+ color?: string;
252
+ outlineColor?: string;
253
+ outlineWidth?: number;
254
+ }
255
+ declare class CustomPolygon extends Sprite {
256
+ discriminant: string;
257
+ vertices: Vec2[];
258
+ color: string;
259
+ outlineColor: string;
260
+ outlineWidth: number;
261
+ getBoundingBox(): BoundingBox;
262
+ getPath(): Path2D;
263
+ draw(stamping?: boolean): void;
264
+ setVertices(vertices: Vec2[]): void;
265
+ setColor(color: string): void;
266
+ constructor(options?: CustomPolygonOptions);
267
+ }
268
+
221
269
  interface PenOptions extends SpriteOptions {
222
270
  drawing?: boolean;
223
271
  size?: number;
@@ -308,7 +356,9 @@ declare const TScratch: {
308
356
  Square: typeof Square;
309
357
  Oval: typeof Oval;
310
358
  Circle: typeof Circle;
359
+ Arc: typeof Arc;
311
360
  RegularPolygon: typeof RegularPolygon;
361
+ CustomPolygon: typeof CustomPolygon;
312
362
  Pen: typeof Pen;
313
363
  Text: typeof Text;
314
364
  ImageSprite: typeof ImageSprite;
@@ -318,4 +368,4 @@ declare const TScratch: {
318
368
  ctx: CanvasRenderingContext2D;
319
369
  };
320
370
 
321
- export { type CanvasTextAlign, type CanvasTextBaseline, Circle, type CircleOptions, Engine, ImageSprite, type ImageSpriteOptions, Oval, type OvalOptions, Pen, type PenOptions, Rectangle, type RectangleOptions, RegularPolygon, type RegularPolygonOptions, Sprite, type SpriteOptions, Square, type SquareOptions, Text, type TextOptions, canvas, ctx, TScratch as default, setAspectRatio, setScale };
371
+ export { Arc, type ArcOptions, type CanvasTextAlign, type CanvasTextBaseline, Circle, type CircleOptions, CustomPolygon, type CustomPolygonOptions, Engine, ImageSprite, type ImageSpriteOptions, Oval, type OvalOptions, Pen, type PenOptions, Rectangle, type RectangleOptions, RegularPolygon, type RegularPolygonOptions, Sprite, type SpriteOptions, Square, type SquareOptions, Text, type TextOptions, type Vec2, type Vec3, type Vec4, canvas, ctx, TScratch as default, setAspectRatio, setScale };
package/dist/index.d.ts CHANGED
@@ -48,6 +48,10 @@ declare abstract class Sprite {
48
48
  changeLayer(dL: number): void;
49
49
  }
50
50
 
51
+ type Vec2 = [number, number];
52
+ type Vec3 = [number, number, number];
53
+ type Vec4 = [number, number, number, number];
54
+
51
55
  type GameLoop = (() => any) | (() => Promise<any>);
52
56
  type SceneMap = {
53
57
  [scene: string]: {
@@ -89,6 +93,7 @@ declare class Engine {
89
93
  stopSound(sound: HTMLAudioElement): void;
90
94
  stopAllSounds(): void;
91
95
  pickRandom(min: number, max: number): number;
96
+ dotProduct(vectors: [Vec2, Vec2] | [Vec3, Vec3] | [Vec4, Vec4]): number;
92
97
  sin(deg: number): number;
93
98
  cos(deg: number): number;
94
99
  tan(deg: number): number;
@@ -195,6 +200,29 @@ declare class Circle extends Sprite {
195
200
  constructor(options?: CircleOptions);
196
201
  }
197
202
 
203
+ interface ArcOptions extends SpriteOptions {
204
+ radius?: number;
205
+ angle?: number;
206
+ color?: string;
207
+ outlineColor?: string;
208
+ outlineWidth?: number;
209
+ }
210
+ declare class Arc extends Sprite {
211
+ discriminant: string;
212
+ radius: number;
213
+ angle: number;
214
+ color: string;
215
+ outlineColor: string;
216
+ outlineWidth: number;
217
+ getBoundingBox(): BoundingBox;
218
+ getPath(): Path2D;
219
+ draw(stamping?: boolean): void;
220
+ setRadius(radius: number): void;
221
+ setAngle(angle: number): void;
222
+ setColor(color: string): void;
223
+ constructor(options?: ArcOptions);
224
+ }
225
+
198
226
  interface RegularPolygonOptions extends SpriteOptions {
199
227
  sides?: number;
200
228
  radius?: number;
@@ -218,6 +246,26 @@ declare class RegularPolygon extends Sprite {
218
246
  constructor(options?: RegularPolygonOptions);
219
247
  }
220
248
 
249
+ interface CustomPolygonOptions extends SpriteOptions {
250
+ vertices?: Vec2[];
251
+ color?: string;
252
+ outlineColor?: string;
253
+ outlineWidth?: number;
254
+ }
255
+ declare class CustomPolygon extends Sprite {
256
+ discriminant: string;
257
+ vertices: Vec2[];
258
+ color: string;
259
+ outlineColor: string;
260
+ outlineWidth: number;
261
+ getBoundingBox(): BoundingBox;
262
+ getPath(): Path2D;
263
+ draw(stamping?: boolean): void;
264
+ setVertices(vertices: Vec2[]): void;
265
+ setColor(color: string): void;
266
+ constructor(options?: CustomPolygonOptions);
267
+ }
268
+
221
269
  interface PenOptions extends SpriteOptions {
222
270
  drawing?: boolean;
223
271
  size?: number;
@@ -308,7 +356,9 @@ declare const TScratch: {
308
356
  Square: typeof Square;
309
357
  Oval: typeof Oval;
310
358
  Circle: typeof Circle;
359
+ Arc: typeof Arc;
311
360
  RegularPolygon: typeof RegularPolygon;
361
+ CustomPolygon: typeof CustomPolygon;
312
362
  Pen: typeof Pen;
313
363
  Text: typeof Text;
314
364
  ImageSprite: typeof ImageSprite;
@@ -318,4 +368,4 @@ declare const TScratch: {
318
368
  ctx: CanvasRenderingContext2D;
319
369
  };
320
370
 
321
- export { type CanvasTextAlign, type CanvasTextBaseline, Circle, type CircleOptions, Engine, ImageSprite, type ImageSpriteOptions, Oval, type OvalOptions, Pen, type PenOptions, Rectangle, type RectangleOptions, RegularPolygon, type RegularPolygonOptions, Sprite, type SpriteOptions, Square, type SquareOptions, Text, type TextOptions, canvas, ctx, TScratch as default, setAspectRatio, setScale };
371
+ export { Arc, type ArcOptions, type CanvasTextAlign, type CanvasTextBaseline, Circle, type CircleOptions, CustomPolygon, type CustomPolygonOptions, Engine, ImageSprite, type ImageSpriteOptions, Oval, type OvalOptions, Pen, type PenOptions, Rectangle, type RectangleOptions, RegularPolygon, type RegularPolygonOptions, Sprite, type SpriteOptions, Square, type SquareOptions, Text, type TextOptions, type Vec2, type Vec3, type Vec4, canvas, ctx, TScratch as default, setAspectRatio, setScale };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- var s=document.getElementById("game-window")||document.createElement("canvas"),h=s.getContext("2d"),u=document.createElement("canvas"),o=u.getContext("2d");u.id="pen-canvas";var y=16/9,p;function F(r){p=r,s.width=y*p,s.height=p,u.width=y*p,u.height=p}function X(r){y=r,s.width=y*p,s.height=p,u.width=y*p,u.height=p}s.parentElement?.insertBefore(u,s);F(500);var l=class r{x;y;dir;scene;hidden;layer;cachedPath=null;pathDirty=!0;static collisionCanvas=null;static collisionCtx=null;refresh(){b.init().refresh()}invalidatePath(){this.pathDirty=!0,this.cachedPath=null}getCachedPath(){return(this.pathDirty||!this.cachedPath)&&(this.cachedPath=this.getPath(),this.pathDirty=!1),this.cachedPath}constructor(t){this.x=t?.x??0,this.y=t?.y??0,this.dir=t?.dir??0,this.scene=t?.scene??"main",this.hidden=t?.hidden??!1,this.layer=t?.layer??0,b.init().addSprite(this)}touching(t){let i=this.getBoundingBox(),e=t.getBoundingBox();if(!(Math.abs(i.x-e.x)<(i.width+e.width)/2&&Math.abs(i.y-e.y)<(i.height+e.height)/2))return!1;let a=i.x-i.width/2,m=i.y+i.height/2,f=i.x+i.width/2,x=i.y-i.height/2,L=e.x-e.width/2,W=e.y+e.height/2,Y=e.x+e.width/2,I=e.y-e.height/2,k=Math.max(a,L),T=Math.min(x,I),A=Math.min(f,Y),z=Math.max(m,W),g=A-k,d=z-T;if(g<=1||d<=1)return!1;r.collisionCanvas||(r.collisionCanvas=document.createElement("canvas"),r.collisionCtx=r.collisionCanvas.getContext("2d",{willReadFrequently:!0})),(r.collisionCanvas.width<g||r.collisionCanvas.height<d)&&(r.collisionCanvas.width=Math.max(g,r.collisionCanvas.width),r.collisionCanvas.height=Math.max(d,r.collisionCanvas.height));let c=r.collisionCtx;c.clearRect(0,0,g,d),c.save(),c.translate(this.x-k,d-this.y+T),c.rotate(this.toRadians(this.dir)),c.fillStyle="red",c.fill(this.getCachedPath()),c.restore();let D=c.getImageData(0,0,g,d).data;c.clearRect(0,0,g,d),c.save(),c.translate(t.x-k,d-t.y+T),c.rotate(this.toRadians(t.dir)),c.fillStyle="blue",c.fill(t.getCachedPath()),c.restore();let E=c.getImageData(0,0,g,d).data;for(let R=3;R<D.length;R+=4)if(D[R]>0&&E[R]>0)return!0;return!1}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}move(t){this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.refresh()}turn(t){this.dir+=t,this.refresh()}point(t){this.dir=t,this.refresh()}pointTowards(t,i){this.dir=90-this.toDegrees(Math.atan2(i,t)),this.refresh()}setX(t){this.x=t,this.refresh()}setY(t){this.y=t,this.refresh()}goTo(t,i){this.x=t,this.y=i,this.refresh()}changeX(t){this.x+=t,this.refresh()}changeY(t){this.y+=t,this.refresh()}show(){this.hidden=!1,this.refresh()}hide(){this.hidden=!0,this.refresh()}goToLayer(t){this.layer=t,this.refresh()}changeLayer(t){this.layer+=t,this.refresh()}};var b=class r{static instance;loopRunning=!1;gameLoop=null;maxFPS=24;deltaTime=1/this.maxFPS;lastFrame=performance.now();refreshScheduled=!1;animationFrameId=null;sounds=[];mouseX=0;mouseY=0;mouseDown=!1;mouseClicked=!1;keysPressed=new Set;currentScene="main";sceneMap={};static init(){return this.instance||(this.instance=new r),this.instance}changeScene(t){this.sceneMap[t]||(this.sceneMap[t]={sprites:[],loop:null}),this.loopRunning=!1,this.currentScene=t,this.gameLoop=this.sceneMap[t].loop,this.setMaxFramesPerSecond(this.maxFPS)}setLoop(t,i){if(!this.sceneMap[t]){this.sceneMap[t]={sprites:[],loop:i},t===this.currentScene&&this.changeScene(t);return}this.sceneMap[t].loop=i,t===this.currentScene&&this.changeScene(t)}pauseLoop(){this.loopRunning=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}resumeLoop(){this.loopRunning=!0,this.setMaxFramesPerSecond(this.maxFPS)}addSprite(t){let{scene:i,layer:e}=t;if(!this.sceneMap[i]){this.sceneMap[i]={sprites:[t],loop:null};return}let n=this.sceneMap[i].sprites.findIndex(a=>a.layer>e);if(n===-1){this.sceneMap[i].sprites.push(t);return}this.sceneMap[i].sprites.splice(n,0,t),this.refresh()}removeSprite(t){let{scene:i}=t;this.sceneMap[i]&&(this.sceneMap[i].sprites=this.sceneMap[i].sprites.filter(e=>e!==t),this.refresh())}async setMaxFramesPerSecond(t){this.maxFPS=t;let i=this.gameLoop;if(!i)return;this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.loopRunning=!0;let e=1e3/t,n=0,a=async m=>{if(!this.loopRunning)return;let f=m-this.lastFrame;this.lastFrame=m,n+=f,n>=e&&(this.deltaTime=n/1e3,n=n%e,i&&await i()),this.animationFrameId=requestAnimationFrame(a)};this.lastFrame=performance.now(),this.animationFrameId=requestAnimationFrame(a)}refresh(){this.refreshScheduled||(this.refreshScheduled=!0,requestAnimationFrame(()=>{this.refreshScheduled=!1,h.clearRect(0,0,s.width,s.height),[...this.sceneMap[this.currentScene]?.sprites??[],...this.sceneMap["*"]?.sprites??[]].forEach(i=>{i.hidden||i.draw()})}))}async wait(t){return new Promise(i=>setTimeout(i,t))}async waitUntil(t){return new Promise(i=>{let e=()=>{t()?i():setTimeout(e,1e3/this.maxFPS)};e()})}hovering(t){let{mouseX:i,mouseY:e}=this,n=i+s.width/2,a=s.height/2-e,m=n-(t.x+s.width/2),f=a-(s.height/2-t.y),x=-this.toRadians(t.dir),L=m*Math.cos(x)-f*Math.sin(x),W=m*Math.sin(x)+f*Math.cos(x);return h.isPointInPath(t.getPath(),L,W)}keyPressed(t){return this.keysPressed.has(t)}playSound(t){let i=new Audio(t);return this.sounds.push(i),i.play(),i}stopSound(t){t.pause(),t.currentTime=0,this.sounds=this.sounds.filter(i=>i!==t)}stopAllSounds(){this.sounds.forEach(t=>{t.pause(),t.currentTime=0}),this.sounds=[]}pickRandom(t,i){return t>i&&([t,i]=[i,t]),Math.floor(Math.random()*(i-t+1)+t)}sin(t){return Math.sin(this.toRadians(t))}cos(t){return Math.cos(this.toRadians(t))}tan(t){return Math.tan(this.toRadians(t))}csc(t){return 1/Math.sin(this.toRadians(t))}sec(t){return 1/Math.cos(this.toRadians(t))}cot(t){return 1/Math.tan(this.toRadians(t))}asin(t){return this.toDegrees(Math.asin(t))}acos(t){return this.toDegrees(Math.acos(t))}acsc(t){return this.toDegrees(Math.asin(1/t))}asec(t){return this.toDegrees(Math.acos(1/t))}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}constructor(){this.setMaxFramesPerSecond(24),u.addEventListener("mousemove",t=>{this.mouseX=t.clientX-u.offsetLeft-u.width/2,this.mouseY=-(t.clientY-u.offsetTop-u.height/2)}),u.addEventListener("mousedown",t=>{this.mouseDown=!0}),u.addEventListener("mouseup",t=>{this.mouseDown=!1}),u.addEventListener("click",t=>{this.mouseClicked=!0,setTimeout(()=>this.mouseClicked=!1,0)}),addEventListener("keydown",t=>{t.repeat||this.keysPressed.add(t.key)}),addEventListener("keyup",t=>{this.keysPressed.delete(t.key)})}};var w=class extends l{discriminant="rectangle";width;height;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.width,this.height),height:Math.hypot(this.width,this.height)}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.width=t?.width??50,this.height=t?.height??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var v=class extends l{discriminant="square";sideLength;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.sideLength,this.sideLength),height:Math.hypot(this.sideLength,this.sideLength)}}getPath(){let t=new Path2D;return t.rect(-this.sideLength/2,-this.sideLength/2,this.sideLength,this.sideLength),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setSideLength(t){this.sideLength=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sideLength=t?.sideLength??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var S=class extends l{discriminant="circle";radX;radY;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.radX*2,this.radY*2),height:Math.hypot(this.radX*2,this.radY*2)}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radX,this.radY,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setRadX(t){this.radX=t,this.invalidatePath(),this.refresh()}setRadY(t){this.radY=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radX=t?.radX??25,this.radY=t?.radY??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var P=class extends l{discriminant="circle";radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radius,this.radius,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var C=class extends l{discriminant="regularpolygon";sides;radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D,i=2*Math.PI/this.sides;t.moveTo(this.radius,0);for(let e=1;e<this.sides;e++)t.lineTo(this.radius*Math.cos(i*e),this.radius*Math.sin(i*e));return t.closePath(),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let a=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(a),this.outlineWidth&&i.stroke(a),i.restore()}setSides(t){this.sides=t,this.invalidatePath(),this.refresh()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sides=t?.sides??5,this.radius=t?.radius??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var B=class extends l{discriminant="pen";drawing;size;color;getBoundingBox(){return{x:this.x,y:this.y,width:this.size,height:this.size}}getPath(){return new Path2D}draw(){}up(){this.drawing=!1}down(){this.drawing=!0}stamp(t){t.draw(!0)}eraseAll(){o.clearRect(0,0,s.width,s.height)}dot(){o.fillStyle=this.color,o.fillRect(this.x-this.size/2+s.width/2,-this.y-this.size/2+s.height/2,this.size,this.size)}drawLine(t,i){o.beginPath(),o.moveTo(t+s.width/2,-i+s.height/2),o.lineTo(this.x+s.width/2,-this.y+s.height/2),o.lineWidth=this.size,o.strokeStyle=this.color,o.stroke()}move(t){let i=this.x,e=this.y;this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.drawing&&this.drawLine(i,e),this.refresh()}setX(t){let i=this.x,e=this.y;this.x=t,this.drawing&&this.drawLine(i,e),this.refresh()}setY(t){let i=this.x,e=this.y;this.y=t,this.drawing&&this.drawLine(i,e),this.refresh()}goTo(t,i){let e=this.x,n=this.y;this.x=t,this.y=i,this.drawing&&this.drawLine(e,n),this.refresh()}changeX(t){let i=this.x,e=this.y;this.x+=t,this.drawing&&this.drawLine(i,e),this.refresh()}changeY(t){let i=this.x,e=this.y;this.y+=t,this.drawing&&this.drawLine(i,e),this.refresh()}constructor(t){super(t),this.drawing=t?.drawing??!1,this.size=t?.size??5,this.color=t?.color??"black"}};var M=class extends l{discriminant="text";content;color;fontFamily;fontSize;align;baseline;font;getBoundingBox(){let t=h.measureText(this.content),i=t.width,e=t.actualBoundingBoxAscent+t.actualBoundingBoxDescent;return{x:this.x,y:this.y,width:i,height:e}}getPath(){let t=new Path2D;h.save(),h.font=this.font;let i=h.measureText(this.content),e=i.width,n=i.actualBoundingBoxAscent+i.actualBoundingBoxDescent;return h.restore(),t.rect(-e/2,-n/2,e,n),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.font=this.font,i.fillStyle=this.color,i.textAlign=this.align,i.textBaseline=this.baseline,i.fillText(this.content,0,0),i.restore()}setContent(t){this.content=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}setFontSize(t){this.fontSize=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setFontFamily(t){this.fontFamily=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setAlign(t){this.align=t,this.invalidatePath(),this.refresh()}setBaseline(t){this.baseline=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.content=t?.content??"",this.color=t?.color??"black",this.fontFamily=t?.fontFamily??"Arial",this.fontSize=t?.fontSize??16,this.align=t?.align??"center",this.baseline=t?.baseline??"middle",this.font=`${this.fontSize}px ${this.fontFamily}`,this.draw()}};var O=class extends l{discriminant="imagesprite";src;width;height;outlineColor;outlineWidth;img;getBoundingBox(){return{x:this.x,y:this.y,width:this.width,height:this.height}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height),this.outlineWidth&&i.stroke(this.getCachedPath()),i.restore()}setSrc(t){this.src=t,this.refresh()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.src=t?.src??"",this.img=new Image,this.img.src=this.src,this.width=t?.width??this.img.width,this.height=t?.height??this.img.height,this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var q={Engine:b,Sprite:l,Rectangle:w,Square:v,Oval:S,Circle:P,RegularPolygon:C,Pen:B,Text:M,ImageSprite:O,setScale:F,setAspectRatio:X,canvas:s,ctx:h},Wt=q;export{P as Circle,b as Engine,O as ImageSprite,S as Oval,B as Pen,w as Rectangle,C as RegularPolygon,l as Sprite,v as Square,M as Text,s as canvas,h as ctx,Wt as default,X as setAspectRatio,F as setScale};
1
+ var s=document.getElementById("game-window")||document.createElement("canvas"),h=s.getContext("2d"),u=document.createElement("canvas"),o=u.getContext("2d");u.id="pen-canvas";var y=16/9,p;function X(a){p=a,s.width=y*p,s.height=p,u.width=y*p,u.height=p}function I(a){y=a,s.width=y*p,s.height=p,u.width=y*p,u.height=p}s.parentElement?.insertBefore(u,s);X(500);var l=class a{x;y;dir;scene;hidden;layer;cachedPath=null;pathDirty=!0;static collisionCanvas=null;static collisionCtx=null;refresh(){b.init().refresh()}invalidatePath(){this.pathDirty=!0,this.cachedPath=null}getCachedPath(){return(this.pathDirty||!this.cachedPath)&&(this.cachedPath=this.getPath(),this.pathDirty=!1),this.cachedPath}constructor(t){this.x=t?.x??0,this.y=t?.y??0,this.dir=t?.dir??0,this.scene=t?.scene??"main",this.hidden=t?.hidden??!1,this.layer=t?.layer??0,b.init().addSprite(this)}touching(t){let i=this.getBoundingBox(),e=t.getBoundingBox();if(!(Math.abs(i.x-e.x)<(i.width+e.width)/2&&Math.abs(i.y-e.y)<(i.height+e.height)/2))return!1;let r=i.x-i.width/2,m=i.y+i.height/2,f=i.x+i.width/2,x=i.y-i.height/2,L=e.x-e.width/2,T=e.y+e.height/2,A=e.x+e.width/2,V=e.y-e.height/2,D=Math.max(r,L),F=Math.min(x,V),z=Math.min(f,A),E=Math.max(m,T),g=z-D,d=E-F;if(g<=1||d<=1)return!1;a.collisionCanvas||(a.collisionCanvas=document.createElement("canvas"),a.collisionCtx=a.collisionCanvas.getContext("2d",{willReadFrequently:!0})),(a.collisionCanvas.width<g||a.collisionCanvas.height<d)&&(a.collisionCanvas.width=Math.max(g,a.collisionCanvas.width),a.collisionCanvas.height=Math.max(d,a.collisionCanvas.height));let c=a.collisionCtx;c.clearRect(0,0,g,d),c.save(),c.translate(this.x-D,d-this.y+F),c.rotate(this.toRadians(this.dir)),c.fillStyle="red",c.fill(this.getCachedPath()),c.restore();let Y=c.getImageData(0,0,g,d).data;c.clearRect(0,0,g,d),c.save(),c.translate(t.x-D,d-t.y+F),c.rotate(this.toRadians(t.dir)),c.fillStyle="blue",c.fill(t.getCachedPath()),c.restore();let q=c.getImageData(0,0,g,d).data;for(let k=3;k<Y.length;k+=4)if(Y[k]>0&&q[k]>0)return!0;return!1}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}move(t){this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.refresh()}turn(t){this.dir+=t,this.refresh()}point(t){this.dir=t,this.refresh()}pointTowards(t,i){this.dir=90-this.toDegrees(Math.atan2(i,t)),this.refresh()}setX(t){this.x=t,this.refresh()}setY(t){this.y=t,this.refresh()}goTo(t,i){this.x=t,this.y=i,this.refresh()}changeX(t){this.x+=t,this.refresh()}changeY(t){this.y+=t,this.refresh()}show(){this.hidden=!1,this.refresh()}hide(){this.hidden=!0,this.refresh()}goToLayer(t){this.layer=t,this.refresh()}changeLayer(t){this.layer+=t,this.refresh()}};var b=class a{static instance;loopRunning=!1;gameLoop=null;maxFPS=24;deltaTime=1/this.maxFPS;lastFrame=performance.now();refreshScheduled=!1;animationFrameId=null;sounds=[];mouseX=0;mouseY=0;mouseDown=!1;mouseClicked=!1;keysPressed=new Set;currentScene="main";sceneMap={};static init(){return this.instance||(this.instance=new a),this.instance}changeScene(t){this.sceneMap[t]||(this.sceneMap[t]={sprites:[],loop:null}),this.loopRunning=!1,this.currentScene=t,this.gameLoop=this.sceneMap[t].loop,this.setMaxFramesPerSecond(this.maxFPS)}setLoop(t,i){if(!this.sceneMap[t]){this.sceneMap[t]={sprites:[],loop:i},t===this.currentScene&&this.changeScene(t);return}this.sceneMap[t].loop=i,t===this.currentScene&&this.changeScene(t)}pauseLoop(){this.loopRunning=!1,this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}resumeLoop(){this.loopRunning=!0,this.setMaxFramesPerSecond(this.maxFPS)}addSprite(t){let{scene:i,layer:e}=t;if(!this.sceneMap[i]){this.sceneMap[i]={sprites:[t],loop:null};return}let n=this.sceneMap[i].sprites.findIndex(r=>r.layer>e);if(n===-1){this.sceneMap[i].sprites.push(t);return}this.sceneMap[i].sprites.splice(n,0,t),this.refresh()}removeSprite(t){let{scene:i}=t;this.sceneMap[i]&&(this.sceneMap[i].sprites=this.sceneMap[i].sprites.filter(e=>e!==t),this.refresh())}async setMaxFramesPerSecond(t){this.maxFPS=t;let i=this.gameLoop;if(!i)return;this.animationFrameId!==null&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.loopRunning=!0;let e=1e3/t,n=0,r=async m=>{if(!this.loopRunning)return;let f=m-this.lastFrame;this.lastFrame=m,n+=f,n>=e&&(this.deltaTime=n/1e3,n=n%e,i&&await i()),this.animationFrameId=requestAnimationFrame(r)};this.lastFrame=performance.now(),this.animationFrameId=requestAnimationFrame(r)}refresh(){this.refreshScheduled||(this.refreshScheduled=!0,requestAnimationFrame(()=>{this.refreshScheduled=!1,h.clearRect(0,0,s.width,s.height),[...this.sceneMap[this.currentScene]?.sprites??[],...this.sceneMap["*"]?.sprites??[]].forEach(i=>{i.hidden||i.draw()})}))}async wait(t){return new Promise(i=>setTimeout(i,t))}async waitUntil(t){return new Promise(i=>{let e=()=>{t()?i():setTimeout(e,1e3/this.maxFPS)};e()})}hovering(t){let{mouseX:i,mouseY:e}=this,n=i+s.width/2,r=s.height/2-e,m=n-(t.x+s.width/2),f=r-(s.height/2-t.y),x=-this.toRadians(t.dir),L=m*Math.cos(x)-f*Math.sin(x),T=m*Math.sin(x)+f*Math.cos(x);return h.isPointInPath(t.getPath(),L,T)}keyPressed(t){return this.keysPressed.has(t)}playSound(t){let i=new Audio(t);return this.sounds.push(i),i.play(),i}stopSound(t){t.pause(),t.currentTime=0,this.sounds=this.sounds.filter(i=>i!==t)}stopAllSounds(){this.sounds.forEach(t=>{t.pause(),t.currentTime=0}),this.sounds=[]}pickRandom(t,i){return t>i&&([t,i]=[i,t]),Math.floor(Math.random()*(i-t+1)+t)}dotProduct(t){let[i,e]=t;switch(i.length){case 2:return i[0]*e[0]+i[1]*e[1];case 3:return i[0]*e[0]+i[1]*e[1]+i[2]*e[2];case 4:return i[0]*e[0]+i[1]*e[1]+i[2]*e[2]+i[3]*e[3]}}sin(t){return Math.sin(this.toRadians(t))}cos(t){return Math.cos(this.toRadians(t))}tan(t){return Math.tan(this.toRadians(t))}csc(t){return 1/Math.sin(this.toRadians(t))}sec(t){return 1/Math.cos(this.toRadians(t))}cot(t){return 1/Math.tan(this.toRadians(t))}asin(t){return this.toDegrees(Math.asin(t))}acos(t){return this.toDegrees(Math.acos(t))}acsc(t){return this.toDegrees(Math.asin(1/t))}asec(t){return this.toDegrees(Math.acos(1/t))}toRadians(t){return t*Math.PI/180}toDegrees(t){return t*180/Math.PI}constructor(){this.setMaxFramesPerSecond(24),u.addEventListener("mousemove",t=>{this.mouseX=t.clientX-u.offsetLeft-u.width/2,this.mouseY=-(t.clientY-u.offsetTop-u.height/2)}),u.addEventListener("mousedown",t=>{this.mouseDown=!0}),u.addEventListener("mouseup",t=>{this.mouseDown=!1}),u.addEventListener("click",t=>{this.mouseClicked=!0,setTimeout(()=>this.mouseClicked=!1,0)}),addEventListener("keydown",t=>{t.repeat||this.keysPressed.add(t.key)}),addEventListener("keyup",t=>{this.keysPressed.delete(t.key)})}};var w=class extends l{discriminant="rectangle";width;height;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.width,this.height),height:Math.hypot(this.width,this.height)}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.width=t?.width??50,this.height=t?.height??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var v=class extends l{discriminant="square";sideLength;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.sideLength,this.sideLength),height:Math.hypot(this.sideLength,this.sideLength)}}getPath(){let t=new Path2D;return t.rect(-this.sideLength/2,-this.sideLength/2,this.sideLength,this.sideLength),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setSideLength(t){this.sideLength=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sideLength=t?.sideLength??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var C=class extends l{discriminant="oval";radX;radY;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:Math.hypot(this.radX*2,this.radY*2),height:Math.hypot(this.radX*2,this.radY*2)}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radX,this.radY,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setRadX(t){this.radX=t,this.invalidatePath(),this.refresh()}setRadY(t){this.radY=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radX=t?.radX??25,this.radY=t?.radY??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var S=class extends l{discriminant="circle";radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.ellipse(0,0,this.radius,this.radius,0,0,Math.PI*2),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var P=class extends l{discriminant="arc";radius;angle;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D;return t.arc(0,0,this.radius,this.toRadians(this.angle/2-90),this.toRadians(-this.angle/2-90)),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setAngle(t){this.angle=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.radius=t?.radius??25,this.angle=t?.angle??270,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var B=class extends l{discriminant="regularpolygon";sides;radius;color;outlineColor;outlineWidth;getBoundingBox(){return{x:this.x,y:this.y,width:this.radius*2,height:this.radius*2}}getPath(){let t=new Path2D,i=2*Math.PI/this.sides;t.moveTo(this.radius,0);for(let e=1;e<this.sides;e++)t.lineTo(this.radius*Math.cos(i*e),this.radius*Math.sin(i*e));return t.closePath(),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setSides(t){this.sides=t,this.invalidatePath(),this.refresh()}setRadius(t){this.radius=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.sides=t?.sides??5,this.radius=t?.radius??50,this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var M=class extends l{discriminant="custompolygon";vertices;color;outlineColor;outlineWidth;getBoundingBox(){let t=0;for(let i of this.vertices){let e=Math.hypot(i[0],i[1]);e>t&&(t=e)}return{x:this.x,y:this.y,width:t,height:t}}getPath(){let t=new Path2D,i=this.vertices;if(i.length<2)return t;t.moveTo(i[0][0],i[0][1]);for(let e=1;e<i.length;e++)t.lineTo(i[e][0],i[e][1]);return t.closePath(),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir));let r=this.getCachedPath();i.fillStyle=this.color,i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.fill(r),this.outlineWidth&&i.stroke(r),i.restore()}setVertices(t){this.vertices=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}constructor(t){super(t),this.vertices=t?.vertices??[],this.color=t?.color??"black",this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var O=class extends l{discriminant="pen";drawing;size;color;getBoundingBox(){return{x:this.x,y:this.y,width:this.size,height:this.size}}getPath(){return new Path2D}draw(){}up(){this.drawing=!1}down(){this.drawing=!0}stamp(t){t.draw(!0)}eraseAll(){o.clearRect(0,0,s.width,s.height)}dot(){o.fillStyle=this.color,o.fillRect(this.x-this.size/2+s.width/2,-this.y-this.size/2+s.height/2,this.size,this.size)}drawLine(t,i){o.beginPath(),o.moveTo(t+s.width/2,-i+s.height/2),o.lineTo(this.x+s.width/2,-this.y+s.height/2),o.lineWidth=this.size,o.strokeStyle=this.color,o.stroke()}move(t){let i=this.x,e=this.y;this.x+=t*Math.sin(this.toRadians(this.dir)),this.y+=t*Math.cos(this.toRadians(this.dir)),this.drawing&&this.drawLine(i,e),this.refresh()}setX(t){let i=this.x,e=this.y;this.x=t,this.drawing&&this.drawLine(i,e),this.refresh()}setY(t){let i=this.x,e=this.y;this.y=t,this.drawing&&this.drawLine(i,e),this.refresh()}goTo(t,i){let e=this.x,n=this.y;this.x=t,this.y=i,this.drawing&&this.drawLine(e,n),this.refresh()}changeX(t){let i=this.x,e=this.y;this.x+=t,this.drawing&&this.drawLine(i,e),this.refresh()}changeY(t){let i=this.x,e=this.y;this.y+=t,this.drawing&&this.drawLine(i,e),this.refresh()}constructor(t){super(t),this.drawing=t?.drawing??!1,this.size=t?.size??5,this.color=t?.color??"black"}};var W=class extends l{discriminant="text";content;color;fontFamily;fontSize;align;baseline;font;getBoundingBox(){let t=h.measureText(this.content),i=t.width,e=t.actualBoundingBoxAscent+t.actualBoundingBoxDescent;return{x:this.x,y:this.y,width:i,height:e}}getPath(){let t=new Path2D;h.save(),h.font=this.font;let i=h.measureText(this.content),e=i.width,n=i.actualBoundingBoxAscent+i.actualBoundingBoxDescent;return h.restore(),t.rect(-e/2,-n/2,e,n),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.font=this.font,i.fillStyle=this.color,i.textAlign=this.align,i.textBaseline=this.baseline,i.fillText(this.content,0,0),i.restore()}setContent(t){this.content=t,this.invalidatePath(),this.refresh()}setColor(t){this.color=t,this.refresh()}setFontSize(t){this.fontSize=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setFontFamily(t){this.fontFamily=t,this.font=`${this.fontSize}px ${this.fontFamily}`,this.invalidatePath(),this.refresh()}setAlign(t){this.align=t,this.invalidatePath(),this.refresh()}setBaseline(t){this.baseline=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.content=t?.content??"",this.color=t?.color??"black",this.fontFamily=t?.fontFamily??"Arial",this.fontSize=t?.fontSize??16,this.align=t?.align??"center",this.baseline=t?.baseline??"middle",this.font=`${this.fontSize}px ${this.fontFamily}`,this.draw()}};var R=class extends l{discriminant="imagesprite";src;width;height;outlineColor;outlineWidth;img;getBoundingBox(){return{x:this.x,y:this.y,width:this.width,height:this.height}}getPath(){let t=new Path2D;return t.rect(-this.width/2,-this.height/2,this.width,this.height),t}draw(t){let i=t?o:h;i.save();let e=this.x+s.width/2,n=-this.y+s.height/2;i.translate(e,n),i.rotate(this.toRadians(this.dir)),i.strokeStyle=this.outlineColor,i.lineWidth=this.outlineWidth,i.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height),this.outlineWidth&&i.stroke(this.getCachedPath()),i.restore()}setSrc(t){this.src=t,this.refresh()}setWidth(t){this.width=t,this.invalidatePath(),this.refresh()}setHeight(t){this.height=t,this.invalidatePath(),this.refresh()}constructor(t){super(t),this.src=t?.src??"",this.img=new Image,this.img.src=this.src,this.width=t?.width??this.img.width,this.height=t?.height??this.img.height,this.outlineColor=t?.outlineColor??"black",this.outlineWidth=t?.outlineWidth??0,this.draw()}};var H={Engine:b,Sprite:l,Rectangle:w,Square:v,Oval:C,Circle:S,Arc:P,RegularPolygon:B,CustomPolygon:M,Pen:O,Text:W,ImageSprite:R,setScale:X,setAspectRatio:I,canvas:s,ctx:h},zt=H;export{P as Arc,S as Circle,M as CustomPolygon,b as Engine,R as ImageSprite,C as Oval,O as Pen,w as Rectangle,B as RegularPolygon,l as Sprite,v as Square,W as Text,s as canvas,h as ctx,zt as default,I as setAspectRatio,X as setScale};
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/canvas.ts","../src/Sprite.ts","../src/Engine.ts","../src/sprites/Rectangle.ts","../src/sprites/Square.ts","../src/sprites/Oval.ts","../src/sprites/Circle.ts","../src/sprites/RegularPolygon.ts","../src/sprites/Pen.ts","../src/sprites/Text.ts","../src/sprites/ImageSprite.ts","../src/index.ts"],"sourcesContent":["export const canvas = document.getElementById('game-window') as HTMLCanvasElement || document.createElement('canvas'); // For testing\r\nexport const ctx = canvas.getContext('2d')!;\r\n\r\nexport const penCanvas = document.createElement('canvas');\r\nexport const penCtx = penCanvas.getContext('2d')!;\r\npenCanvas.id = 'pen-canvas';\r\n\r\nlet ratio: number = 16 / 9;\r\nlet scale: number;\r\n\r\nexport function setScale(newScale: number) {\r\n scale = newScale;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\nexport function setAspectRatio(newAspectRatio: number) {\r\n ratio = newAspectRatio;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\ncanvas.parentElement?.insertBefore(penCanvas, canvas);\r\n\r\nsetScale(500);","import Engine from './Engine.ts';\r\n\r\nexport interface BoundingBox {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface SpriteOptions {\r\n x?: number;\r\n y?: number;\r\n dir?: number;\r\n scene?: string;\r\n hidden?: boolean;\r\n layer?: number;\r\n}\r\n\r\nexport default abstract class Sprite {\r\n\r\n public x: number;\r\n public y: number;\r\n public dir: number;\r\n public scene: string;\r\n public hidden: boolean;\r\n public layer: number;\r\n\r\n private cachedPath: Path2D | null = null;\r\n private pathDirty: boolean = true;\r\n\r\n // Reusable collision detection canvas\r\n private static collisionCanvas: HTMLCanvasElement | null = null;\r\n private static collisionCtx: CanvasRenderingContext2D | null = null;\r\n\r\n // Rendering\r\n\r\n public abstract getBoundingBox(): BoundingBox;\r\n public abstract getPath(): Path2D;\r\n public abstract draw(stamping?: boolean): void;\r\n\r\n protected refresh() {\r\n Engine.init().refresh();\r\n }\r\n\r\n protected invalidatePath() {\r\n this.pathDirty = true;\r\n this.cachedPath = null;\r\n }\r\n\r\n protected getCachedPath(): Path2D {\r\n if (this.pathDirty || !this.cachedPath) {\r\n this.cachedPath = this.getPath();\r\n this.pathDirty = false;\r\n }\r\n return this.cachedPath;\r\n }\r\n\r\n constructor(options?: SpriteOptions) {\r\n this.x = options?.x ?? 0;\r\n this.y = options?.y ?? 0;\r\n this.dir = options?.dir ?? 0;\r\n this.scene = options?.scene ?? 'main';\r\n this.hidden = options?.hidden ?? false;\r\n this.layer = options?.layer ?? 0;\r\n Engine.init().addSprite(this);\r\n }\r\n\r\n // Sensing\r\n\r\n public touching(sprite: Sprite): boolean {\r\n\r\n // AABB (bounding boxes)\r\n const bBox1 = this.getBoundingBox();\r\n const bBox2 = sprite.getBoundingBox();\r\n\r\n const aabbOverlap =\r\n Math.abs(bBox1.x - bBox2.x) < (bBox1.width + bBox2.width) / 2 &&\r\n Math.abs(bBox1.y - bBox2.y) < (bBox1.height + bBox2.height) / 2;\r\n\r\n if (!aabbOverlap) return false;\r\n\r\n // Image data (pixel perfect)\r\n\r\n // Compute intersection bounding box\r\n const b1Left = bBox1.x - bBox1.width / 2;\r\n const b1Top = bBox1.y + bBox1.height / 2;\r\n const b1Right = bBox1.x + bBox1.width / 2;\r\n const b1Bottom = bBox1.y - bBox1.height / 2;\r\n\r\n const b2Left = bBox2.x - bBox2.width / 2;\r\n const b2Top = bBox2.y + bBox2.height / 2;\r\n const b2Right = bBox2.x + bBox2.width / 2;\r\n const b2Bottom = bBox2.y - bBox2.height / 2;\r\n\r\n const xMin = Math.max(b1Left, b2Left);\r\n const yMin = Math.min(b1Bottom, b2Bottom);\r\n const xMax = Math.min(b1Right, b2Right);\r\n const yMax = Math.max(b1Top, b2Top);\r\n\r\n const width = xMax - xMin;\r\n const height = yMax - yMin;\r\n\r\n if (width <= 1 || height <= 1) return false;\r\n\r\n // Reuse or create offscreen canvas for collision detection\r\n if (!Sprite.collisionCanvas) {\r\n Sprite.collisionCanvas = document.createElement('canvas');\r\n Sprite.collisionCtx = Sprite.collisionCanvas.getContext('2d', { willReadFrequently: true })!;\r\n }\r\n\r\n // Resize if needed\r\n if (Sprite.collisionCanvas.width < width || Sprite.collisionCanvas.height < height) {\r\n Sprite.collisionCanvas.width = Math.max(width, Sprite.collisionCanvas.width);\r\n Sprite.collisionCanvas.height = Math.max(height, Sprite.collisionCanvas.height);\r\n }\r\n\r\n const ctx = Sprite.collisionCtx!;\r\n ctx.clearRect(0, 0, width, height);\r\n\r\n // Draw first sprite\r\n ctx.save();\r\n ctx.translate(this.x - xMin, height - this.y + yMin);\r\n ctx.rotate(this.toRadians(this.dir));\r\n ctx.fillStyle = 'red';\r\n ctx.fill(this.getCachedPath());\r\n ctx.restore();\r\n const img1 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Draw second sprite\r\n ctx.clearRect(0, 0, width, height);\r\n ctx.save();\r\n ctx.translate(sprite.x - xMin, height - sprite.y + yMin);\r\n ctx.rotate(this.toRadians(sprite.dir));\r\n ctx.fillStyle = 'blue';\r\n ctx.fill(sprite.getCachedPath());\r\n ctx.restore();\r\n const img2 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Check for overlapping non-transparent pixels\r\n for (let i = 3; i < img1.length; i += 4) // alpha channel\r\n if (img1[i]! > 0 && img2[i]! > 0) return true;\r\n\r\n return false;\r\n }\r\n\r\n // Helpers\r\n\r\n protected toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n protected toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Methods\r\n\r\n // Motion\r\n public move(steps: number) {\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n this.refresh();\r\n }\r\n\r\n public turn(deg: number) {\r\n this.dir += deg;\r\n this.refresh();\r\n }\r\n\r\n public point(dir: number) {\r\n this.dir = dir;\r\n this.refresh();\r\n }\r\n\r\n public pointTowards(x: number, y: number) {\r\n this.dir = 90 - this.toDegrees(Math.atan2(y, x));\r\n this.refresh();\r\n }\r\n\r\n public setX(x: number) {\r\n this.x = x;\r\n this.refresh();\r\n }\r\n\r\n public setY(y: number) {\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public goTo(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public changeX(dX: number) {\r\n this.x += dX;\r\n this.refresh();\r\n }\r\n\r\n public changeY(dY: number) {\r\n this.y += dY;\r\n this.refresh();\r\n }\r\n\r\n // Looks\r\n\r\n public show() {\r\n this.hidden = false;\r\n this.refresh();\r\n }\r\n\r\n public hide() {\r\n this.hidden = true;\r\n this.refresh();\r\n }\r\n\r\n public goToLayer(layer: number) {\r\n this.layer = layer;\r\n this.refresh();\r\n }\r\n\r\n public changeLayer(dL: number) {\r\n this.layer += dL;\r\n this.refresh();\r\n }\r\n}","import { canvas, ctx, penCanvas } from './canvas.ts';\r\nimport Sprite from './Sprite.ts';\r\n\r\ntype GameLoop = (() => any) | (() => Promise<any>);\r\n\r\ntype SceneMap = {\r\n [scene: string]: {\r\n sprites: Sprite[];\r\n loop: GameLoop | null;\r\n };\r\n};\r\n\r\nexport default class Engine {\r\n\r\n private static instance: Engine;\r\n\r\n private loopRunning: boolean = false;\r\n public gameLoop: GameLoop | null = null;\r\n\r\n public maxFPS: number = 24;\r\n public deltaTime: number = 1 / this.maxFPS;\r\n private lastFrame: number = performance.now();\r\n private refreshScheduled: boolean = false;\r\n private animationFrameId: number | null = null;\r\n\r\n public sounds: HTMLAudioElement[] = [];\r\n\r\n public mouseX: number = 0;\r\n public mouseY: number = 0;\r\n\r\n public mouseDown: boolean = false;\r\n public mouseClicked: boolean = false;\r\n\r\n private keysPressed: Set<string> = new Set<string>();\r\n\r\n public currentScene: string = 'main';\r\n public sceneMap: SceneMap = {};\r\n\r\n // Singleton initialization\r\n\r\n public static init() {\r\n if (!this.instance)\r\n this.instance = new Engine();\r\n\r\n return this.instance;\r\n }\r\n\r\n // Change the scene\r\n\r\n public changeScene(scene: string) {\r\n if (!this.sceneMap[scene])\r\n this.sceneMap[scene] = { sprites: [], loop: null };\r\n\r\n this.loopRunning = false;\r\n this.currentScene = scene;\r\n this.gameLoop = this.sceneMap[scene].loop;\r\n this.setMaxFramesPerSecond(this.maxFPS); // Update the interval function\r\n }\r\n\r\n // Loops\r\n\r\n public setLoop(scene: string, loop: GameLoop) {\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [], loop };\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].loop = loop;\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n }\r\n\r\n public pauseLoop() {\r\n this.loopRunning = false;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n }\r\n\r\n public resumeLoop() {\r\n this.loopRunning = true;\r\n void this.setMaxFramesPerSecond(this.maxFPS);\r\n }\r\n\r\n // Internal\r\n\r\n public addSprite(sprite: Sprite) {\r\n const { scene, layer } = sprite;\r\n\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [sprite], loop: null };\r\n return;\r\n }\r\n\r\n let targetIndex = this.sceneMap[scene].sprites.findIndex(s => s.layer > layer);\r\n if (targetIndex === -1) {\r\n this.sceneMap[scene].sprites.push(sprite);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].sprites.splice(targetIndex, 0, sprite);\r\n this.refresh();\r\n }\r\n\r\n public removeSprite(sprite: Sprite) {\r\n const { scene } = sprite;\r\n\r\n if (!this.sceneMap[scene]) return;\r\n\r\n this.sceneMap[scene].sprites = this.sceneMap[scene].sprites.filter(s => s !== sprite);\r\n this.refresh();\r\n }\r\n\r\n public async setMaxFramesPerSecond(maxFPS: number) {\r\n this.maxFPS = maxFPS;\r\n\r\n let loop = this.gameLoop;\r\n if (!loop) return;\r\n\r\n // Cancel existing animation frame if any\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n\r\n this.loopRunning = true;\r\n const frameInterval = 1000 / maxFPS;\r\n let accumulator = 0;\r\n\r\n const tick = async (currentTime: number) => {\r\n if (!this.loopRunning) return;\r\n\r\n const deltaTime = currentTime - this.lastFrame;\r\n this.lastFrame = currentTime;\r\n accumulator += deltaTime;\r\n\r\n // Fixed timestep: only run loop when enough time has passed\r\n if (accumulator >= frameInterval) {\r\n this.deltaTime = accumulator / 1000;\r\n accumulator = accumulator % frameInterval;\r\n\r\n if (loop) await loop();\r\n }\r\n\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n };\r\n\r\n this.lastFrame = performance.now();\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n }\r\n\r\n public refresh() {\r\n if (this.refreshScheduled) return;\r\n this.refreshScheduled = true;\r\n\r\n requestAnimationFrame(() => {\r\n this.refreshScheduled = false;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n const sprites = [\r\n ...(this.sceneMap[this.currentScene]?.sprites ?? []),\r\n ...(this.sceneMap['*']?.sprites ?? [])\r\n ];\r\n sprites.forEach(sprite => {\r\n if (!sprite.hidden)\r\n sprite.draw();\r\n });\r\n });\r\n }\r\n\r\n // Wait functions\r\n\r\n public async wait(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n\r\n public async waitUntil(conditionGetter: () => boolean): Promise<void> {\r\n return new Promise(resolve => {\r\n const check = () => {\r\n if (conditionGetter()) resolve();\r\n else setTimeout(check, 1000 / this.maxFPS);\r\n }\r\n check();\r\n });\r\n }\r\n\r\n // Events\r\n\r\n public hovering(sprite: Sprite) {\r\n const { mouseX, mouseY } = this;\r\n\r\n const canvasMouseX = mouseX + canvas.width / 2;\r\n const canvasMouseY = canvas.height / 2 - mouseY;\r\n\r\n // Mouse relative to sprite center\r\n const localX = canvasMouseX - (sprite.x + canvas.width / 2);\r\n const localY = canvasMouseY - (canvas.height / 2 - sprite.y);\r\n\r\n // Rotate mouse point by -dir to align with the path's local coordinates\r\n const angle = -this.toRadians(sprite.dir);\r\n const rotatedX = localX * Math.cos(angle) - localY * Math.sin(angle);\r\n const rotatedY = localX * Math.sin(angle) + localY * Math.cos(angle);\r\n\r\n return ctx.isPointInPath(sprite.getPath(), rotatedX, rotatedY);\r\n }\r\n\r\n public keyPressed(key: string) {\r\n return this.keysPressed.has(key);\r\n }\r\n\r\n // Sound\r\n\r\n public playSound(src: string) {\r\n const audio = new Audio(src);\r\n this.sounds.push(audio);\r\n\r\n audio.play();\r\n\r\n return audio;\r\n }\r\n\r\n public stopSound(sound: HTMLAudioElement) {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n this.sounds = this.sounds.filter(s => s !== sound);\r\n }\r\n\r\n public stopAllSounds() {\r\n this.sounds.forEach(sound => {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n });\r\n this.sounds = [];\r\n }\r\n\r\n // Math\r\n\r\n public pickRandom(min: number, max: number) {\r\n if (min > max)\r\n [min, max] = [max, min];\r\n return Math.floor(Math.random() * (max - min + 1) + min);\r\n }\r\n\r\n // Trigonometric functions\r\n public sin(deg: number) {\r\n return Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public cos(deg: number) {\r\n return Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public tan(deg: number) {\r\n return Math.tan(this.toRadians(deg));\r\n }\r\n\r\n public csc(deg: number) {\r\n return 1 / Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public sec(deg: number) {\r\n return 1 / Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public cot(deg: number) {\r\n return 1 / Math.tan(this.toRadians(deg));\r\n }\r\n\r\n // Inverse Trigonometric functions\r\n public asin(val: number) {\r\n return this.toDegrees(Math.asin(val));\r\n }\r\n\r\n public acos(val: number) {\r\n return this.toDegrees(Math.acos(val));\r\n }\r\n\r\n public acsc(val: number) {\r\n return this.toDegrees(Math.asin(1 / val));\r\n }\r\n\r\n public asec(val: number) {\r\n return this.toDegrees(Math.acos(1 / val));\r\n }\r\n\r\n // Helpers\r\n\r\n public toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n public toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Private constructor\r\n\r\n private constructor() {\r\n void this.setMaxFramesPerSecond(24);\r\n\r\n // Events\r\n\r\n // Mouse\r\n penCanvas.addEventListener('mousemove', e => {\r\n this.mouseX = e.clientX - penCanvas.offsetLeft - penCanvas.width / 2;\r\n this.mouseY = -(e.clientY - penCanvas.offsetTop - penCanvas.height / 2);\r\n });\r\n penCanvas.addEventListener('mousedown', e => {\r\n this.mouseDown = true;\r\n });\r\n penCanvas.addEventListener('mouseup', e => {\r\n this.mouseDown = false;\r\n });\r\n penCanvas.addEventListener('click', e => {\r\n this.mouseClicked = true;\r\n setTimeout(() => this.mouseClicked = false, 0);\r\n });\r\n\r\n // Keys\r\n addEventListener('keydown', e => {\r\n if (e.repeat) return;\r\n this.keysPressed.add(e.key);\r\n });\r\n\r\n addEventListener('keyup', e => {\r\n this.keysPressed.delete(e.key);\r\n });\r\n }\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface RectangleOptions extends SpriteOptions {\r\n width?: number;\r\n height?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Rectangle extends Sprite {\r\n\r\n public discriminant = 'rectangle';\r\n\r\n public width: number;\r\n public height: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.width, this.height),\r\n height: Math.hypot(this.width, this.height)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RectangleOptions) {\r\n super(options);\r\n this.width = options?.width ?? 50;\r\n this.height = options?.height ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface SquareOptions extends SpriteOptions {\r\n sideLength?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Square extends Sprite {\r\n\r\n public discriminant = 'square';\r\n\r\n public sideLength: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.sideLength, this.sideLength),\r\n height: Math.hypot(this.sideLength, this.sideLength)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.sideLength / 2,\r\n -this.sideLength / 2,\r\n this.sideLength,\r\n this.sideLength\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSideLength(sideLength: number) {\r\n this.sideLength = sideLength;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: SquareOptions) {\r\n super(options);\r\n this.sideLength = options?.sideLength ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface OvalOptions extends SpriteOptions {\r\n radX?: number;\r\n radY?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Oval extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radX: number;\r\n public radY: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.radX * 2, this.radY * 2),\r\n height: Math.hypot(this.radX * 2, this.radY * 2)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radX,\r\n this.radY,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadX(radX: number) {\r\n this.radX = radX;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadY(radY: number) {\r\n this.radY = radY;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: OvalOptions) {\r\n super(options);\r\n this.radX = options?.radX ?? 25;\r\n this.radY = options?.radY ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface CircleOptions extends SpriteOptions {\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Circle extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radius,\r\n this.radius,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CircleOptions) {\r\n super(options);\r\n this.radius = options?.radius ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface RegularPolygonOptions extends SpriteOptions {\r\n sides?: number;\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n}\r\n\r\nexport default class RegularPolygon extends Sprite {\r\n\r\n public discriminant = 'regularpolygon';\r\n\r\n public sides: number;\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const step = (2 * Math.PI) / this.sides;\r\n path.moveTo(this.radius, 0);\r\n for (let i = 1; i < this.sides; i++) {\r\n path.lineTo(this.radius * Math.cos(step * i), this.radius * Math.sin(step * i));\r\n }\r\n path.closePath();\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n\r\n c.translate(cX, cY);\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSides(sides: number) {\r\n this.sides = sides;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RegularPolygonOptions) {\r\n super(options);\r\n this.sides = options?.sides ?? 5;\r\n this.radius = options?.radius ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface PenOptions extends SpriteOptions {\r\n drawing?: boolean;\r\n size?: number;\r\n color?: string;\r\n}\r\n\r\nexport default class Pen extends Sprite {\r\n\r\n public discriminant = 'pen';\r\n\r\n public drawing: boolean;\r\n public size: number;\r\n public color: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.size,\r\n height: this.size\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n return new Path2D();\r\n }\r\n public draw() {}\r\n\r\n public up() {\r\n this.drawing = false;\r\n }\r\n\r\n public down() {\r\n this.drawing = true;\r\n }\r\n\r\n public stamp(sprite: Sprite) {\r\n sprite.draw(true);\r\n }\r\n\r\n public eraseAll() {\r\n penCtx.clearRect(0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n public dot() {\r\n penCtx.fillStyle = this.color;\r\n penCtx.fillRect(\r\n this.x - this.size / 2 + canvas.width / 2,\r\n -this.y - this.size / 2 + canvas.height / 2,\r\n this.size,\r\n this.size\r\n );\r\n }\r\n\r\n private drawLine(lastX: number, lastY: number) {\r\n penCtx.beginPath();\r\n\r\n penCtx.moveTo(lastX + canvas.width / 2, -lastY + canvas.height / 2);\r\n penCtx.lineTo(this.x + canvas.width / 2, -this.y + canvas.height / 2);\r\n\r\n penCtx.lineWidth = this.size;\r\n penCtx.strokeStyle = this.color;\r\n penCtx.stroke();\r\n }\r\n\r\n // Overriding methods to include drawing\r\n\r\n public override move(steps: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setX(x: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setY(y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override goTo(x: number, y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeX(dX: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += dX;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeY(dY: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y += dY;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: PenOptions) {\r\n super(options);\r\n this.drawing = options?.drawing ?? false;\r\n this.size = options?.size ?? 5;\r\n this.color = options?.color ?? 'black';\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport type CanvasTextAlign =\r\n | 'left'\r\n | 'right'\r\n | 'center'\r\n | 'start'\r\n | 'end';\r\n\r\nexport type CanvasTextBaseline =\r\n | 'top'\r\n | 'hanging'\r\n | 'middle'\r\n | 'alphabetic'\r\n | 'ideographic'\r\n | 'bottom';\r\n\r\nexport interface TextOptions extends SpriteOptions {\r\n content?: string;\r\n color?: string;\r\n fontFamily?: string;\r\n fontSize?: number;\r\n align?: CanvasTextAlign;\r\n baseline?: CanvasTextBaseline;\r\n}\r\n\r\nexport default class Text extends Sprite {\r\n\r\n public discriminant = 'text';\r\n\r\n public content: string;\r\n public color: string;\r\n public fontFamily: string;\r\n public fontSize: number;\r\n public align: CanvasTextAlign;\r\n public baseline: CanvasTextBaseline;\r\n\r\n private font: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width, height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n ctx.save();\r\n \r\n ctx.font = this.font;\r\n\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n ctx.restore();\r\n\r\n path.rect(-width / 2, -height / 2, width, height);\r\n\r\n return path\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.font = this.font;\r\n c.fillStyle = this.color;\r\n c.textAlign = this.align;\r\n c.textBaseline = this.baseline;\r\n\r\n c.fillText(this.content, 0, 0);\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setContent(content: string) {\r\n this.content = content;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n public setFontSize(fontSize: number) {\r\n this.fontSize = fontSize;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setFontFamily(fontFamily: string) {\r\n this.fontFamily = fontFamily;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAlign(align: CanvasTextAlign) {\r\n this.align = align;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setBaseline(baseline: CanvasTextBaseline) {\r\n this.baseline = baseline;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: TextOptions) {\r\n super(options);\r\n\r\n this.content = options?.content ?? '';\r\n this.color = options?.color ?? 'black';\r\n this.fontFamily = options?.fontFamily ?? 'Arial';\r\n this.fontSize = options?.fontSize ?? 16;\r\n this.align = options?.align ?? 'center';\r\n this.baseline = options?.baseline ?? 'middle';\r\n\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n\r\n this.draw();\r\n }\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface ImageSpriteOptions extends SpriteOptions {\r\n src?: string;\r\n width: number;\r\n height: number;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class ImageSprite extends Sprite {\r\n\r\n public discriminant = 'imagesprite';\r\n\r\n public src: string;\r\n public width: number;\r\n public height: number;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n protected img: HTMLImageElement;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.width,\r\n height: this.height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.drawImage(\r\n this.img,\r\n 0, 0,\r\n this.img.width,\r\n this.img.height,\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width, this.height\r\n );\r\n if (this.outlineWidth)\r\n c.stroke(this.getCachedPath());\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setSrc(src: string) {\r\n this.src = src;\r\n this.refresh();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: ImageSpriteOptions) {\r\n super(options);\r\n\r\n this.src = options?.src ?? '';\r\n this.img = new Image();\r\n this.img.src = this.src;\r\n\r\n this.width = options?.width ?? this.img.width;\r\n this.height = options?.height ?? this.img.height;\r\n\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n \r\n this.draw();\r\n }\r\n}","import Engine from './Engine.ts';\r\nimport Sprite, { type SpriteOptions } from './Sprite.ts';\r\nimport { setScale, setAspectRatio, canvas, ctx } from './canvas.ts';\r\n\r\nimport Rectangle, { type RectangleOptions } from './sprites/Rectangle.ts';\r\nimport Square, { type SquareOptions } from './sprites/Square.ts';\r\nimport Oval, { type OvalOptions } from './sprites/Oval.ts';\r\nimport Circle, { type CircleOptions } from './sprites/Circle.ts';\r\nimport RegularPolygon, { type RegularPolygonOptions } from './sprites/RegularPolygon.ts';\r\nimport Pen, { type PenOptions } from './sprites/Pen.ts';\r\nimport Text, { type TextOptions, type CanvasTextAlign, type CanvasTextBaseline } from './sprites/Text.ts';\r\nimport ImageSprite, { type ImageSpriteOptions } from './sprites/ImageSprite.ts';\r\n\r\nconst TScratch = {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n RegularPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};\r\n\r\nexport default TScratch;\r\nexport {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n RegularPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Options\r\n type SpriteOptions,\r\n type RectangleOptions,\r\n type SquareOptions,\r\n type OvalOptions,\r\n type CircleOptions,\r\n type RegularPolygonOptions,\r\n type PenOptions,\r\n type TextOptions,\r\n type ImageSpriteOptions,\r\n\r\n // Other types\r\n type CanvasTextAlign,\r\n type CanvasTextBaseline,\r\n \r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};"],"mappings":"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","names":["canvas","ctx","penCanvas","penCtx","ratio","scale","setScale","newScale","setAspectRatio","newAspectRatio","Sprite","_Sprite","Engine","options","sprite","bBox1","bBox2","b1Left","b1Top","b1Right","b1Bottom","b2Left","b2Top","b2Right","b2Bottom","xMin","yMin","xMax","yMax","width","height","ctx","img1","img2","i","deg","rad","steps","dir","x","y","dX","dY","layer","dL","Engine","_Engine","scene","loop","sprite","layer","targetIndex","s","maxFPS","frameInterval","accumulator","tick","currentTime","deltaTime","ctx","canvas","ms","resolve","conditionGetter","check","mouseX","mouseY","canvasMouseX","canvasMouseY","localX","localY","angle","rotatedX","rotatedY","key","src","audio","sound","min","max","deg","val","rad","penCanvas","e","Rectangle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","width","height","color","options","Square","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","sideLength","color","options","Oval","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radX","radY","color","options","Circle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","color","options","RegularPolygon","Sprite","path","step","i","stamping","c","penCtx","ctx","cX","canvas","cY","sides","radius","color","options","Pen","Sprite","sprite","penCtx","canvas","lastX","lastY","steps","x","y","dX","dY","options","Text","Sprite","metrics","ctx","width","height","path","stamping","c","penCtx","cX","canvas","cY","content","color","fontSize","fontFamily","align","baseline","options","ImageSprite","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","src","width","height","options","TScratch","Engine","Sprite","Rectangle","Square","Oval","Circle","RegularPolygon","Pen","Text","ImageSprite","setScale","setAspectRatio","canvas","ctx","index_default"]}
1
+ {"version":3,"sources":["../src/canvas.ts","../src/Sprite.ts","../src/Engine.ts","../src/sprites/Rectangle.ts","../src/sprites/Square.ts","../src/sprites/Oval.ts","../src/sprites/Circle.ts","../src/sprites/Arc.ts","../src/sprites/RegularPolygon.ts","../src/sprites/CustomPolygon.ts","../src/sprites/Pen.ts","../src/sprites/Text.ts","../src/sprites/ImageSprite.ts","../src/index.ts"],"sourcesContent":["export const canvas = document.getElementById('game-window') as HTMLCanvasElement || document.createElement('canvas'); // For testing\r\nexport const ctx = canvas.getContext('2d')!;\r\n\r\nexport const penCanvas = document.createElement('canvas');\r\nexport const penCtx = penCanvas.getContext('2d')!;\r\npenCanvas.id = 'pen-canvas';\r\n\r\nlet ratio: number = 16 / 9;\r\nlet scale: number;\r\n\r\nexport function setScale(newScale: number) {\r\n scale = newScale;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\nexport function setAspectRatio(newAspectRatio: number) {\r\n ratio = newAspectRatio;\r\n\r\n canvas.width = ratio * scale;\r\n canvas.height = scale;\r\n\r\n penCanvas.width = ratio * scale;\r\n penCanvas.height = scale;\r\n}\r\n\r\ncanvas.parentElement?.insertBefore(penCanvas, canvas);\r\n\r\nsetScale(500);","import Engine from './Engine.ts';\r\n\r\nexport interface BoundingBox {\r\n x: number;\r\n y: number;\r\n width: number;\r\n height: number;\r\n}\r\n\r\nexport interface SpriteOptions {\r\n x?: number;\r\n y?: number;\r\n dir?: number;\r\n scene?: string;\r\n hidden?: boolean;\r\n layer?: number;\r\n}\r\n\r\nexport default abstract class Sprite {\r\n\r\n public x: number;\r\n public y: number;\r\n public dir: number;\r\n public scene: string;\r\n public hidden: boolean;\r\n public layer: number;\r\n\r\n private cachedPath: Path2D | null = null;\r\n private pathDirty: boolean = true;\r\n\r\n // Reusable collision detection canvas\r\n private static collisionCanvas: HTMLCanvasElement | null = null;\r\n private static collisionCtx: CanvasRenderingContext2D | null = null;\r\n\r\n // Rendering\r\n\r\n public abstract getBoundingBox(): BoundingBox;\r\n public abstract getPath(): Path2D;\r\n public abstract draw(stamping?: boolean): void;\r\n\r\n protected refresh() {\r\n Engine.init().refresh();\r\n }\r\n\r\n protected invalidatePath() {\r\n this.pathDirty = true;\r\n this.cachedPath = null;\r\n }\r\n\r\n protected getCachedPath(): Path2D {\r\n if (this.pathDirty || !this.cachedPath) {\r\n this.cachedPath = this.getPath();\r\n this.pathDirty = false;\r\n }\r\n return this.cachedPath;\r\n }\r\n\r\n constructor(options?: SpriteOptions) {\r\n this.x = options?.x ?? 0;\r\n this.y = options?.y ?? 0;\r\n this.dir = options?.dir ?? 0;\r\n this.scene = options?.scene ?? 'main';\r\n this.hidden = options?.hidden ?? false;\r\n this.layer = options?.layer ?? 0;\r\n Engine.init().addSprite(this);\r\n }\r\n\r\n // Sensing\r\n\r\n public touching(sprite: Sprite): boolean {\r\n\r\n // AABB (bounding boxes)\r\n const bBox1 = this.getBoundingBox();\r\n const bBox2 = sprite.getBoundingBox();\r\n\r\n const aabbOverlap =\r\n Math.abs(bBox1.x - bBox2.x) < (bBox1.width + bBox2.width) / 2 &&\r\n Math.abs(bBox1.y - bBox2.y) < (bBox1.height + bBox2.height) / 2;\r\n\r\n if (!aabbOverlap) return false;\r\n\r\n // Image data (pixel perfect)\r\n\r\n // Compute intersection bounding box\r\n const b1Left = bBox1.x - bBox1.width / 2;\r\n const b1Top = bBox1.y + bBox1.height / 2;\r\n const b1Right = bBox1.x + bBox1.width / 2;\r\n const b1Bottom = bBox1.y - bBox1.height / 2;\r\n\r\n const b2Left = bBox2.x - bBox2.width / 2;\r\n const b2Top = bBox2.y + bBox2.height / 2;\r\n const b2Right = bBox2.x + bBox2.width / 2;\r\n const b2Bottom = bBox2.y - bBox2.height / 2;\r\n\r\n const xMin = Math.max(b1Left, b2Left);\r\n const yMin = Math.min(b1Bottom, b2Bottom);\r\n const xMax = Math.min(b1Right, b2Right);\r\n const yMax = Math.max(b1Top, b2Top);\r\n\r\n const width = xMax - xMin;\r\n const height = yMax - yMin;\r\n\r\n if (width <= 1 || height <= 1) return false;\r\n\r\n // Reuse or create offscreen canvas for collision detection\r\n if (!Sprite.collisionCanvas) {\r\n Sprite.collisionCanvas = document.createElement('canvas');\r\n Sprite.collisionCtx = Sprite.collisionCanvas.getContext('2d', { willReadFrequently: true })!;\r\n }\r\n\r\n // Resize if needed\r\n if (Sprite.collisionCanvas.width < width || Sprite.collisionCanvas.height < height) {\r\n Sprite.collisionCanvas.width = Math.max(width, Sprite.collisionCanvas.width);\r\n Sprite.collisionCanvas.height = Math.max(height, Sprite.collisionCanvas.height);\r\n }\r\n\r\n const ctx = Sprite.collisionCtx!;\r\n ctx.clearRect(0, 0, width, height);\r\n\r\n // Draw first sprite\r\n ctx.save();\r\n ctx.translate(this.x - xMin, height - this.y + yMin);\r\n ctx.rotate(this.toRadians(this.dir));\r\n ctx.fillStyle = 'red';\r\n ctx.fill(this.getCachedPath());\r\n ctx.restore();\r\n const img1 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Draw second sprite\r\n ctx.clearRect(0, 0, width, height);\r\n ctx.save();\r\n ctx.translate(sprite.x - xMin, height - sprite.y + yMin);\r\n ctx.rotate(this.toRadians(sprite.dir));\r\n ctx.fillStyle = 'blue';\r\n ctx.fill(sprite.getCachedPath());\r\n ctx.restore();\r\n const img2 = ctx.getImageData(0, 0, width, height).data;\r\n\r\n // Check for overlapping non-transparent pixels\r\n for (let i = 3; i < img1.length; i += 4) // alpha channel\r\n if (img1[i]! > 0 && img2[i]! > 0) return true;\r\n\r\n return false;\r\n }\r\n\r\n // Helpers\r\n\r\n protected toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n protected toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Methods\r\n\r\n // Motion\r\n public move(steps: number) {\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n this.refresh();\r\n }\r\n\r\n public turn(deg: number) {\r\n this.dir += deg;\r\n this.refresh();\r\n }\r\n\r\n public point(dir: number) {\r\n this.dir = dir;\r\n this.refresh();\r\n }\r\n\r\n public pointTowards(x: number, y: number) {\r\n this.dir = 90 - this.toDegrees(Math.atan2(y, x));\r\n this.refresh();\r\n }\r\n\r\n public setX(x: number) {\r\n this.x = x;\r\n this.refresh();\r\n }\r\n\r\n public setY(y: number) {\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public goTo(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n this.refresh();\r\n }\r\n\r\n public changeX(dX: number) {\r\n this.x += dX;\r\n this.refresh();\r\n }\r\n\r\n public changeY(dY: number) {\r\n this.y += dY;\r\n this.refresh();\r\n }\r\n\r\n // Looks\r\n\r\n public show() {\r\n this.hidden = false;\r\n this.refresh();\r\n }\r\n\r\n public hide() {\r\n this.hidden = true;\r\n this.refresh();\r\n }\r\n\r\n public goToLayer(layer: number) {\r\n this.layer = layer;\r\n this.refresh();\r\n }\r\n\r\n public changeLayer(dL: number) {\r\n this.layer += dL;\r\n this.refresh();\r\n }\r\n}","import { canvas, ctx, penCanvas } from './canvas.ts';\r\nimport Sprite from './Sprite.ts';\r\nimport type { Vec2, Vec3, Vec4 } from './types/Vectors.ts';\r\n\r\ntype GameLoop = (() => any) | (() => Promise<any>);\r\n\r\ntype SceneMap = {\r\n [scene: string]: {\r\n sprites: Sprite[];\r\n loop: GameLoop | null;\r\n };\r\n};\r\n\r\nexport default class Engine {\r\n\r\n private static instance: Engine;\r\n\r\n private loopRunning: boolean = false;\r\n public gameLoop: GameLoop | null = null;\r\n\r\n public maxFPS: number = 24;\r\n public deltaTime: number = 1 / this.maxFPS;\r\n private lastFrame: number = performance.now();\r\n private refreshScheduled: boolean = false;\r\n private animationFrameId: number | null = null;\r\n\r\n public sounds: HTMLAudioElement[] = [];\r\n\r\n public mouseX: number = 0;\r\n public mouseY: number = 0;\r\n\r\n public mouseDown: boolean = false;\r\n public mouseClicked: boolean = false;\r\n\r\n private keysPressed: Set<string> = new Set<string>();\r\n\r\n public currentScene: string = 'main';\r\n public sceneMap: SceneMap = {};\r\n\r\n // Singleton initialization\r\n\r\n public static init() {\r\n if (!this.instance)\r\n this.instance = new Engine();\r\n\r\n return this.instance;\r\n }\r\n\r\n // Change the scene\r\n\r\n public changeScene(scene: string) {\r\n if (!this.sceneMap[scene])\r\n this.sceneMap[scene] = { sprites: [], loop: null };\r\n\r\n this.loopRunning = false;\r\n this.currentScene = scene;\r\n this.gameLoop = this.sceneMap[scene].loop;\r\n this.setMaxFramesPerSecond(this.maxFPS); // Update the interval function\r\n }\r\n\r\n // Loops\r\n\r\n public setLoop(scene: string, loop: GameLoop) {\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [], loop };\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].loop = loop;\r\n if (scene === this.currentScene)\r\n this.changeScene(scene);\r\n }\r\n\r\n public pauseLoop() {\r\n this.loopRunning = false;\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n }\r\n\r\n public resumeLoop() {\r\n this.loopRunning = true;\r\n void this.setMaxFramesPerSecond(this.maxFPS);\r\n }\r\n\r\n // Internal\r\n\r\n public addSprite(sprite: Sprite) {\r\n const { scene, layer } = sprite;\r\n\r\n if (!this.sceneMap[scene]) {\r\n this.sceneMap[scene] = { sprites: [sprite], loop: null };\r\n return;\r\n }\r\n\r\n let targetIndex = this.sceneMap[scene].sprites.findIndex(s => s.layer > layer);\r\n if (targetIndex === -1) {\r\n this.sceneMap[scene].sprites.push(sprite);\r\n return;\r\n }\r\n\r\n this.sceneMap[scene].sprites.splice(targetIndex, 0, sprite);\r\n this.refresh();\r\n }\r\n\r\n public removeSprite(sprite: Sprite) {\r\n const { scene } = sprite;\r\n\r\n if (!this.sceneMap[scene]) return;\r\n\r\n this.sceneMap[scene].sprites = this.sceneMap[scene].sprites.filter(s => s !== sprite);\r\n this.refresh();\r\n }\r\n\r\n public async setMaxFramesPerSecond(maxFPS: number) {\r\n this.maxFPS = maxFPS;\r\n\r\n let loop = this.gameLoop;\r\n if (!loop) return;\r\n\r\n // Cancel existing animation frame if any\r\n if (this.animationFrameId !== null) {\r\n cancelAnimationFrame(this.animationFrameId);\r\n this.animationFrameId = null;\r\n }\r\n\r\n this.loopRunning = true;\r\n const frameInterval = 1000 / maxFPS;\r\n let accumulator = 0;\r\n\r\n const tick = async (currentTime: number) => {\r\n if (!this.loopRunning) return;\r\n\r\n const deltaTime = currentTime - this.lastFrame;\r\n this.lastFrame = currentTime;\r\n accumulator += deltaTime;\r\n\r\n // Fixed timestep: only run loop when enough time has passed\r\n if (accumulator >= frameInterval) {\r\n this.deltaTime = accumulator / 1000;\r\n accumulator = accumulator % frameInterval;\r\n\r\n if (loop) await loop();\r\n }\r\n\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n };\r\n\r\n this.lastFrame = performance.now();\r\n this.animationFrameId = requestAnimationFrame(tick);\r\n }\r\n\r\n public refresh() {\r\n if (this.refreshScheduled) return;\r\n this.refreshScheduled = true;\r\n\r\n requestAnimationFrame(() => {\r\n this.refreshScheduled = false;\r\n ctx.clearRect(0, 0, canvas.width, canvas.height);\r\n const sprites = [\r\n ...(this.sceneMap[this.currentScene]?.sprites ?? []),\r\n ...(this.sceneMap['*']?.sprites ?? [])\r\n ];\r\n sprites.forEach(sprite => {\r\n if (!sprite.hidden)\r\n sprite.draw();\r\n });\r\n });\r\n }\r\n\r\n // Wait functions\r\n\r\n public async wait(ms: number): Promise<void> {\r\n return new Promise(resolve => setTimeout(resolve, ms));\r\n }\r\n\r\n public async waitUntil(conditionGetter: () => boolean): Promise<void> {\r\n return new Promise(resolve => {\r\n const check = () => {\r\n if (conditionGetter()) resolve();\r\n else setTimeout(check, 1000 / this.maxFPS);\r\n }\r\n check();\r\n });\r\n }\r\n\r\n // Events\r\n\r\n public hovering(sprite: Sprite) {\r\n const { mouseX, mouseY } = this;\r\n\r\n const canvasMouseX = mouseX + canvas.width / 2;\r\n const canvasMouseY = canvas.height / 2 - mouseY;\r\n\r\n // Mouse relative to sprite center\r\n const localX = canvasMouseX - (sprite.x + canvas.width / 2);\r\n const localY = canvasMouseY - (canvas.height / 2 - sprite.y);\r\n\r\n // Rotate mouse point by -dir to align with the path's local coordinates\r\n const angle = -this.toRadians(sprite.dir);\r\n const rotatedX = localX * Math.cos(angle) - localY * Math.sin(angle);\r\n const rotatedY = localX * Math.sin(angle) + localY * Math.cos(angle);\r\n\r\n return ctx.isPointInPath(sprite.getPath(), rotatedX, rotatedY);\r\n }\r\n\r\n public keyPressed(key: string) {\r\n return this.keysPressed.has(key);\r\n }\r\n\r\n // Sound\r\n\r\n public playSound(src: string) {\r\n const audio = new Audio(src);\r\n this.sounds.push(audio);\r\n\r\n audio.play();\r\n\r\n return audio;\r\n }\r\n\r\n public stopSound(sound: HTMLAudioElement) {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n this.sounds = this.sounds.filter(s => s !== sound);\r\n }\r\n\r\n public stopAllSounds() {\r\n this.sounds.forEach(sound => {\r\n sound.pause();\r\n sound.currentTime = 0;\r\n });\r\n this.sounds = [];\r\n }\r\n\r\n // Math\r\n\r\n public pickRandom(min: number, max: number) {\r\n if (min > max)\r\n [min, max] = [max, min];\r\n return Math.floor(Math.random() * (max - min + 1) + min);\r\n }\r\n\r\n public dotProduct(vectors: [Vec2, Vec2] | [Vec3, Vec3] | [Vec4, Vec4]) {\r\n const [a, b] = vectors;\r\n\r\n switch (a.length) {\r\n case 2: return a[0] * b[0] + a[1] * b[1];\r\n case 3: return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]!;\r\n case 4: return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]! + a[3] * b[3]!; // TypeScript doesn't narrow down the types on b\r\n }\r\n }\r\n\r\n // Trigonometric functions\r\n public sin(deg: number) {\r\n return Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public cos(deg: number) {\r\n return Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public tan(deg: number) {\r\n return Math.tan(this.toRadians(deg));\r\n }\r\n\r\n public csc(deg: number) {\r\n return 1 / Math.sin(this.toRadians(deg));\r\n }\r\n\r\n public sec(deg: number) {\r\n return 1 / Math.cos(this.toRadians(deg));\r\n }\r\n\r\n public cot(deg: number) {\r\n return 1 / Math.tan(this.toRadians(deg));\r\n }\r\n\r\n // Inverse Trigonometric functions\r\n public asin(val: number) {\r\n return this.toDegrees(Math.asin(val));\r\n }\r\n\r\n public acos(val: number) {\r\n return this.toDegrees(Math.acos(val));\r\n }\r\n\r\n public acsc(val: number) {\r\n return this.toDegrees(Math.asin(1 / val));\r\n }\r\n\r\n public asec(val: number) {\r\n return this.toDegrees(Math.acos(1 / val));\r\n }\r\n\r\n // Helpers\r\n\r\n public toRadians(deg: number) {\r\n return deg * Math.PI / 180;\r\n }\r\n\r\n public toDegrees(rad: number) {\r\n return rad * 180 / Math.PI;\r\n }\r\n\r\n // Private constructor\r\n\r\n private constructor() {\r\n void this.setMaxFramesPerSecond(24);\r\n\r\n // Events\r\n\r\n // Mouse\r\n penCanvas.addEventListener('mousemove', e => {\r\n this.mouseX = e.clientX - penCanvas.offsetLeft - penCanvas.width / 2;\r\n this.mouseY = -(e.clientY - penCanvas.offsetTop - penCanvas.height / 2);\r\n });\r\n penCanvas.addEventListener('mousedown', e => {\r\n this.mouseDown = true;\r\n });\r\n penCanvas.addEventListener('mouseup', e => {\r\n this.mouseDown = false;\r\n });\r\n penCanvas.addEventListener('click', e => {\r\n this.mouseClicked = true;\r\n setTimeout(() => this.mouseClicked = false, 0);\r\n });\r\n\r\n // Keys\r\n addEventListener('keydown', e => {\r\n if (e.repeat) return;\r\n this.keysPressed.add(e.key);\r\n });\r\n\r\n addEventListener('keyup', e => {\r\n this.keysPressed.delete(e.key);\r\n });\r\n }\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface RectangleOptions extends SpriteOptions {\r\n width?: number;\r\n height?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Rectangle extends Sprite {\r\n\r\n public discriminant = 'rectangle';\r\n\r\n public width: number;\r\n public height: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.width, this.height),\r\n height: Math.hypot(this.width, this.height)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RectangleOptions) {\r\n super(options);\r\n this.width = options?.width ?? 50;\r\n this.height = options?.height ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { ctx, canvas, penCtx } from '../canvas.ts';\r\n\r\nexport interface SquareOptions extends SpriteOptions {\r\n sideLength?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Square extends Sprite {\r\n\r\n public discriminant = 'square';\r\n\r\n public sideLength: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.sideLength, this.sideLength),\r\n height: Math.hypot(this.sideLength, this.sideLength)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.sideLength / 2,\r\n -this.sideLength / 2,\r\n this.sideLength,\r\n this.sideLength\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSideLength(sideLength: number) {\r\n this.sideLength = sideLength;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: SquareOptions) {\r\n super(options);\r\n this.sideLength = options?.sideLength ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface OvalOptions extends SpriteOptions {\r\n radX?: number;\r\n radY?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Oval extends Sprite {\r\n\r\n public discriminant = 'oval';\r\n\r\n public radX: number;\r\n public radY: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: Math.hypot(this.radX * 2, this.radY * 2),\r\n height: Math.hypot(this.radX * 2, this.radY * 2)\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radX,\r\n this.radY,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadX(radX: number) {\r\n this.radX = radX;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadY(radY: number) {\r\n this.radY = radY;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: OvalOptions) {\r\n super(options);\r\n this.radX = options?.radX ?? 25;\r\n this.radY = options?.radY ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface CircleOptions extends SpriteOptions {\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Circle extends Sprite {\r\n\r\n public discriminant = 'circle';\r\n\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.ellipse(\r\n 0, 0,\r\n this.radius,\r\n this.radius,\r\n 0, 0,\r\n Math.PI * 2\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CircleOptions) {\r\n super(options);\r\n this.radius = options?.radius ?? 25;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\n\r\nexport interface ArcOptions extends SpriteOptions {\r\n radius?: number;\r\n angle?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class Arc extends Sprite {\r\n\r\n public discriminant = 'arc';\r\n\r\n public radius: number;\r\n public angle: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.arc(\r\n 0, 0,\r\n this.radius,\r\n this.toRadians(this.angle / 2 - 90),\r\n this.toRadians(-this.angle / 2 - 90)\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAngle(angle: number) {\r\n this.angle = angle;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: ArcOptions) {\r\n super(options);\r\n\r\n this.radius = options?.radius ?? 25;\r\n this.angle = options?.angle ?? 270;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface RegularPolygonOptions extends SpriteOptions {\r\n sides?: number;\r\n radius?: number;\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n}\r\n\r\nexport default class RegularPolygon extends Sprite {\r\n\r\n public discriminant = 'regularpolygon';\r\n\r\n public sides: number;\r\n public radius: number;\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.radius * 2,\r\n height: this.radius * 2\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const step = (2 * Math.PI) / this.sides;\r\n path.moveTo(this.radius, 0);\r\n for (let i = 1; i < this.sides; i++) {\r\n path.lineTo(this.radius * Math.cos(step * i), this.radius * Math.sin(step * i));\r\n }\r\n path.closePath();\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n\r\n c.translate(cX, cY);\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setSides(sides: number) {\r\n this.sides = sides;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setRadius(radius: number) {\r\n this.radius = radius;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: RegularPolygonOptions) {\r\n super(options);\r\n this.sides = options?.sides ?? 5;\r\n this.radius = options?.radius ?? 50;\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n this.draw();\r\n }\r\n\r\n}","import Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\nimport { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport type { Vec2 } from '../types/Vectors.ts';\r\n\r\nexport interface CustomPolygonOptions extends SpriteOptions {\r\n vertices?: Vec2[];\r\n color?: string;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class CustomPolygon extends Sprite {\r\n\r\n public discriminant = 'custompolygon';\r\n\r\n public vertices: Vec2[];\r\n public color: string;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n\r\n let furthestVertexSize = 0;\r\n\r\n for (const v of this.vertices) {\r\n\r\n const size = Math.hypot(v[0], v[1]);\r\n\r\n if (size > furthestVertexSize)\r\n furthestVertexSize = size;\r\n }\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: furthestVertexSize,\r\n height: furthestVertexSize\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n const vertices = this.vertices;\r\n\r\n if (vertices.length < 2) return path;\r\n\r\n path.moveTo(vertices[0]![0], vertices[0]![1]);\r\n\r\n for (let i = 1; i < vertices.length; i++)\r\n path.lineTo(vertices[i]![0], vertices[i]![1]);\r\n\r\n path.closePath();\r\n\r\n return path;\r\n }\r\n\r\n public draw(stamping?: boolean): void {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n const path = this.getCachedPath();\r\n\r\n c.fillStyle = this.color;\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.fill(path)\r\n if (this.outlineWidth)\r\n c.stroke(path);\r\n\r\n c.restore();\r\n }\r\n\r\n public setVertices(vertices: Vec2[]) {\r\n this.vertices = vertices;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n constructor(options?: CustomPolygonOptions) {\r\n super(options);\r\n\r\n this.vertices = options?.vertices ?? [];\r\n this.color = options?.color ?? 'black';\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n\r\n this.draw();\r\n }\r\n\r\n}","import { canvas, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface PenOptions extends SpriteOptions {\r\n drawing?: boolean;\r\n size?: number;\r\n color?: string;\r\n}\r\n\r\nexport default class Pen extends Sprite {\r\n\r\n public discriminant = 'pen';\r\n\r\n public drawing: boolean;\r\n public size: number;\r\n public color: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.size,\r\n height: this.size\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n return new Path2D();\r\n }\r\n public draw() {}\r\n\r\n public up() {\r\n this.drawing = false;\r\n }\r\n\r\n public down() {\r\n this.drawing = true;\r\n }\r\n\r\n public stamp(sprite: Sprite) {\r\n sprite.draw(true);\r\n }\r\n\r\n public eraseAll() {\r\n penCtx.clearRect(0, 0, canvas.width, canvas.height);\r\n }\r\n\r\n public dot() {\r\n penCtx.fillStyle = this.color;\r\n penCtx.fillRect(\r\n this.x - this.size / 2 + canvas.width / 2,\r\n -this.y - this.size / 2 + canvas.height / 2,\r\n this.size,\r\n this.size\r\n );\r\n }\r\n\r\n private drawLine(lastX: number, lastY: number) {\r\n penCtx.beginPath();\r\n\r\n penCtx.moveTo(lastX + canvas.width / 2, -lastY + canvas.height / 2);\r\n penCtx.lineTo(this.x + canvas.width / 2, -this.y + canvas.height / 2);\r\n\r\n penCtx.lineWidth = this.size;\r\n penCtx.strokeStyle = this.color;\r\n penCtx.stroke();\r\n }\r\n\r\n // Overriding methods to include drawing\r\n\r\n public override move(steps: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += steps * Math.sin(this.toRadians(this.dir));\r\n this.y += steps * Math.cos(this.toRadians(this.dir));\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setX(x: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override setY(y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override goTo(x: number, y: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x = x;\r\n this.y = y;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeX(dX: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.x += dX;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n public override changeY(dY: number) {\r\n const lastX = this.x;\r\n const lastY = this.y;\r\n\r\n this.y += dY;\r\n if (this.drawing)\r\n this.drawLine(lastX, lastY);\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: PenOptions) {\r\n super(options);\r\n this.drawing = options?.drawing ?? false;\r\n this.size = options?.size ?? 5;\r\n this.color = options?.color ?? 'black';\r\n }\r\n\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport type CanvasTextAlign =\r\n | 'left'\r\n | 'right'\r\n | 'center'\r\n | 'start'\r\n | 'end';\r\n\r\nexport type CanvasTextBaseline =\r\n | 'top'\r\n | 'hanging'\r\n | 'middle'\r\n | 'alphabetic'\r\n | 'ideographic'\r\n | 'bottom';\r\n\r\nexport interface TextOptions extends SpriteOptions {\r\n content?: string;\r\n color?: string;\r\n fontFamily?: string;\r\n fontSize?: number;\r\n align?: CanvasTextAlign;\r\n baseline?: CanvasTextBaseline;\r\n}\r\n\r\nexport default class Text extends Sprite {\r\n\r\n public discriminant = 'text';\r\n\r\n public content: string;\r\n public color: string;\r\n public fontFamily: string;\r\n public fontSize: number;\r\n public align: CanvasTextAlign;\r\n public baseline: CanvasTextBaseline;\r\n\r\n private font: string;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width, height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n ctx.save();\r\n \r\n ctx.font = this.font;\r\n\r\n const metrics = ctx.measureText(this.content);\r\n const width = metrics.width;\r\n const height = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;\r\n\r\n ctx.restore();\r\n\r\n path.rect(-width / 2, -height / 2, width, height);\r\n\r\n return path\r\n }\r\n\r\n public override draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.font = this.font;\r\n c.fillStyle = this.color;\r\n c.textAlign = this.align;\r\n c.textBaseline = this.baseline;\r\n\r\n c.fillText(this.content, 0, 0);\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setContent(content: string) {\r\n this.content = content;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setColor(color: string) {\r\n this.color = color;\r\n this.refresh();\r\n }\r\n\r\n public setFontSize(fontSize: number) {\r\n this.fontSize = fontSize;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setFontFamily(fontFamily: string) {\r\n this.fontFamily = fontFamily;\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setAlign(align: CanvasTextAlign) {\r\n this.align = align;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setBaseline(baseline: CanvasTextBaseline) {\r\n this.baseline = baseline;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: TextOptions) {\r\n super(options);\r\n\r\n this.content = options?.content ?? '';\r\n this.color = options?.color ?? 'black';\r\n this.fontFamily = options?.fontFamily ?? 'Arial';\r\n this.fontSize = options?.fontSize ?? 16;\r\n this.align = options?.align ?? 'center';\r\n this.baseline = options?.baseline ?? 'middle';\r\n\r\n this.font = `${this.fontSize}px ${this.fontFamily}`;\r\n\r\n this.draw();\r\n }\r\n}","import { canvas, ctx, penCtx } from '../canvas.ts';\r\nimport Sprite, { type BoundingBox, type SpriteOptions } from '../Sprite.ts';\r\n\r\nexport interface ImageSpriteOptions extends SpriteOptions {\r\n src?: string;\r\n width: number;\r\n height: number;\r\n outlineColor?: string;\r\n outlineWidth?: number;\r\n};\r\n\r\nexport default class ImageSprite extends Sprite {\r\n\r\n public discriminant = 'imagesprite';\r\n\r\n public src: string;\r\n public width: number;\r\n public height: number;\r\n public outlineColor: string;\r\n public outlineWidth: number;\r\n\r\n protected img: HTMLImageElement;\r\n\r\n public getBoundingBox(): BoundingBox {\r\n return {\r\n x: this.x,\r\n y: this.y,\r\n width: this.width,\r\n height: this.height\r\n };\r\n }\r\n\r\n public getPath(): Path2D {\r\n const path = new Path2D();\r\n\r\n path.rect(\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width,\r\n this.height\r\n );\r\n\r\n return path;\r\n }\r\n\r\n public override draw(stamping?: boolean) {\r\n const c = stamping ? penCtx : ctx;\r\n\r\n c.save();\r\n\r\n const cX = this.x + canvas.width / 2;\r\n const cY = -this.y + canvas.height / 2;\r\n c.translate(cX, cY);\r\n\r\n c.rotate(this.toRadians(this.dir));\r\n\r\n c.strokeStyle = this.outlineColor;\r\n c.lineWidth = this.outlineWidth;\r\n c.drawImage(\r\n this.img,\r\n 0, 0,\r\n this.img.width,\r\n this.img.height,\r\n -this.width / 2,\r\n -this.height / 2,\r\n this.width, this.height\r\n );\r\n if (this.outlineWidth)\r\n c.stroke(this.getCachedPath());\r\n\r\n c.restore();\r\n }\r\n\r\n // Methods\r\n\r\n public setSrc(src: string) {\r\n this.src = src;\r\n this.refresh();\r\n }\r\n\r\n public setWidth(width: number) {\r\n this.width = width;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n public setHeight(height: number) {\r\n this.height = height;\r\n this.invalidatePath();\r\n this.refresh();\r\n }\r\n\r\n // Constructor\r\n\r\n constructor(options?: ImageSpriteOptions) {\r\n super(options);\r\n\r\n this.src = options?.src ?? '';\r\n this.img = new Image();\r\n this.img.src = this.src;\r\n\r\n this.width = options?.width ?? this.img.width;\r\n this.height = options?.height ?? this.img.height;\r\n\r\n this.outlineColor = options?.outlineColor ?? 'black';\r\n this.outlineWidth = options?.outlineWidth ?? 0;\r\n \r\n this.draw();\r\n }\r\n}","import Engine from './Engine.ts';\r\nimport Sprite, { type SpriteOptions } from './Sprite.ts';\r\nimport { setScale, setAspectRatio, canvas, ctx } from './canvas.ts';\r\n\r\nimport Rectangle, { type RectangleOptions } from './sprites/Rectangle.ts';\r\nimport Square, { type SquareOptions } from './sprites/Square.ts';\r\nimport Oval, { type OvalOptions } from './sprites/Oval.ts';\r\nimport Circle, { type CircleOptions } from './sprites/Circle.ts';\r\nimport Arc, { type ArcOptions } from './sprites/Arc.ts';\r\nimport RegularPolygon, { type RegularPolygonOptions } from './sprites/RegularPolygon.ts';\r\nimport CustomPolygon, { type CustomPolygonOptions } from './sprites/CustomPolygon.ts';\r\nimport Pen, { type PenOptions } from './sprites/Pen.ts';\r\nimport Text, { type TextOptions, type CanvasTextAlign, type CanvasTextBaseline } from './sprites/Text.ts';\r\nimport ImageSprite, { type ImageSpriteOptions } from './sprites/ImageSprite.ts';\r\n\r\nimport type { Vec2, Vec3, Vec4 } from './types/Vectors.ts';\r\n\r\nconst TScratch = {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n Arc,\r\n RegularPolygon,\r\n CustomPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};\r\n\r\nexport default TScratch;\r\nexport {\r\n // Main\r\n Engine,\r\n Sprite,\r\n\r\n // Sprites\r\n Rectangle,\r\n Square,\r\n Oval,\r\n Circle,\r\n Arc,\r\n RegularPolygon,\r\n CustomPolygon,\r\n Pen,\r\n Text,\r\n ImageSprite,\r\n\r\n // Options\r\n type SpriteOptions,\r\n type RectangleOptions,\r\n type SquareOptions,\r\n type OvalOptions,\r\n type CircleOptions,\r\n type ArcOptions,\r\n type RegularPolygonOptions,\r\n type CustomPolygonOptions,\r\n type PenOptions,\r\n type TextOptions,\r\n type ImageSpriteOptions,\r\n\r\n // Other types\r\n type CanvasTextAlign,\r\n type CanvasTextBaseline,\r\n type Vec2,\r\n type Vec3,\r\n type Vec4,\r\n \r\n // Canvas\r\n setScale,\r\n setAspectRatio,\r\n canvas,\r\n ctx\r\n};"],"mappings":"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","names":["canvas","ctx","penCanvas","penCtx","ratio","scale","setScale","newScale","setAspectRatio","newAspectRatio","Sprite","_Sprite","Engine","options","sprite","bBox1","bBox2","b1Left","b1Top","b1Right","b1Bottom","b2Left","b2Top","b2Right","b2Bottom","xMin","yMin","xMax","yMax","width","height","ctx","img1","img2","i","deg","rad","steps","dir","x","y","dX","dY","layer","dL","Engine","_Engine","scene","loop","sprite","layer","targetIndex","s","maxFPS","frameInterval","accumulator","tick","currentTime","deltaTime","ctx","canvas","ms","resolve","conditionGetter","check","mouseX","mouseY","canvasMouseX","canvasMouseY","localX","localY","angle","rotatedX","rotatedY","key","src","audio","sound","min","max","vectors","a","b","deg","val","rad","penCanvas","e","Rectangle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","width","height","color","options","Square","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","sideLength","color","options","Oval","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radX","radY","color","options","Circle","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","color","options","Arc","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","radius","angle","color","options","RegularPolygon","Sprite","path","step","i","stamping","c","penCtx","ctx","cX","canvas","cY","sides","radius","color","options","CustomPolygon","Sprite","furthestVertexSize","v","size","path","vertices","i","stamping","c","penCtx","ctx","cX","canvas","cY","color","options","Pen","Sprite","sprite","penCtx","canvas","lastX","lastY","steps","x","y","dX","dY","options","Text","Sprite","metrics","ctx","width","height","path","stamping","c","penCtx","cX","canvas","cY","content","color","fontSize","fontFamily","align","baseline","options","ImageSprite","Sprite","path","stamping","c","penCtx","ctx","cX","canvas","cY","src","width","height","options","TScratch","Engine","Sprite","Rectangle","Square","Oval","Circle","Arc","RegularPolygon","CustomPolygon","Pen","Text","ImageSprite","setScale","setAspectRatio","canvas","ctx","index_default"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tscratch",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "A Scratch-style game engine for TypeScript.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",