UNPKG

duckengine

Version:
9 lines (6 loc) • 111 kB
var __webpack_require__={};(()=>{__webpack_require__.d=(exports,definition)=>{for(var key in definition){if(__webpack_require__.o(definition,key)&&!__webpack_require__.o(exports,key)){Object.defineProperty(exports,key,{enumerable:true,get:definition[key]})}}}})();(()=>{__webpack_require__.o=(obj,prop)=>Object.prototype.hasOwnProperty.call(obj,prop)})();var __webpack_exports__={};__webpack_require__.d(__webpack_exports__,{_:()=>Duck,Z:()=>lib});const __debugStack_duckengine=[];class Error{constructor(message){console.error("DuckEngine Error : "+message);__debugStack_duckengine.push(message)}}class Warn{constructor(message){console.warn("DuckEngine Warning : "+message);__debugStack_duckengine.push(message)}}class Log{constructor(message){console.log("DuckEngine : "+message);__debugStack_duckengine.push(message)}}const Debug={stack:()=>{return __debugStack_duckengine},Error:Error,Warn:Warn,Log:Log};const debug=Debug;function clamp(x,min,max){if(x<min)x=min;else if(x>max)x=max;return x}function degToRadians(degrees){return degrees*Math.PI/180}class Vector2{constructor(x=0,y=0){this.x=x;this.y=y}setValues(x,y){this.x=x;this.y=y;return this}setValuesVec(vector){this.x=vector.x;this.y=vector.y;return this}add(vector){this.x+=vector.x;this.y+=vector.y;return this}addNumber(number){this.x+=number;this.y+=number;return this}subtract(vector){this.x-=vector.x;this.y-=vector.y;return this}subtractNumber(number){this.x-=number;this.y-=number;return this}multiply(vector){this.x*=vector.x;this.y*=vector.y;return this}multiplyNumber(number){this.x*=number;this.y*=number;return this}divide(vector){this.x/=vector.x;this.y/=vector.y;return this}divideNumber(number){this.x/=number;this.y/=number;return this}round(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this}angleBetween(vector){return Math.atan2(this.x*vector.y-this.y*vector.x,this.x*vector.x+this.y*vector.y)}angleTo(vector){return Math.atan2(vector.y-this.y,vector.x-this.x)}clone(){return new Vector2(this.x,this.y)}distance(vector){return Math.sqrt((vector.x-this.x)*(vector.x-this.x)+(vector.y-this.y)*(vector.y-this.y))}distanceSqr(vector){return(vector.x-this.x)*(vector.x-this.x)+(vector.y-this.y)*(vector.y-this.y)}dot(vector){return this.x*vector.x+this.y*vector.y}crossProduct(vector){return this.x*vector.y-this.y*vector.x}equals(vector){return this.x===vector.x&&this.y===vector.y}perpendicular(resultVector){resultVector=resultVector||new Vector2;return resultVector.setValues(-this.y,this.x)}moveTowards(current,target,maxDistanceDelta){const toVector_x=target.x-current.x;const toVector_y=target.y-current.y;const sqDist=toVector_x*toVector_x+toVector_y*toVector_y;if(sqDist===0||maxDistanceDelta>=0&&sqDist<=maxDistanceDelta*maxDistanceDelta){return target}const dist=Math.sqrt(sqDist);const newX=current.x+toVector_x/dist*maxDistanceDelta;const newY=current.y+toVector_y/dist*maxDistanceDelta;return new Vector2(newX,newY)}normalize(){const mag=this.magnitude();if(mag>0){this.divideNumber(mag)}return this}getNormal(vector,resultVector){resultVector=resultVector||new Vector2;return resultVector.setValues(vector.y-this.y,this.x-vector.x).normalize()}isZero(){return this.x===0&&this.y===0}scale(scalar){this.x*=scalar.x;this.y*=scalar.y;return this}negate(){this.x=-this.x;this.y=-this.y;return this}magnitude(){return Math.sqrt(this.x*this.x+this.y*this.y)}magnitudeSqr(){return this.x*this.x+this.y*this.y}scaleToMagnitude(magnitude){const k=magnitude/this.magnitude();this.x*=k;this.y*=k;return this}toString(){return`Vector2(${this.x}, ${this.y})`}toPrecision(precision){this.x=Number(this.x.toPrecision(precision));this.y=Number(this.y.toPrecision(precision));return this}translate(dx,dy){this.x+=dx;this.y+=dy;return this}translateX(dx){this.x+=dx;return this}translateY(dy){this.x+=dy;return this}tripleProduct(a,b,c,resultVector){resultVector=resultVector||new Vector2;const ac=a.dot(c);const bc=b.dot(c);return resultVector.setValues(b.x*ac-a.x*bc,b.y*ac-a.y*bc)}clamp(min,max){this.x=clamp(this.x,min,max);this.y=clamp(this.y,min,max);return this}clampMin(min){if(this.x<min){this.x=min}if(this.y<min){this.y=min}return this}clampMax(max){if(this.x>max){this.x=max}if(this.y>max){this.y=max}return this}rotate(degrees,center=Vector2.ZERO){const radians=degToRadians(degrees);const cx=center.x||0;const cy=center.y||0;const c=Math.cos(radians),s=Math.sin(radians);const x=this.x-cx;const y=this.y-cy;this.x=x*c-y*s+cx;this.y=x*s+y*c+cy;return this}reflect(){this.x*=-1;this.y*=-1;return this}abs(){this.x=Math.abs(this.x);this.y=Math.abs(this.y);return this}static get ZERO(){return new Vector2(0,0)}static get UP(){return new Vector2(0,-1)}static get DOWN(){return new Vector2(0,1)}static get LEFT(){return new Vector2(-1,0)}static get RIGHT(){return new Vector2(1,0)}static CREATE(x,y){if(!x&&!y)return this.ZERO;if(x&&!y)return new Vector2(x);if(!x&&y)return new Vector2(0,y);return new Vector2(x,y)}static fromVector2Like(vector2Like){return new Vector2(vector2Like.x,vector2Like.y)}static toVector2Like(vector2){return{x:vector2.x,y:vector2.y}}static fromVec(vector){return new Vector2(vector.x,vector.y)}}class Collider{constructor(hitbox,collidesWith,game){this.hitbox=hitbox;this.collidesWith=collidesWith;this.game=game}_update(hitbox,updatedCollidesWith){this.hitbox=hitbox;this.collidesWith=updatedCollidesWith;if(Array.isArray(this.collidesWith)){this.collidesWith.forEach(otherObject=>{if(otherObject.hitbox){this.collideHitboxes(otherObject.hitbox)}})}else{this.collidesWith.each(otherObject=>{if(otherObject.hitbox){this.collideHitboxes(otherObject.hitbox)}})}}collideHitboxes(hitbox2){const rectCX=hitbox2.position.x+hitbox2.w*.5;const rectCY=hitbox2.position.y+hitbox2.h*.5;const thisCX=this.hitbox.position.x+this.hitbox.w*.5;const thisCY=this.hitbox.position.y+this.hitbox.h*.5;const dx=rectCX-thisCX;const dy=rectCY-thisCY;const aw=(hitbox2.w+this.hitbox.w)*.5;const ah=(hitbox2.h+this.hitbox.h)*.5;if(Math.abs(dx)>aw||Math.abs(dy)>ah){return"none"}if(Math.abs(dx/this.hitbox.w)>Math.abs(dy/this.hitbox.h)){if(dx<0){this.hitbox.position.x=hitbox2.position.x+hitbox2.w;return"left"}else{this.hitbox.position.x=hitbox2.position.x-this.hitbox.w;return"right"}}else{if(dy<0){this.hitbox.position.y=hitbox2.position.y+hitbox2.h;return"top"}else{this.hitbox.position.y=hitbox2.position.y-this.hitbox.h;return"bottom"}}}}function uniqueID(){function chr4(){return Math.random().toString(16).slice(-4)}return chr4()+chr4()+"-"+chr4()+"-"+chr4()+"-"+chr4()+"-"+chr4()+chr4()+chr4()}function hitboxFaceIntersect(hitbox,hitbox2){const rectCX=hitbox2.position.x+hitbox2.w*.5;const rectCY=hitbox2.position.y+hitbox2.h*.5;const thisCX=hitbox.position.x+hitbox.w*.5;const thisCY=hitbox.position.y+hitbox.h*.5;const dx=rectCX-thisCX;const dy=rectCY-thisCY;const aw=(hitbox2.w+hitbox.w)*.5;const ah=(hitbox2.h+hitbox.h)*.5;if(Math.abs(dx)>aw||Math.abs(dy)>ah){return"none"}if(Math.abs(dx/hitbox.w)>Math.abs(dy/hitbox.h)){if(dx<0){hitbox.position.x=hitbox2.position.x+hitbox2.w;return"left"}else{hitbox.position.x=hitbox2.position.x-hitbox.w;return"right"}}else{if(dy<0){hitbox.position.y=hitbox2.position.y+hitbox2.h;return"top"}else{hitbox.position.y=hitbox2.position.y-hitbox.h;return"bottom"}}}function rectToRectIntersect(rect,rect2){const rectCX=rect2.position.x+rect2.w*.5;const rectCY=rect2.position.y+rect2.h*.5;const thisCX=rect.position.x+rect.w*.5;const thisCY=rect.position.y+rect.h*.5;const dx=rectCX-thisCX;const dy=rectCY-thisCY;const aw=(rect2.w+rect.w)*.5;const ah=(rect2.h+rect.h)*.5;if(Math.abs(dx)>aw||Math.abs(dy)>ah)return false;else return true}class Hitbox{constructor(position,w,h,offset,physicsObject,game,scene,debugColor){this.id=uniqueID();this.position=position;this.offset=offset;this.w=w;this.h=h;this.game=game;this.scene=scene;this.physicsObject=physicsObject;this.debugColor=debugColor;this.visible=debugColor?true:false;this.zIndex=Duck.Layers.Rendering.zIndex.graphicDebug;this.culled=debugColor?true:false;this.collisionState="none"}_draw(){if(this.game.renderer.ctx){if(this.debugColor){this.game.renderer.drawRect(this.position.x,this.position.y,this.w,this.h,this.debugColor)}}else{new debug.Error("CanvasRenderingContext2D is undefined. HTMLCanvasElement is undefined.")}}_update(physicsObject){this.physicsObject=physicsObject;this.position=this.physicsObject.position.add(this.offset)}setDebugColor(debugColor,visible=true){this.debugColor=debugColor;this.visible=visible}scale(scale){this.w=scale.x;this.h=scale.y}setPosition(newPosition,offset=this.offset){this.offset=offset;this.position=newPosition.add(this.offset)}auto(offset){if(this.physicsObject.shape==="circle"){const topLeft=new Vector2(this.physicsObject.position.x-this.physicsObject.r,this.physicsObject.position.y-this.physicsObject.r);if(offset){topLeft.add(offset)}this.position=topLeft;this.scale(new Vector2(this.physicsObject.r*2,this.physicsObject.r*2))}else{this.position=this.physicsObject.position;if(offset){this.position.add(offset)}this.scale(new Vector2(this.physicsObject.w,this.physicsObject.h))}}intersectsWith(hitbox){return rectToRectIntersect({position:{x:this.position.x,y:this.position.y},w:this.w,h:this.h},{position:{x:hitbox.position.x,y:hitbox.position.y},w:hitbox.w,h:hitbox.h})}intersectsFaceWith(hitbox){this.collisionState=hitboxFaceIntersect(this,hitbox);return this.collisionState}groupIntersectsFaceWith(hitboxes){const collisionStates=[];if(Array.isArray(hitboxes)){for(let i=0;i<hitboxes.length;i++){const hitbox=hitboxes[i];collisionStates.push(hitboxFaceIntersect(this,hitbox))}}else{for(let i=0;i<hitboxes.group.length;i++){const hitbox=hitboxes.group[i];collisionStates.push(hitboxFaceIntersect(this,hitbox))}}return collisionStates}getTop(){return this.position.y}getBottom(){return this.position.y+this.h}getLeft(){return this.position.x}getRight(){return this.position.x+this.w}getCenter(){return new Vector2(this.position.x+this.w/2,this.position.y+this.h/2)}getCenterY(){return this.position.y+this.h/2}getCenterX(){return this.position.x+this.w/2}}class PhysicsBody{constructor(shape,id,x,y,w,h,r,game,scene){this.shape=shape;this.id=id;this.position=new Vector2(x,y);this.w=w;this.h=h;this.r=r;this.options={type:"KinematicBody"};this.game=game;this.scene=scene;this.velocity=Vector2.ZERO;this.collider=undefined;this.collidesWith=[];this.enabled=true;this.isAttached=false;this.attachedChildren=[];this.attachOffset=Vector2.ZERO;this.bounds={x:-Infinity,y:-Infinity,w:Infinity,h:Infinity};this.physics={addCollider:collidesWith=>{var _a;if(!this.hitbox){new debug.Error("Cannot add collider to PhysicsObject. No hitbox exists. Create a hitbox first using PhysicsObject.physics.addHitbox");return undefined}if(!((_a=this.game.config.physics)===null||_a===void 0?void 0:_a.enabled)){new debug.Error("Cannot add collider to PhysicsObject. Game Config.physics.enabled must be truthy!")}this.collidesWith=collidesWith;this.collider=new Collider(this.hitbox,collidesWith,this.game);return this.collider},addHitbox:(w,h,offset=Vector2.ZERO,debugColor)=>{var _a;if(!((_a=this.game.config.physics)===null||_a===void 0?void 0:_a.enabled)){new debug.Error("Cannot add hitbox to PhysicsObject. Game Config.physics.enabled must be truthy!")}this.hitbox=new Hitbox(this.position,w||0,h||0,offset,this,this.game,this.scene,debugColor);if(!w&&!h){this.hitbox.auto(offset)}this.scene.displayList.add(this.hitbox);return this.hitbox},setBounds:(x,y,w,h)=>{this.bounds.x=x;this.bounds.y=y;this.bounds.w=w;this.bounds.h=h}}}setEnabled(enabled){this.enabled=enabled;return this.enabled}_update(){var _a;this.position.x+=this.velocity.x*this.game.smoothDeltaTime;this.position.y+=this.velocity.y*this.game.smoothDeltaTime;this.position.x=clamp(this.position.x,this.bounds.x,this.bounds.w);this.position.y=clamp(this.position.y,this.bounds.y,this.bounds.h);this.velocity.x=0;this.velocity.y=0;if(this.game.config.roundPixels){this.position.round()}if((_a=this.game.config.physics)===null||_a===void 0?void 0:_a.gravity){if(this.options.type==="KinematicBody"||this.options.type==="RigidBody"){this.applyGravity(Vector2.fromVector2Like(this.game.config.physics.gravity))}}this.attachedChildren.forEach(object=>{const pos=this.position.clone();pos.subtract(object.attachOffset);object.position=pos;if(object.hitbox){object.hitbox.position=object.position.clone().add(object.hitbox.offset)}})}setType(type){this.options.type=type;return this.options}attachTo(object,diffOffset){const offset=diffOffset||Vector2.fromVec(object.position).subtract(this.position);this.isAttached=true;this.attachOffset=offset;object.attachedChildren.push(this)}attachChild(object,diffOffset){const offset=diffOffset||Vector2.fromVec(this.position).subtract(object.position);object.isAttached=true;object.attachOffset=offset;this.attachedChildren.push(object)}detachFrom(object){const f=object.attachedChildren.find(o=>o.id===this.id);if(f){this.isAttached=false;this.attachOffset=Vector2.ZERO;object.attachedChildren.splice(object.attachedChildren.findIndex(o=>o.id===this.id),1)}else{new debug.Error("Cannot detachFrom from object, PhysicsBody is not attached to anything.")}}detachChild(object){const f=this.attachedChildren.find(o=>o.id===object.id);if(f){object.isAttached=false;object.attachOffset=Vector2.ZERO;this.attachedChildren.splice(this.attachedChildren.findIndex(o=>o.id===object.id),1)}else{new debug.Error("Cannot detachChild from PhysicsBody, object is not attached to anything.")}}setVelocity(axis,pxPerSecond){if(this.options.type!=="KinematicBody"){new debug.Error(`Cannot set velocity as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody.`);return}if(this.isAttached){new debug.Error("Cannot set velocity as PhysicsBody is attached to another PhysicsBody.");return}if(axis==="x"){this.velocity.x=pxPerSecond}if(axis==="y"){this.velocity.y=pxPerSecond}}setVelocityX(pxPerSecond){if(this.options.type!=="KinematicBody"){new debug.Error(`Cannot set velocity X as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody.`);return}if(this.isAttached){new debug.Error("Cannot set velocity X as PhysicsBody is attached to another PhysicsBody.");return}this.velocity.x=pxPerSecond}setVelocityY(pxPerSecond){if(this.options.type!=="KinematicBody"){new debug.Error(`Cannot set velocity Y as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody.`);return}if(this.isAttached){new debug.Error("Cannot set velocity Y as PhysicsBody is attached to another PhysicsBody.");return}this.velocity.y=pxPerSecond}accelerateVelocity(target,amount){if(this.options.type!=="KinematicBody"){new debug.Error(`Cannot accelerate velocity as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody.`);return}if(this.isAttached){new debug.Error("Cannot accelerate velocity as PhysicsBody is attached to another PhysicsBody.");return}this.velocity.moveTowards(this.velocity,target,amount)}applyFriction(frictionAmount){if(this.options.type!=="KinematicBody"&&this.options.type!=="RigidBody"){new debug.Error(`Cannot apply friction as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody or RigidBody.`);return}if(this.isAttached){new debug.Error("Cannot apply friction as PhysicsBody is attached to another PhysicsBody.");return}this.velocity.subtract(frictionAmount).clampMin(0)}applyGravity(gravity){if(this.options.type!=="KinematicBody"&&this.options.type!=="RigidBody"){new debug.Error(`Cannot apply gravity as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody or RigidBody.`);return}if(this.isAttached){new debug.Error("Cannot apply gravity as PhysicsBody is attached to another PhysicsBody.");return}if(gravity.x!==0){this.velocity.x+=gravity.x}if(gravity.y!==0){this.velocity.y+=gravity.y}}bounceVelocityBounds(bounds=this.bounds,restitution=1){if(this.options.type!=="KinematicBody"&&this.options.type!=="RigidBody"){new debug.Error(`Cannot bounce velocity as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody or RigidBody.`);return}if(this.isAttached){new debug.Error("Cannot bounce velocity as PhysicsBody is attached to another PhysicsBody.");return}if(this.position.x>bounds.w||this.position.x<bounds.x){this.velocity.x=this.velocity.x*-restitution}if(this.position.y>bounds.h||this.position.y<bounds.y){this.velocity.y=this.velocity.y*-restitution}}reflectVelocity(){if(this.options.type!=="KinematicBody"&&this.options.type!=="RigidBody"){new debug.Error(`Cannot reflect velocity as PhysicsBody.options.type is ${this.options.type} instead of KinematicBody or RigidBody.`);return}if(this.isAttached){new debug.Error("Cannot reflect velocity as PhysicsBody is attached to another PhysicsBody.");return}this.velocity.reflect()}autoFitHitbox(offset){var _a;(_a=this.hitbox)===null||_a===void 0?void 0:_a.auto(offset)}scaleHitbox(scale){var _a;(_a=this.hitbox)===null||_a===void 0?void 0:_a.scale(scale)}getTop(){return this.position.y}getBottom(){return this.position.y+this.h}getLeft(){return this.position.x}getRight(){return this.position.x+this.w}getCenter(){if(this.shape==="circle"){return new Vector2(this.position.x,this.position.y)}else{return new Vector2(this.position.x+this.w/2,this.position.y+this.h/2)}}getCenterY(){if(this.shape==="circle"){return this.position.y+this.r}else{return this.position.y+this.h/2}}getCenterX(){if(this.shape==="circle"){return this.position.x+this.r}else{return this.position.x+this.w/2}}isColliding(obj){var _a,_b;if(obj.hitbox){return((_a=this.hitbox)===null||_a===void 0?void 0:_a.intersectsFaceWith(obj.hitbox))!=="none"?(_b=this.hitbox)===null||_b===void 0?void 0:_b.intersectsFaceWith(obj.hitbox):false}else{return false}}isCollidingGroup(objects){var _a;const hitboxes=[];if(Array.isArray(objects)){objects.forEach(obj=>{if(obj.hitbox){hitboxes.push(obj.hitbox)}})}else{objects.each(obj=>{if(obj.hitbox){hitboxes.push(obj.hitbox)}})}const states=(_a=this.hitbox)===null||_a===void 0?void 0:_a.groupIntersectsFaceWith(hitboxes);return(states===null||states===void 0?void 0:states.includes("top"))?"top":false||(states===null||states===void 0?void 0:states.includes("bottom"))?"bottom":false||(states===null||states===void 0?void 0:states.includes("left"))?"left":false||(states===null||states===void 0?void 0:states.includes("right"))?"right":false}}class GameObject extends PhysicsBody{constructor(shape,x,y,w,h,r,texture,game,scene){const id=uniqueID();super(shape,id,x,y,w,h,r,game,scene);this.texture=texture;this.visible=true;this.zIndex=Duck.Layers.Rendering.zIndex.gameobject;this.culled=true;if(this.game.renderer.ctx){this.game.renderer.setBlendMode("source-over")}}_draw(){}setVisible(visible){this.visible=visible;this.game.renderer.pipeline.pool()}setScale(scale){if(typeof scale!=="number"){if(scale.width){this.w=scale.width}if(scale.height){this.h=scale.height}}else{this.r=scale}}setFillColor(fillColor){this.texture.texture=fillColor}}class TextureBase{constructor(type,dataType,texture,w,h){this.id=uniqueID();this.type=type;this.dataType=dataType;this.texture=texture;this.scale=new Vector2(w,h);if(this.type==="image"){this.texture.width=this.scale.x;this.texture.height=this.scale.y}}setScale(scale){this.scale=new Vector2(scale.width,scale.height);if(this.type==="image"){this.texture.width=this.scale.x;this.texture.height=this.scale.y}return this.scale}setImagePath(imagePath){if(this.type==="image"){this.texture.src=imagePath}}setFillColor(color){if(this.type==="color"){this.texture=color}}static fromColor(color,w,h){return new TextureBase("color","base",color,w,h)}static fromTexture(imgpath,w,h){const img=new Image(w,h);img.src=imgpath;return new TextureBase("image","base",img,w,h)}static fromEither(fillColorOrIMGPath,w,h){return new TextureBase("either","base",fillColorOrIMGPath,w,h)}}class Texture extends TextureBase{constructor(type,texture,w,h){if(type==="image"){super("image","base",texture,w,h)}else if(type==="color"){super("color","base",texture,w,h)}else{super("either","base",texture,w,h)}}}class Circle extends GameObject{constructor(x,y,r,fillColor,game,scene){super("circle",x,y,0,0,r,Texture.fromColor(fillColor,r,r),game,scene)}_draw(){if(this.game.renderer.ctx){this.game.renderer.drawCircle(this.position.x,this.position.y,this.r,this.texture.texture)}else{new debug.Error("CanvasRenderingContext2D is undefined. Canvas is undefined.")}}}class Rect extends GameObject{constructor(x,y,w,h,fillColor,game,scene){super("rect",x,y,w,h,0,Texture.fromColor(fillColor,w,h),game,scene)}_draw(){if(this.game.renderer.ctx){this.game.renderer.drawRect(this.position.x,this.position.y,this.w,this.h,this.texture.texture)}else{new debug.Error("CanvasRenderingContext2D is undefined. HTMLCanvasElement is undefined.")}}}function circleRectCollision(circle,rect){let dx=Math.abs(circle.position.x-(rect.position.x+rect.w/2));let dy=Math.abs(circle.position.y-(rect.position.y+rect.h/2));if(dx>circle.r+rect.w/2){return false}if(dy>circle.r+rect.h/2){return false}if(dx<=rect.w){return true}if(dy<=rect.h){return true}dx=dx-rect.w;dy=dy-rect.h;return dx*dx+dy*dy<=circle.r*circle.r}function randomInt(min,max){return Math.floor(Math.random()*(max-min+1)+min)}function lerp(start,end,amount){return(1-amount)*start+amount*end}class RoundRect extends GameObject{constructor(x,y,w,h,r,fillColor,game,scene){super("roundrect",x,y,w,h,r,Texture.fromColor(fillColor,w,h),game,scene)}_draw(){if(this.game.renderer.ctx){this.game.renderer.drawRoundRect(this.position.x,this.position.y,this.w,this.h,this.r,this.texture.texture)}else{new debug.Error("CanvasRenderingContext2D is undefined as Canvas is undefined.")}}}class Timer{constructor(ms,cb,args,repeat){this.seconds=ms/1e3;this.cb=cb;this.repeat=repeat-1;this.counter=0;this.repeatCounter=0;this.done=false;this.args=args}count(delta){if(this.done){return}if(this.counter<this.seconds){this.counter+=delta;return}if(this.repeatCounter<this.repeat){this.repeatCounter++;this.counter=0;this.cb(...this.args,this.counter,this.repeatCounter,this.done);return}if(this.counter>this.seconds){this.done=true;this.cb(...this.args,this.counter,this.repeatCounter,this.done);return}}stop(){this.done=true}reset(){this.done=false;this.counter=0;this.repeatCounter=0}pause(){this.done=true}resume(){this.done=true}}class AnimationFrame{constructor(col,row,sprite){this.col=col;this.row=row;this.sprite=sprite}set(){this.sprite.currentCol=this.col;this.sprite.currentRow=this.row}}class animation_Animation{constructor(config,game,scene,sprite){this.key=config.key;this.config=config;this.game=game;this.scene=scene;this.sprite=sprite;this.countBy=this.config.useDelta?this.game.deltaTime:1e3/this.config.frameRate;this.repeat=this.config.repeat||1;this.repeatCounter=0;this.frames=this.createFrames();this.reversedFrames=this.frames.slice().reverse();this.animationNormalTimer=new Timer(1e3/this.config.frameRate,()=>{this.normalStep(this)},[],this.frames.length*this.repeat);this.animationReverseTimer=new Timer(1e3/this.config.frameRate,()=>{this.reverseStep(this)},[],this.reversedFrames.length*this.repeat);if(this.config.delay){this.delayTimer=new Timer(this.config.delay,()=>undefined,[],1)}this.currentIndex=0;this.currentFrame=this.frames[this.currentIndex]}createFrames(){const res=[];for(let i=0;i<this.config.frames.length;i++){const frameBase=this.config.frames[i];res.push(new AnimationFrame(frameBase.col,frameBase.row,this.sprite))}return res}normalStep(self){if(self.currentIndex<self.frames.length-1){self.currentIndex+=1;self.currentFrame=self.frames[self.currentIndex];self.currentFrame.set()}else{self.repeatCounter+=1;if(self.config.yoyo){self.stop();self.playReverse()}else if(self.repeatCounter<self.repeat){self.currentIndex=0;self.currentFrame=self.frames[self.currentIndex];self.currentFrame.set()}}}reverseStep(self){if(self.currentIndex<self.reversedFrames.length-1){self.currentIndex+=1;self.currentFrame=self.reversedFrames[self.currentIndex];self.currentFrame.set()}else{self.repeatCounter+=1;if(self.config.yoyo){self.stopReverse();self.play()}else if(self.repeatCounter<self.repeat){self.currentIndex=0;self.currentFrame=self.frames[self.currentIndex];self.currentFrame.set()}}}setRepeat(repeat){this.repeat=repeat;this.animationNormalTimer.repeat=this.repeat}setRepeatReverse(repeat){this.repeat=repeat;this.animationReverseTimer.repeat=this.repeat}play(){this.countBy=this.config.useDelta?this.game.deltaTime:1e3/this.config.frameRate;if(this.delayTimer){this.delayTimer.count(this.countBy);if(this.delayTimer.done){this.animationNormalTimer.count(this.countBy)}}else{this.animationNormalTimer.count(this.countBy)}}playReverse(){this.countBy=this.config.useDelta?this.game.deltaTime:1e3/this.config.frameRate;if(this.delayTimer){this.delayTimer.count(this.countBy);if(this.delayTimer.done){this.animationReverseTimer.count(this.countBy)}}else{this.animationReverseTimer.count(this.countBy)}}pause(){this.animationNormalTimer.pause()}pauseReverse(){this.animationReverseTimer.pause()}resume(){this.animationNormalTimer.resume()}resumeReverse(){this.animationReverseTimer.resume()}stop(){this.animationNormalTimer.stop()}stopReverse(){this.animationReverseTimer.stop()}restart(){this.animationNormalTimer.reset()}restartReverse(){this.animationReverseTimer.reset()}}class AnimationState{constructor(key,animation,vector,autoAdvance){this.key=key;this.animation=animation;this.autoAdvance=autoAdvance;this.vector=vector;this.connections=[]}}class StateMachine{constructor(config,animations){this.config=config;this.animations=animations;this.connections=[];this.config.connections.forEach(base=>{if(base.connType==="one"){this.connectTo(base.from,base.to)}else{this.connectLoop(base.from,base.to)}});this.currentState=this.connections.find(conn=>conn.find(state=>state.key===this.config.defaultState))}connectTo(from,to){const fromAnim=this.animations.find(anim=>anim.config.key===from.key);const toAnim=this.animations.find(anim=>anim.config.key===to.key);if(fromAnim&&toAnim){const fromState=new AnimationState(fromAnim.key,fromAnim,from.vector,from.autoAdvance||false);const toState=new AnimationState(toAnim.key,toAnim,to.vector,to.autoAdvance||false);this.connections.push([fromState,toState])}}connectLoop(from,to){const fromAnim=this.animations.find(anim=>anim.config.key===from.key);const toAnim=this.animations.find(anim=>anim.config.key===to.key);if(fromAnim&&toAnim){const fromState=new AnimationState(fromAnim.key,fromAnim,from.vector,from.autoAdvance||false);const toState=new AnimationState(toAnim.key,toAnim,to.vector,to.autoAdvance||false);fromState.connections.push(toState);toState.connections.push(fromState);this.connections.push([fromState,toState],[toState,fromState])}}travel(vector){const state=this.connections.find(connArray=>connArray.find(state=>state.vector.equals(vector)));if(this.canTravel(state.key)){this.currentState=state}}canTravel(dest){return this.currentState.connections.find(state=>state.key===dest)?true:false}}class AnimationManager{constructor(game,scene,sprite,defaultAnimation){this.game=game;this.scene=scene;this.sprite=sprite;this.animations=[];this.currentAnimation=this.add(defaultAnimation)}createStateMachine(config,animations){return new StateMachine(config,animations)}setCurrentAnimation(key){this.currentAnimation=this.get(key)}add(config){const anim=new animation_Animation(config,this.game,this.scene,this.sprite);this.animations.push(anim);return anim}remove(key){const anim=this.get(key);if(anim){this.animations.splice(this.getIndex(key))}}get(key){return this.animations.find(anim=>anim.key===key)}getIndex(key){return this.animations.findIndex(anim=>anim.key===key)}clear(){this.animations=[]}setRepeat(repeat){this.currentAnimation.setRepeat(repeat)}setRepeatReverse(repeat){this.currentAnimation.setRepeatReverse(repeat)}play(){this.currentAnimation.play()}playReverse(){this.currentAnimation.playReverse()}pause(){this.currentAnimation.pause()}pauseReverse(){this.currentAnimation.pause()}resume(){this.currentAnimation.resume()}resumeReverse(){this.currentAnimation.resumeReverse()}stop(){this.currentAnimation.stop()}stopReverse(){this.currentAnimation.stopReverse()}restart(){this.currentAnimation.restart()}restartReverse(){this.currentAnimation.restartReverse()}}class Sprite extends GameObject{constructor(x,y,w,h,textureKey,game,scene,currentRow,currentCol){super("sprite",x,y,w,h,0,scene.loader.textureStack.find(t=>t.key===textureKey).value,game,scene);this.currentRow=currentRow;this.currentCol=currentCol;const defaultAnimConfig={key:"__default",frameRate:0,frames:[{col:this.currentCol,row:this.currentRow}]};this.anims=new AnimationManager(this.game,this.scene,this,defaultAnimConfig);this.defaultAnim=this.anims.get("__default")}_draw(){if(this.game.renderer.ctx){if(this.texture.dataType==="sheet"){this.game.renderer.drawSprite(this.position.x,this.position.y,this.w,this.h,this.texture,this.currentRow,this.currentCol)}else{this.game.renderer.drawSprite(this.position.x,this.position.y,this.w,this.h,this.texture)}}else{new debug.Error("CanvasRenderingContext2D is undefined. HTMLCanvasElement is undefined.")}}setScale(scale){if(scale.width){this.w=scale.width;this.texture.setScale({width:this.w})}if(scale.height){this.h=scale.height;this.texture.setScale({height:this.h})}}setImagePath(imgpath){this.texture.texture.src=imgpath}setFillColor(color){new debug.Warn("Cannot fill color of a sprite. Changed the image path instead. Use setImagePath instead.")}}function getValuesHSL(hsl){let res=hsl.substring(4,hsl.length-1).replace(/ /g,"").replace(/%/g,"").split(",");return res}function isHex(str){return/^#[0-9A-F]{6}|#[0-9A-F]{3}$/i.test(str)}function hexToRGBA(hex,alpha){if(isHex(hex)){hex=hex.replace("#","");if(hex.length===3){hex=hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2]}const[r,g,b]=hex.match(/\w\w/g).map(x=>parseInt(x,16));return`rgba(${r},${g},${b},${alpha})`}else{new debug.Error("Cannot convert hex to RGBA. Invalid hex.");return"rgba(0, 0, 0, 1)"}}function hslToRGB(h,s,l){let r,g,b;h=parseInt(h);s=parseInt(s);l=parseInt(l);if(s===0){r=g=b=l}else{const hue2rgb=function hue2rgb(p,q,t){if(t<0)t+=1;if(t>1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p};const q=l<.5?l*(1+s):l+s-l*s;const p=2*l-q;r=hue2rgb(p,q,h+1/3);g=hue2rgb(p,q,h);b=hue2rgb(p,q,h-1/3)}return`rgb(${Math.round(r*255)}, ${Math.round(g*255)}, ${Math.round(b*255)})`}function isHSL(str){return/hsl[(]\s*0*(?:[12]?\d{1,2}|3(?:[0-5]\d|60))\s*(?:\s*,\s*0*(?:\d\d?(?:\.\d+)?\s*%|\.\d+\s*%|100(?:\.0*)?\s*%)){2}\s*[)]$/.test(str)}function isRGB(str){return/^rgb[(](?:\s*0*(?:\d\d?(?:\.\d+)?(?:\s*%)?|\.\d+\s*%|100(?:\.0*)?\s*%|(?:1\d\d|2[0-4]\d|25[0-5])(?:\.\d+)?)\s*(?:,(?![)])|(?=[)]))){3}[)]$/.test(str)}function rgbToRGBA(color,alpha){let new_col="";new_col=color.replace(/rgb/i,"rgba");new_col=new_col.replace(/\)/i,`,${alpha})`);return new_col}function convertColorToRGBA(color,alpha){let res="";if(isHex(color)){res=hexToRGBA(color,alpha)}if(isRGB(color)){res=rgbToRGBA(color,alpha)}if(isHSL(color)){const values=getValuesHSL(color);const a=hslToRGB(values[0],values[1],values[2]);res=rgbToRGBA(a,alpha)}return res}class StaticLight extends GameObject{constructor(x,y,r,fillColor,alpha,game,scene){super("circle",x,y,0,0,r,Texture.fromColor(fillColor,r,r),game,scene);this.r=r;this.alpha=alpha;this.game=game;this.visible=true;this.zIndex=2;this.color=fillColor;this.color=convertColorToRGBA(this.color,this.alpha);this.texture.texture=this.color}_draw(){if(this.game.renderer.ctx){this.game.renderer.setBlendMode("lighten");this.game.renderer.drawCircle(this.position.x,this.position.y,this.r,this.texture.texture);this.game.renderer.setBlendMode("source-over")}else{new debug.Error("CanvasRenderingContext2D is undefined. Canvas is undefined.")}}setFillColorAlpha(color,alpha){this.color=convertColorToRGBA(color,alpha)}}const DisplayEvents={SET_SCALE:"DISPLAY_SET_SCALE",FULLSCREEN:"DISPLAY_FULLSCREEN",UNFULLSCREEN:"DISPLAY_UNFULLSCREEN",FOCUS:"DISPLAY_FOCUS",BLUR:"DISPLAY_BLUR"};const displayEvents=DisplayEvents;const GameEvents={FOCUS:"GAME_FOCUS",BLUR:"GAME_BLUR",START:"GAME_START",STOP:"GAME_STOP",LOAD_BEGIN:"GAME_LOAD_BEGIN",LOAD_FINISH:"GAME_LOAD_FINISH",SCENE_ADD:"GAME_SCENE_ADD",SCENE_REMOVE:"GAME_SCENE_REMOVE",LOAD_SCENE:"GAME_LOAD_SCENE",SWITCH_SCENE:"GAME_SWITCH_SCENE",SHOW_SCENE:"GAME_SHOW_SCENE",DRAW_SPLASH:"GAME_DRAW_SPLASH",CLEAR_FRAME:"GAME_CLEAR_FRAME",SET_SCALE:"GAME_SET_SCALE",SET_BACKGROUND:"GAME_SET_BACKGROUND",SYNC_CACHE:"GAME_SYNC_CACHE",LOCK_POINTER:"GAME_LOCK_POINTER",UNLOCK_POINTER:"GAME_UNLOCK_POINTER",CONTEXT_LOST:"GAME_CONTEXT_LOST",CONTEXT_RESTORED:"GAME_CONTEXT_RESTORED"};const gameEvents=GameEvents;const RendererEvents={PIPELINE_POOL:"RENDERER_PIPELINE_POOL",CLEAR_FRAME:"CLEAR_FRAME"};const rendererEvents=RendererEvents;const ButtonEvents={CLICK:"BUTTON_CLICK",HOVER:"BUTTON_HOVER",NOTHOVER:"BUTTON_NOTHOVER"};const buttonEvents=ButtonEvents;const CutsceneEvents={START:"CUTSCENE_START",END:"CUTSCENE_END",NEXT:"CUTSCENE_NEXT"};const cutsceneEvents=CutsceneEvents;const GroupEvents={ADD:"GROUP_ADD",REMOVE:"GROUP_REMOVE"};const groupEvents=GroupEvents;const EVENTS={BUTTON:buttonEvents,GROUP:groupEvents,CUTSCENE:cutsceneEvents,GAME:gameEvents,RENDERER:rendererEvents,DISPLAY:displayEvents};const events=EVENTS;class UI extends GameObject{constructor(shape,x,y,w,h,r,texture,game,scene){super(shape,x,y,w,h,r,texture,game,scene)}}class Button extends UI{constructor(shape,x,y,w,h,r,fillColorOrIMGPath,text,game,scene){super(shape,x,y,w,h,r,Texture.fromEither(fillColorOrIMGPath,w,h),game,scene);this.shape=shape;this.text=text;this.hovering=false;this.zIndex=Duck.Layers.Rendering.zIndex.button;if(this.game.canvas){this.game.canvas.addEventListener("click",e=>{const rect=this.game.canvas.getBoundingClientRect();const mousePos={x:e.clientX-rect.left,y:e.clientY-rect.top};const buttonPos={x:this.position.x,y:this.position.y};if(this.scene.currentCamera){const coords=this.scene.currentCamera.worldToScreen(this.position.x,this.position.y,this);buttonPos.x=coords.position.x;buttonPos.y=coords.position.y}if(rectToRectIntersect({position:buttonPos,w:this.w,h:this.h},{position:{x:mousePos.x,y:mousePos.y},w:1,h:1})&&this.scene.visible){this.game.eventEmitter.emit(events.BUTTON.CLICK,{x:mousePos.x,y:mousePos.y,type:events.BUTTON.CLICK})}});this.game.canvas.addEventListener("mousemove",e=>{const rect=this.game.canvas.getBoundingClientRect();const mousePos={x:e.clientX-rect.left,y:e.clientY-rect.top};const buttonPos={x:this.position.x,y:this.position.y};if(this.scene.currentCamera){const coords=this.scene.currentCamera.worldToScreen(this.position.x,this.position.y,this);buttonPos.x=coords.position.x;buttonPos.y=coords.position.y}if(rectToRectIntersect({position:buttonPos,w:this.w,h:this.h},{position:{x:mousePos.x,y:mousePos.y},w:1,h:1})&&this.scene.visible){this.game.eventEmitter.emit(events.BUTTON.HOVER,{x:mousePos.x,y:mousePos.y,type:events.BUTTON.HOVER});this.hovering=true}else if(this.scene.visible){this.game.eventEmitter.emit(events.BUTTON.NOTHOVER,{x:mousePos.x,y:mousePos.y,type:events.BUTTON.NOTHOVER});this.hovering=false}})}else{new debug.Error("Cannot add event listeners to canvas for mouseover and click for button. Canvas element is undefined or null.")}}_draw(){if(this.game.renderer.ctx){switch(this.shape){case"rect":this.game.renderer.drawRect(this.position.x,this.position.y,this.w,this.h,this.texture.texture);break;case"roundrect":this.game.renderer.drawRoundRect(this.position.x,this.position.y,this.w,this.h,this.r,this.texture.texture);break;case"sprite":this.game.renderer.drawSprite(this.position.x,this.position.y,this.w,this.h,this.texture);break;default:new debug.Error("Cannot draw button. Shape must be a rect, roundrect, or sprite.");break}}}on(type,func){this.game.eventEmitter.on(`BUTTON_${type}`,func)}off(type){this.game.eventEmitter.off(`BUTTON_${type}`)}}function extractNumbers(string){var _a;return Number((_a=string.match(/\d/g))===null||_a===void 0?void 0:_a.join(""))}class Text extends UI{constructor(text,config,game,scene){super("rect",config.x,config.y,0,0,0,Texture.fromColor(text,0,0),game,scene);this.text=text;this.config=config;this.game=game;this.w=this.game.renderer.measureText(config.styles.fontCSS,this.text).width;this.h=extractNumbers(config.styles.fontCSS);this.texture.setScale({width:this.w,height:this.h});this.zIndex=Duck.Layers.Rendering.zIndex.text}_draw(){if(this.game.renderer.ctx){this.game.renderer.setFont(this.config.styles.fontCSS);this.game.renderer.setLineWidth(this.config.styles.strokeWidth||1);this.game.renderer.setStrokeColor(this.config.styles.strokeColor||"#000");this.game.renderer.setFillColor(this.config.styles.fillColor||"#000");if(this.config.method==="draw"){this.game.renderer.drawText(this.text,this.position.x,this.position.y,this.config.styles.maxWidth)}if(this.config.method==="stroke"){this.game.renderer.strokeText(this.text,this.position.x,this.position.y,this.config.styles.maxWidth)}if(this.config.method==="draw-stroke"){this.game.renderer.drawText(this.text,this.position.x,this.position.y,this.config.styles.maxWidth);this.game.renderer.strokeText(this.text,this.position.x,this.position.y,this.config.styles.maxWidth)}}}setText(text){this.text=text}}class Particle extends GameObject{constructor(shape,w,h,r,fillColorOrIMGPath,game,scene){super(shape,0,0,w,h,r,Texture.fromEither(fillColorOrIMGPath,w,h),game,scene);this.originalFillColorOrIMGPath=fillColorOrIMGPath;this.w=w;this.h=h;this.r=r;this.floatVelocity=Vector2.ZERO;this.zIndex=Duck.Layers.Rendering.zIndex.particle;this.visible=false;this.age=0;setInterval(()=>{this.age++},1e3)}_draw(){if(this.game.renderer.ctx){switch(this.shape){case"circle":this.game.renderer.drawCircle(this.position.x,this.position.y,this.r,this.texture.texture);break;case"rect":this.game.renderer.drawRect(this.position.x,this.position.y,this.w,this.h,this.texture.texture);break;case"roundrect":this.game.renderer.drawRoundRect(this.position.x,this.position.y,this.w,this.h,this.r,this.texture.texture);break;case"sprite":this.game.renderer.drawSprite(this.position.x,this.position.y,this.w,this.h,this.texture.texture);break;default:if(this.game.config.debug){new debug.Warn('Cannot draw Particle. Particle Shape is not a "circle", "rect", "roundrect", or "sprite".')}break}}else{new debug.Error("Cannot draw particle. CanvasRenderingContext2D is undefined.")}}_update(){var _a;this.position.x+=this.velocity.x*this.game.smoothDeltaTime;this.position.y+=this.velocity.y*this.game.smoothDeltaTime;this.position.x+=this.floatVelocity.x*this.game.smoothDeltaTime;this.position.y+=this.floatVelocity.y*this.game.smoothDeltaTime;this.position.x=clamp(this.position.x,this.bounds.x,this.bounds.w);this.position.y=clamp(this.position.y,this.bounds.y,this.bounds.h);this.velocity.x=0;this.velocity.y=0;if((_a=this.game.config.physics)===null||_a===void 0?void 0:_a.gravity){if(this.options.type==="KinematicBody"||this.options.type==="RigidBody"){this.applyGravity(Vector2.fromVector2Like(this.game.config.physics.gravity))}}this.attachedChildren.forEach(object=>{const pos=this.position.clone();pos.subtract(object.attachOffset);object.position=pos;if(object.hitbox){object.hitbox.position=object.position.clone().add(object.hitbox.offset)}})}setImagePath(imagePath){this.texture.setImagePath(imagePath)}}class map_Map{constructor(origin,tileLayers,game,scene){this.id=uniqueID();this.shape="map";this.origin=Vector2.fromVector2Like(origin);this.tileLayers=tileLayers;this.game=game;this.scene=scene;this.visible=true;this.zIndex=2;this.culled=true}_draw(){}}class Camera{constructor(game,scene){this.lerpX=1;this.lerpY=1;this.game=game;this.scene=scene;this.distance=1e3;this.isMain=false;if(scene.mainCamera===this){this.isMain=true}this.lookAt=[0,0];this.fieldOfView=Math.PI/4;this.viewport={left:0,right:0,top:0,bottom:0,w:0,h:0,scale:[1,1]};this.bounds;this.following;this.updateViewport()}begin(){this.game.renderer.save();this.applyScale();this.applyTranslation();if(this.following){if(this.following.shape==="rect"){if(this.bounds){if(rectToRectIntersect(this.following,this.bounds)){this.lookAt[0]=lerp(this.lookAt[0],this.following.getCenterX(),this.lerpX);this.lookAt[1]=lerp(this.lookAt[1],this.following.getCenterY(),this.lerpY)}}else{this.lookAt[0]=lerp(this.lookAt[0],this.following.getCenterX(),this.lerpX);this.lookAt[1]=lerp(this.lookAt[1],this.following.getCenterY(),this.lerpY)}}if(this.following.shape==="circle"){if(this.bounds){if(circleRectCollision(this.following,this.bounds)){this.lookAt[0]=lerp(this.lookAt[0],this.following.getCenterX(),this.lerpX);this.lookAt[1]=lerp(this.lookAt[1],this.following.getCenterY(),this.lerpY)}}else{this.lookAt[0]=lerp(this.lookAt[0],this.following.getCenterX(),this.lerpX);this.lookAt[1]=lerp(this.lookAt[1],this.following.getCenterY(),this.lerpY)}}this.updateViewport()}}end(){this.game.renderer.restore()}applyScale(){this.game.renderer.scale(this.viewport.scale[0],this.viewport.scale[1])}applyTranslation(){this.game.renderer.translate(-this.viewport.left,-this.viewport.top)}updateViewport(){if(this.game.renderer.ctx){let cWidth=this.game.canvas.width;let cHeight=this.game.canvas.height;if(this.game.config.dprScale&&window.devicePixelRatio!==1){cWidth=Number(this.game.canvas.style.width.replace("px",""));cHeight=Number(this.game.canvas.style.height.replace("px",""));this.distance=1e3/window.devicePixelRatio}this.aspectRatio=cWidth/cHeight;this.viewport.w=this.distance*Math.tan(this.fieldOfView);this.viewport.h=this.viewport.w/this.aspectRatio;this.viewport.left=this.lookAt[0]-this.viewport.w/2;this.viewport.top=this.lookAt[1]-this.viewport.h/2;this.viewport.right=this.viewport.left+this.viewport.w;this.viewport.bottom=this.viewport.top+this.viewport.h;this.viewport.scale[0]=cWidth/this.viewport.w;this.viewport.scale[1]=cHeight/this.viewport.h}else{new debug.Error("Cannot update camera. CanvasRenderingContext2D is undefined.")}}setZoom(z){this.distance=z;this.updateViewport()}setZoomSmooth(intervalMS,smoothValue,z){let operation="add";if(this.distance<z){operation="add"}else{operation="subtract"}const int=setInterval(()=>{if(operation==="add"){if(this.distance<z){this.distance+=smoothValue}else{clearInterval(int);if(this.game.config.debug){new debug.Log("Reached target camera Zoom with setZoomSmooth")}}}else{if(this.distance>z){this.distance-=smoothValue}else{clearInterval(int);if(this.game.config.debug){new debug.Log("Reached target camera Zoom with setZoomSmooth")}}}},intervalMS)}moveTo(x,y){this.lookAt[0]=x;this.lookAt[1]=y;this.updateViewport()}startFollow(gameObject,lerpX=1,lerpY=1){this.following=gameObject;this.lerpX=lerpX;this.lerpY=lerpY}stopFollow(){this.following=undefined}screenToWorld(x,y,obj){obj.position.x=x/this.viewport.scale[0]+this.viewport.left;obj.position.y=y/this.viewport.scale[1]+this.viewport.top;return obj}worldToScreen(x,y,obj){obj.position.x=(x-this.viewport.left)*this.viewport.scale[0];obj.position.y=(y-this.viewport.top)*this.viewport.scale[1];return obj}setFOV(f){this.fieldOfView=f}setFOVSmooth(intervalMS,smoothValue,f){let operation="add";if(this.fieldOfView<f){operation="add"}else{operation="subtract"}const int=setInterval(()=>{if(operation==="add"){if(this.fieldOfView<f){this.fieldOfView+=smoothValue}else{clearInterval(int);if(this.game.config.debug){new debug.Log("Reached target camera FOV with setFOVSmooth")}}}else{if(this.fieldOfView>f){this.fieldOfView-=smoothValue}else{clearInterval(int);if(this.game.config.debug){new debug.Log("Reached target camera FOV with setFOVSmooth")}}}},intervalMS)}resetFOV(){this.fieldOfView=Math.PI/4}resetZoom(){this.distance=1e3}setBounds(bounds){this.bounds=bounds}shake(intervalMS,timeMS,v){const int=setInterval(()=>{const r=randomInt(1,4);if(r===1){this.lookAt[0]+=v}if(r===2){this.lookAt[0]-=v}if(r===3){this.lookAt[1]+=v}if(r===2){this.lookAt[1]+=v}this.updateViewport()},intervalMS);setTimeout(()=>{clearInterval(int)},timeMS)}cull(renderableObjects,options){const preserveVisibility=options?options.preserveVisibility:true;const modifyPhysicsEnable=options?options.modifyPhysicsEnable:true;const visibleObjects=this.scene.displayList.visibilityFilter(true);const culledObjects=visibleObjects.filter(r=>renderableObjects.find(_r=>_r.id===r.id));const nonCulledObjects=visibleObjects.filter(r=>!culledObjects.includes(r));for(const culledObject of culledObjects){if(culledObject instanceof map_Map){continue}if(preserveVisibility){culledObject.culled=true}else{culledObject.visible=true}if(modifyPhysicsEnable){if(culledObject instanceof PhysicsBody){culledObject.enabled=true}}}for(const nonCulledObject of nonCulledObjects){if(nonCulledObject instanceof map_Map){continue}if(preserveVisibility){nonCulledObject.culled=false}else{nonCulledObject.visible=false}if(modifyPhysicsEnable){if(nonCulledObject instanceof PhysicsBody){nonCulledObject.enabled=false}}}this.game.renderer.pipeline.pool()}autoCull(options){const preserveVisibility=options?options.preserveVisibility:true;const modifyPhysicsEnable=options?options.modifyPhysicsEnable:true;const objects=this.scene.displayList.list;const culledObjects=objects.filter(r=>{if(r instanceof Rect||r instanceof RoundRect||r instanceof Sprite||r instanceof Button||r instanceof Text){if(rectToRectIntersect(r,{position:{x:this.viewport.left,y:this.viewport.top},w:this.viewport.w,h:this.viewport.h})){return true}else{return false}}if(r instanceof Circle||r instanceof StaticLight||r instanceof Particle){if(circleRectCollision(r,{position:{x:this.viewport.left,y:this.viewport.top},w:this.viewport.w,h:this.viewport.h})){return true}else{return false}}return false});const nonCulledObjects=objects.filter(r=>!culledObjects.includes(r));for(const culledObject of culledObjects){if(culledObject instanceof map_Map){continue}if(preserveVisibility){culledObject.culled=true}else{culledObject.visible=true}if(modifyPhysicsEnable){if(culledObject instanceof PhysicsBody){culledObject.enabled=true}}}for(const nonCulledObject of nonCulledObjects){if(nonCulledObject instanceof map_Map){continue}if(preserveVisibility){nonCulledObject.culled=false}else{nonCulledObject.visible=false}if(modifyPhysicsEnable){if(nonCulledObject instanceof PhysicsBody){nonCulledObject.enabled=false}}}this.game.renderer.pipeline.pool()}get defaultZoom(){if(this.game.config.dprScale){if(this.game.config.debug){new debug.Log("Getter defaultZoom returned default zoom with dpr scaling. (info)")}return 1e3/window.devicePixelRatio}else{return 1e3}}get defaultFOV(){return Math.PI/4}}const version="2.1.0";const startup=` šŸ¦† DuckEngine - ${version} šŸ¦† https://github.com/ksplatdev/DuckEngine MIT License Copyright (c) 2021 Bleart Emini `;function dprScale(canvas,context,width,height){const devicePixelRatio=window.devicePixelRatio||1;const backingStoreRatio=context.webkitBackingStorePixelRatio||context.mozBackingStorePixelRatio||context.msBackingStorePixelRatio||context.oBackingStorePixelRatio||context.backingStorePixelRatio||1;const ratio=devicePixelRatio/backingStoreRatio;if(devicePixelRatio!==backingStoreRatio){canvas.width=width*ratio;canvas.height=height*ratio;canvas.style.width=width+"px";canvas.style.height=height+"px"}else{canvas.width=width;canvas.height=height;canvas.style.width="";canvas.style.height=""}context.scale(ratio,ratio)}class EventEmitter{constructor(){this.callbacks={}}on(event,cb){if(!this.callbacks[event])this.callbacks[event]=[];this.callbacks[event].push(cb)}off(event){if(this.callbacks[event]){this.callbacks[event]=[]}}emit(event,...args){const cbs=this.callbacks[event];if(cbs){cbs.forEach(cb=>{if(args){cb(...args)}else{cb()}})}}}function detectBrowser(){const isOpera=!!window.opr&&!!opr.addons||!!window.opera||navigator.userAgent.indexOf(" OPR/")>=0;const isFirefox=typeof InstallTrigger!=="undefined";const isSafari=/constructor/i.test(window.HTMLElement)||function(p){return p.toString()==="[object SafariRemoteNotification]"}(!window["safari"]||typeof safari!=="undefined"&&window["safari"].pushNotification);const isIE=false||!!document.documentMode;const isEdge=!isIE&&!!window.StyleMedia;const isChrome=!!window.chrome&&(!!window.chrome.webstore||!!window.chrome.runtime);const isEdgeChromium=isChrome&&navigator.userAgent.indexOf("Edg")!==-1;const isBlink=(isChrome||isOpera)&&!!window.CSS;const res={isOpera:isOpera?"Opera":false,isFirefox:isFirefox?"Firefox":false,isIE:isIE?"IE":false,isEdge:isEdge?"Edge":false,isEdgeChromium:isEdgeChromium?"EdgeChromium":false,isBlink:isBlink?"Blink":false,isSafari:isSafari?"Safari":false};return res.isOpera||res.isFirefox||res.isIE||res.isEdge||res.isEdgeChromium||res.isBlink||res.isSafari||"Unknown"}function averageArray(v){return v.reduce((a,b)=>a+b)/v.length}function smoothOut(vector,variance){const t_avg=averageArray(vector)*variance;const ret=Array(vector.length);for(let i=0;i<vector.length;i++){(function(){const prev=i>0?ret[i-1]:vector[i];const next=i<vector.length?vector[i]:vector[i-1];ret[i]=averageArray([t_avg,averageArray([prev,vector[i],next])])})()}return averageArray(ret)}class PluginManager{constructor(){this.plugins={}}registerPlugin(plugin){const foundPlugin=this.find(plugin.name);if(!foundPlugin){this.plugins[plugin.name]=plugin}else{new debug.Error(`Cannot register plugin with name "${plugin.name}". Plugin with that name already exists.`)}}unregisterPlugin(name){const plugin=this.find(name);if(plugin){delete this.plugins[name]}}call(name){const plugin=this.find(name);if(plugin){plugin.func(...plugin.args)}}find(name){return this.plugins[name]}}class CacheManager{constructor(){this.cache={};this.storageIdentifier="DuckEngine_CacheManager_";this.sync()}sync(){this.cache=Object.assign({},localStorage)}set(name,value){this.cache[name]=value;localStorage.setItem(`${this.storageIdentifier}${name}`,value)}get(name){return localStorage.getItem(`${this.storageIdentifier}${name}`)||this.cache[name]}delete(name){if(this.has(name)){delete this.cache[name];localStorage.removeItem(`${this.storageIdentifier}${name}`)}else{new debug.Error(`CacheManager: Cannot delete from values with name "${name}". "${name}" doe