-
-
Notifications
You must be signed in to change notification settings - Fork 186
/
p5play.min.js
1 lines (1 loc) · 132 KB
/
p5play.min.js
1
if(typeof planck!="object"){if(typeof process=="object"){global.planck=require("./planck.min.js")}else throw"planck.js must be loaded before p5play"}p5.prototype.registerMethod("init",(function p5playInit(){const $=this;const pl=planck;if(typeof process!="object"&&window._p5play_gtagged!=false){let script=document.createElement("script");script.src="https://www.googletagmanager.com/gtag/js?id=G-EHXNCTSYLK";script.async=true;document.head.append(script);window._p5play_gtagged=true;script.onload=()=>{window.dataLayer??=[];window.gtag=function(){dataLayer.push(arguments)};gtag("js",new Date);gtag("config","G-EHXNCTSYLK");gtag("event","p5play_v3_26")}}const DEGREES=$.DEGREES;$.angleMode(DEGREES);const scaleTo=(x,y,tileSize)=>new pl.Vec2(x*tileSize/$.world.meterSize,y*tileSize/$.world.meterSize);const scaleXTo=(x,tileSize)=>x*tileSize/$.world.meterSize;const scaleFrom=(x,y,tileSize)=>new pl.Vec2(x/tileSize*$.world.meterSize,y/tileSize*$.world.meterSize);const scaleXFrom=(x,tileSize)=>x/tileSize*$.world.meterSize;const linearSlop=pl.Settings.linearSlop;const angularSlop=pl.Settings.angularSlop/60;const isSlop=val=>Math.abs(val)<=linearSlop;const fixRound=(val,slop)=>Math.abs(val-Math.round(val))<=(slop||linearSlop)?Math.round(val):val;const minAngleDist=(ang,rot)=>{let full=$._angleMode==DEGREES?360:$.TWO_PI;let dist1=(ang-rot)%full;let dist2=(full-Math.abs(dist1))*-Math.sign(dist1);return(Math.abs(dist1)<Math.abs(dist2)?dist1:dist2)||0};const eventTypes={_collisions:["_collides","_colliding","_collided"],_overlappers:["_overlaps","_overlapping","_overlapped"]};this.P5Play=class{constructor(){this.sprites={};this.groups={};this.groupsCreated=0;this.spritesCreated=0;this.spritesDrawn=0;this.images={};this.disableImages=false;this.palettes=[];this.friendlyRounding=true;this.storeRemovedGroupRefs=true;this.snapToGrid=false;this.gridSize=.5;this.os={};this.context="web";if(window.matchMedia)this.hasMouse=window.matchMedia("(any-hover: none)").matches?false:true;else this.hasMouse=true;this.standardizeKeyboard=false;if(typeof navigator=="object"){let idx=navigator.userAgent.indexOf("iPhone OS");if(idx>-1){let version=navigator.userAgent.substring(idx+10,idx+12);this.os.platform="iOS";this.os.version=version}else{let pl=navigator.userAgentData?.platform;if(!pl&&navigator.platform){pl=navigator.platform.slice(3);if(pl=="Mac")pl="macOS";else if(pl=="Win")pl="Windows";else if(pl=="Lin")pl="Linux"}this.os.platform=pl}}this.renderStats=false;this._renderStats={x:10,y:20,font:"monospace"};this._fps=60;this._fpsArr=[60];this._collides={};this._colliding={};this._collided={};this._overlaps={};this._overlapping={};this._overlapped={}}onImageLoad(){}};this.p5play=new $.P5Play;delete $.P5Play;let usePhysics=true;let timeScale=1;const log=console.log;this.log=console.log;this.Sprite=class{constructor(x,y,w,h,collider){this._isSprite=true;this.idNum;let args=[...arguments];let group,ani;if(args[0]!==undefined&&args[0]._isGroup){group=args[0];args=args.slice(1)}if(args[0]!==undefined&&(typeof args[0]=="string"||args[0]instanceof $.Ani||args[0]instanceof p5.Image)){ani=args[0];args=args.slice(1)}if(args.length==1&&typeof args[0]=="number"){throw new FriendlyError("Sprite",0,[args[0]])}if(!Array.isArray(args[0])){x=args[0];y=args[1];w=args[2];h=args[3];collider=args[4]}else{x=undefined;y=undefined;w=args[0];h=undefined;collider=args[1];if(Array.isArray(collider)){throw new FriendlyError("Sprite",1,[`[[${w}], [${h}]]`])}}if(typeof w=="string"){collider=w;w=undefined}if(typeof h=="string"){if(isColliderType(h)){collider=h}else{w=getRegularPolygon(w,h)}h=undefined}this.idNum=$.p5play.spritesCreated;this._uid=1e3+this.idNum;$.p5play.sprites[this._uid]=this;$.p5play.spritesCreated++;this.groups=[];this.animations=new $.Anis;this.joints=[];this.joints.removeAll=()=>{while(this.joints.length){this.joints.at(-1).remove()}};this.watch;this.mod={};this._removed=false;this._life=2147483647;this._visible=true;this._pixelPerfect=false;this._aniChangeCount=0;this._draw=()=>this.__draw();this._hasOverlap={};this._collisions={};this._overlappers={};group??=$.allSprites;this._tile="";this.tileSize=group.tileSize||1;let _this=this;this._position={x:0,y:0};this._pos=$.createVector.call($);Object.defineProperty(this._pos,"x",{get(){if(!_this.body||!usePhysics)return _this._position.x;let x=_this.body.getPosition().x/_this.tileSize*$.world.meterSize;return $.p5play.friendlyRounding?fixRound(x):x},set(val){_this._position.x=val;if(_this.body){let pos=new pl.Vec2(val*_this.tileSize/$.world.meterSize,_this.body.getPosition().y);_this.body.setPosition(pos)}}});Object.defineProperty(this._pos,"y",{get(){if(!_this.body||!usePhysics)return _this._position.y;let y=_this.body.getPosition().y/_this.tileSize*$.world.meterSize;return $.p5play.friendlyRounding?fixRound(y):y},set(val){_this._position.y=val;if(_this.body){let pos=new pl.Vec2(_this.body.getPosition().x,val*_this.tileSize/$.world.meterSize);_this.body.setPosition(pos)}}});this._canvasPos=$.createVector.call($);Object.defineProperty(this._canvasPos,"x",{get(){let x=_this._pos.x-$.camera.x;if($.canvas.renderer=="2d")x+=$.canvas.hw/$.camera._zoom;return x}});Object.defineProperty(this._canvasPos,"y",{get(){let y=_this._pos.y-$.camera.y;if($.canvas.renderer=="2d")y+=$.canvas.hh/$.camera._zoom;return y}});this._velocity={x:0,y:0};this._direction=0;this._vel=$.createVector.call($);Object.defineProperties(this._vel,{x:{get(){let val;if(_this.body)val=_this.body.getLinearVelocity().x;else val=_this._velocity.x;val/=_this.tileSize;return $.p5play.friendlyRounding?fixRound(val):val},set(val){val*=_this.tileSize;if(_this.body){_this.body.setLinearVelocity(new pl.Vec2(val,_this.body.getLinearVelocity().y))}else{_this._velocity.x=val}if(val||this.y)_this._direction=this.heading()}},y:{get(){let val;if(_this.body)val=_this.body.getLinearVelocity().y;else val=_this._velocity.y;val/=_this.tileSize;return $.p5play.friendlyRounding?fixRound(val):val},set(val){val*=_this.tileSize;if(_this.body){_this.body.setLinearVelocity(new pl.Vec2(_this.body.getLinearVelocity().x,val))}else{_this._velocity.y=val}if(val||this.x)_this._direction=this.heading()}}});this._mirror={_x:1,_y:1,get x(){return this._x<0},set x(val){if(_this.watch)_this.mod[20]=true;this._x=val?-1:1},get y(){return this._y<0},set y(val){if(_this.watch)_this.mod[20]=true;this._y=val?-1:1}};this._heading="right";this._layer=group._layer;this._layer??=$.allSprites._getTopLayer()+1;if(group.dynamic)collider??="dynamic";if(group.kinematic)collider??="kinematic";if(group.static)collider??="static";collider??=group.collider;if(!collider||typeof collider!="string"){collider="dynamic"}this.collider=collider;x??=group.x;if(x===undefined){if($.canvas?.renderer=="2d"&&!$._webgpuFallback){x=$.canvas.hw/this.tileSize}else x=0;if(w)this._vertexMode=true}y??=group.y;if(y===undefined){if($.canvas?.renderer=="2d"&&!$._webgpuFallback){y=$.canvas.hh/this.tileSize}else y=0}let forcedBoxShape=false;if(w===undefined){w=group.w||group.width||group.d||group.diameter||group.v||group.vertices;if(!h&&!group.d&&!group.diameter){h=group.h||group.height;forcedBoxShape=true}}if(typeof x=="function")x=x(group.length);if(typeof y=="function")y=y(group.length);if(typeof w=="function")w=w(group.length);if(typeof h=="function")h=h(group.length);this.x=x;this.y=y;if(!group._isAllSpritesGroup){if(!ani){for(let _ani in group.animations){ani=_ani;break}if(!ani){ani=group._img;if(typeof ani=="function"){ani=ani(group.length)}if(ani)this._img=true}}}for(let g=group;g;g=$.p5play.groups[g.parent]){this.groups.push(g)}this.groups.reverse();if(ani){let ts=this.tileSize;if(this._img||ani instanceof p5.Image){if(typeof ani!="string")this.image=ani;else this.image=new $.EmojiImage(ani,w);if(!w&&(this._img.w!=1||this._img.h!=1)){w=(this._img.defaultWidth||this._img.w)/ts;h??=(this._img.defaultHeight||this._img.h)/ts}}else{if(typeof ani=="string")this._changeAni(ani);else this._ani=ani.clone();if(!w&&(this._ani.w!=1||this._ani.h!=1)){w=(this._ani.defaultWidth||this._ani.w)/ts;h??=(this._ani.defaultHeight||this._ani.h)/ts}}}this.groups=[];this.mouse=new $._SpriteMouse;this._rotation=0;this._rotationSpeed=0;this._bearing=0;this._scale=new Scale;Object.defineProperty(this._scale,"x",{get(){return this._x},set(val){if(val==this._x)return;if(_this.watch)_this.mod[26]=true;let scalarX=Math.abs(val/this._x);_this._w*=scalarX;_this._hw*=scalarX;_this._resizeColliders({x:scalarX,y:1});this._x=val;this._avg=(this._x+this._y)*.5}});Object.defineProperty(this._scale,"y",{get(){return this._y},set(val){if(val==this._y)return;if(_this.watch)_this.mod[26]=true;let scalarY=Math.abs(val/this._y);if(_this._h){this._h*=scalarY;this._hh*=scalarY}_this._resizeColliders({x:1,y:scalarY});this._y=val;this._avg=(this._x+this._y)*.5}});this._offset={_x:0,_y:0,get x(){return this._x},set x(val){if(val==this._x)return;if(_this.watch)_this.mod[21]=true;_this._offsetCenterBy(val-this._x,0)},get y(){return this._y},set y(val){if(val==this._y)return;if(_this.watch)_this.mod[21]=true;_this._offsetCenterBy(0,val-this._y)}};this._massUndef=true;if(w===undefined){this._dimensionsUndef=true;this._widthUndef=true;w=this.tileSize>1?1:50;if(h===undefined)this._heightUndef=true}if(forcedBoxShape)h??=this.tileSize>1?1:50;this._shape=group.shape;if(this.__collider!=3){if(this._vertexMode)this.addCollider(w);else this.addCollider(0,0,w,h);this.shape=this._shape}else{this.w=w;if(Array.isArray(w)){throw new Error('Cannot set the collider type of a sprite with a polygon or chain shape to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.')}if(w!==undefined&&h===undefined)this.shape="circle";else{this.shape="box";this.h=h}}this.prevPos={x:x,y:y};this.prevRotation=0;this._dest={x:x,y:y};this._destIdx=0;this._debug=false;this.text;if(!group._isAllSpritesGroup)$.allSprites.push(this);group.push(this);let gvx=group.vel.x||0;let gvy=group.vel.y||0;if(typeof gvx=="function")gvx=gvx(group.length-1);if(typeof gvy=="function")gvy=gvy(group.length-1);this.vel.x=gvx;this.vel.y=gvy;let skipProps=["ani","collider","x","y","w","h","d","diameter","dynamic","height","kinematic","static","vel","width"];for(let prop of $.Sprite.propsAll){if(skipProps.includes(prop))continue;let val=group[prop];if(val===undefined)continue;if(typeof val=="function"&&isArrowFunction(val)){val=val(group.length-1)}if(typeof val=="object"){if(val instanceof p5.Color){this[prop]=$.color(...val.levels)}else{this[prop]=Object.assign({},val)}}else{this[prop]=val}}skipProps=["add","animation","animations","autoCull","contains","GroupSprite","Group","idNum","length","mod","mouse","p","parent","Sprite","Subgroup","subgroups","velocity"];for(let i=0;i<this.groups.length;i++){let g=this.groups[i];let props=Object.keys(g);for(let prop of props){if(!isNaN(prop)||prop[0]=="_"||skipProps.includes(prop)||$.Sprite.propsAll.includes(prop)){continue}let val=g[prop];if(val===undefined)continue;if(typeof val=="function"&&isArrowFunction(val)){val=val(g.length-1)}if(typeof val=="object"){this[prop]=Object.assign({},val)}else{this[prop]=val}}}{let r=$.random(.12,.96);let g=$.random(.12,.96);let b=$.random(.12,.96);if($._colorFormat!=1){r*=255;g*=255;b*=255}this.color??=$.color(r,g,b)}this._textFill??=$.color(0);this._textSize??=this.tileSize==1?$.canvas?$.textSize():12:.8}addCollider(offsetX,offsetY,w,h){if(this._removed){console.error("Can't add colliders to a sprite that was removed.");return}if(this.__collider==3){this._collider="dynamic";this.__collider=0}let props={};props.shape=this._parseShape(...arguments);if(props.shape.m_type=="chain"){props.density=0;props.restitution=0}props.density??=this.density||5;props.friction??=this.friction||.5;props.restitution??=this.bounciness||.2;if(!this.body){this.body=$.world.createBody({position:scaleTo(this.x,this.y,this.tileSize),type:this.collider});this.body.sprite=this}else this.body.m_gravityScale||=1;let com=new pl.Vec2(this.body.getLocalCenter());this.body.createFixture(props);if(this.watch)this.mod[19]=true;this.body.setMassData({mass:this.body.getMass(),center:com,I:this.body.getInertia()})}addSensor(offsetX,offsetY,w,h){if(this._removed){console.error("Can't add sensors to a sprite that was removed.");return}let s=this._parseShape(...arguments);if(!this.body){this.body=$.world.createBody({position:scaleTo(this.x,this.y,this.tileSize),type:"dynamic",gravityScale:0});this.body.sprite=this;this.mass=0;this._massUndef=true;this.rotation=this._rotation;this.vel=this._velocity}this.body.createFixture({shape:s,isSensor:true});this._sortFixtures();this._hasSensors=true}_parseShape(offsetX,offsetY,w,h){let args=[...arguments];let path,shape;if(args.length==0){offsetX=0;offsetY=0;w=this._w;h=this._h}else if(args.length<=2){offsetX=0;offsetY=0;w=args[0];h=args[1];this._vertexMode=true}let dimensions;if(Array.isArray(w)||typeof h=="string"){if(!isNaN(w))w=Number(w);if(typeof w!="number"&&Array.isArray(w[0])){this._originMode??="start"}if(typeof h=="string"){path=getRegularPolygon(w,h);h=undefined}else{path=w}}else{if(w!==undefined&&h===undefined){shape="circle"}else{shape="box"}w??=this.tileSize>1?1:50;h??=w;dimensions=scaleTo(w-.08,h-.08,this.tileSize)}let s;if(shape=="box"){s=pl.Box(dimensions.x/2,dimensions.y/2,scaleTo(offsetX,offsetY,this.tileSize),0)}else if(shape=="circle"){s=pl.Circle(scaleTo(offsetX,offsetY,this.tileSize),dimensions.x/2)}else if(path){let vecs=[{x:0,y:0}];let vert={x:0,y:0};let min={x:0,y:0};let max={x:0,y:0};let usesVertices=Array.isArray(path[0]);function checkVert(){if(vert.x<min.x)min.x=vert.x;if(vert.y<min.y)min.y=vert.y;if(vert.x>max.x)max.x=vert.x;if(vert.y>max.y)max.y=vert.y}let x,y;if(usesVertices){if(this._vertexMode){x=path[0][0];y=path[0][1];if(!this.fixture||!this._relativeOrigin){this.x=x;this.y=y}else{x=this.x-this._relativeOrigin.x;y=this.y-this._relativeOrigin.y;vecs.pop()}}for(let i=0;i<path.length;i++){if(this._vertexMode){if(i==0&&!this.fixture)continue;vert.x=path[i][0]-x;vert.y=path[i][1]-y}else{vert.x+=path[i][0];vert.y+=path[i][1]}vecs.push({x:vert.x,y:vert.y});checkVert()}}else{let rep=1;if(path.length%2)rep=path[path.length-1];let mod=rep>0?1:-1;rep=Math.abs(rep);let ang=0;for(let i=0;i<rep;i++){for(let j=0;j<path.length-1;j+=2){let len=path[j];ang+=path[j+1];vert.x+=len*$.cos(ang);vert.y+=len*$.sin(ang);vecs.push({x:vert.x,y:vert.y});checkVert()}ang*=mod}}let isConvex=false;if(isSlop(Math.abs(vecs[0].x)-Math.abs(vecs[vecs.length-1].x))&&isSlop(Math.abs(vecs[0].y)-Math.abs(vecs[vecs.length-1].y))){if(this._shape!="chain")shape="polygon";else shape="chain";this._originMode="center";if(this._isConvexPoly(vecs.slice(0,-1)))isConvex=true}else{shape="chain"}w=max.x-min.x;h=max.y-min.y;if(this._originMode=="start"){for(let i=0;i<vecs.length;i++){vecs[i]=scaleTo(vecs[i].x,vecs[i].y,this.tileSize)}}else{let centerX=0;let centerY=0;let sumX=0;let sumY=0;let vl=vecs.length;if(shape=="polygon"||isConvex)vl--;for(let i=0;i<vl;i++){sumX+=vecs[i].x;sumY+=vecs[i].y}centerX=sumX/vl;centerY=sumY/vl;if(!this.fixture){this._relativeOrigin={x:centerX,y:centerY}}if(this._vertexMode&&usesVertices){if(!this.fixture){this.x+=centerX;this.y+=centerY}else{centerX=this._relativeOrigin.x;centerY=this._relativeOrigin.y}}for(let i=0;i<vecs.length;i++){let vec=vecs[i];vecs[i]=scaleTo(vec.x+offsetX-centerX,vec.y+offsetY-centerY,this.tileSize)}}if(!isConvex||vecs.length-1>pl.Settings.maxPolygonVertices||this._shape=="chain"){shape="chain"}if(shape=="polygon"){s=pl.Polygon(vecs)}else if(shape=="chain"){s=pl.Chain(vecs,false)}}this.shape??=shape;if(!this.fixtureList){this._w=w;this._hw=w*.5;if(this.__shape!=1){this._h=h;this._hh=h*.5}}else{this._extents??={t:this.hh,b:this.hh,l:this._hw,r:this._hw};let ex=this._extents;let l=offsetX-w*.5;let r=offsetX+w*.5;let t=offsetY-h*.5;let b=offsetY+h*.5;if(l<ex.l)ex.l=l;if(r>ex.r)ex.r=r;if(t<ex.t)ex.t=t;if(b>ex.b)ex.b=b;this._totalWidth=ex.r-ex.l;this._totalHeight=ex.b-ex.t;let abs=Math.abs;this._largestExtent=Math.max(abs(ex.l),abs(ex.r),abs(ex.t),abs(ex.b))}return s}removeColliders(){if(!this.body)return;this._removeContacts(0);this._removeFixtures(0)}removeSensors(){if(!this.body)return;this._removeContacts(1);this._removeFixtures(1);this._hasSensors=false}_removeFixtures(type){let prevFxt;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){if(type===undefined||fxt.m_isSensor==type){let _fxt=fxt.m_next;fxt.destroyProxies($.world.m_broadPhase);if(!prevFxt){this.body.m_fixtureList=_fxt}else{prevFxt.m_next=_fxt}}else{prevFxt=fxt}}}_removeContacts(type){if(!this.body)return;let ce=this.body.m_contactList;while(ce){let con=ce.contact;ce=ce.next;if(type===undefined||con.m_fixtureA.m_isSensor==type){$.world.destroyContact(con)}}}_offsetCenterBy(x,y){if(!x&&!y)return;this._offset._x+=x;this._offset._y+=y;if(!this.body)return;let off=scaleTo(x,y,this.tileSize);this.__offsetCenterBy(off.x,off.y)}__offsetCenterBy(x,y){for(let fxt=this.body.m_fixtureList;fxt;fxt=fxt.m_next){let shape=fxt.m_shape;if(shape.m_type!="circle"){let vertices=shape.m_vertices;for(let v of vertices){v.x+=x;v.y+=y}}else{shape.m_p.x+=x;shape.m_p.y+=y}}}_cloneBodyProps(){let body={};let props=["bounciness","density","drag","friction","heading","isSuperFast","rotation","rotationDrag","rotationLock","rotationSpeed","scale","vel","x","y"];if(!this._massUndef||!this._dimensionsUndef){props.push("mass")}for(let prop of props){if(typeof this[prop]=="object"){body[prop]=Object.assign({},this[prop])}else{body[prop]=this[prop]}}return body}get animation(){return this._ani}set animation(val){this.changeAni(val)}get ani(){return this._ani}set ani(val){this.changeAni(val)}get anis(){return this.animations}get autoUpdate(){return this._autoUpdate}set autoUpdate(val){this._autoUpdate=val}get autoDraw(){return this._autoDraw}set autoDraw(val){this._autoDraw=val}get allowSleeping(){return this.body?.isSleepingAllowed()}set allowSleeping(val){if(this.watch)this.mod[5]=true;if(this.body)this.body.setSleepingAllowed(val)}get bounciness(){if(!this.fixture)return;return this.fixture.getRestitution()}set bounciness(val){if(this.watch)this.mod[7]=true;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){fxt.setRestitution(val)}}get collider(){return this._collider}set collider(val){if(val==this._collider)return;val=val.toLowerCase();let c=val[0];if(c=="d")val="dynamic";if(c=="s")val="static";if(c=="k")val="kinematic";if(c=="n")val="none";if(val==this._collider)return;if(val=="none"&&(this._shape=="chain"||this._shape=="polygon")){console.error('Cannot set the collider type of a polygon or chain collider to "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');return}if(this._removed){throw new Error("Cannot change the collider type of a sprite that was removed.")}let oldCollider=this.__collider;this._collider=val;this.__collider=["d","s","k","n"].indexOf(c);if(this.watch)this.mod[8]=true;if(oldCollider===undefined)return;if(this.__collider!=3){if(this.body)this.body.setType(val);if(oldCollider==3){this.addCollider();this.x=this._position.x;this.y=this._position.y;this.vel.x=this._velocity.x;this.vel.y=this._velocity.y;this.rotation=this._rotation;this.rotationSpeed=this._rotationSpeed}}else{this.removeColliders();if(this.fixture?.m_isSensor)this.body.m_gravityScale=0;else{this._syncWithPhysicsBody();$.world.destroyBody(this.body);this.body=null}}}_syncWithPhysicsBody(){this._position.x=this.x;this._position.y=this.y;this._velocity.x=this.vel.x;this._velocity.y=this.vel.y;this._rotation=this.rotation;this._rotationSpeed=this.rotationSpeed}_parseColor(val){if(val instanceof p5.Color){return val}else if(typeof val!="object"){if(val.length==1)return $.colorPal(val);else return $.color(val)}return $.color(...val.levels)}get color(){return this._color}set color(val){if(this.watch)this.mod[9]=true;this._color=this._parseColor(val)}get colour(){return this._color}set colour(val){this.color=val}get fill(){return this._color}set fill(val){this.color=val}get stroke(){return this._stroke}set stroke(val){if(this.watch)this.mod[29]=true;this._stroke=this._parseColor(val)}get strokeWeight(){return this._strokeWeight}set strokeWeight(val){if(this.watch)this.mod[30]=true;this._strokeWeight=val}get textColor(){return this._textFill}set textColor(val){if(this.watch)this.mod[32]=true;this._textFill=this._parseColor(val)}get textColour(){return this._textFill}set textColour(val){this.textColor=val}get textFill(){return this._textFill}set textFill(val){this.textColor=val}get textSize(){return this._textSize}set textSize(val){if(this.watch)this.mod[33]=true;this._textSize=val}get textStroke(){return this._textStroke}set textStroke(val){if(this.watch)this.mod[34]=true;this._textStroke=this._parseColor(val)}get textStrokeWeight(){return this._textStrokeWeight}set textStrokeWeight(val){if(this.watch)this.mod[35]=true;this._textStrokeWeight=val}get tile(){return this._tile}set tile(val){if(this.watch)this.mod[36]=true;this._tile=val}get tileSize(){return this._tileSize}set tileSize(val){if(this.watch)this.mod[37]=true;this._tileSize=val}get bearing(){return this._bearing}set bearing(val){if(this.watch)this.mod[6]=true;this._bearing=val}get debug(){return this._debug}set debug(val){if(this.watch)this.mod[10]=true;this._debug=val}get density(){if(!this.fixture)return;return this.fixture.getDensity()}set density(val){if(this.watch)this.mod[11]=true;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){fxt.setDensity(val)}}_getDirectionAngle(name){name=name.toLowerCase().replaceAll(/[ _-]/g,"");let dirs={up:-90,down:90,left:180,right:0,upright:-45,rightup:-45,upleft:-135,leftup:-135,downright:45,rightdown:45,downleft:135,leftdown:135,forward:this.rotation,backward:this.rotation+180};let val=dirs[name];if($._angleMode=="radians"){val=$.radians(val)}return val}get direction(){if(this.vel.x!==0||this.vel.y!==0){return $.atan2(this.vel.y,this.vel.x)}if(this._isTurtleSprite)return this.rotation;return this._direction}set direction(val){if(this.watch)this.mod[12]=true;if(typeof val=="string"){this._heading=val;val=this._getDirectionAngle(val)}this._direction=val;if(this._isTurtleSprite)this.rotation=val;let speed=this.speed;this.vel.x=$.cos(val)*speed;this.vel.y=$.sin(val)*speed}get drag(){return this.body?.getLinearDamping()}set drag(val){if(this.watch)this.mod[13]=true;if(this.body)this.body.setLinearDamping(val)}get draw(){return this._display}set draw(val){this._userDefinedDraw=true;this._draw=val}get dynamic(){return this.body?.isDynamic()}set dynamic(val){if(val)this.collider="dynamic";else this.collider="kinematic"}get fixture(){return this.fixtureList}get fixtureList(){if(!this.body)return null;return this.body.m_fixtureList}get friction(){if(!this.fixture)return;return this.fixture.getFriction()}set friction(val){if(this.watch)this.mod[14]=true;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){fxt.setFriction(val)}}get heading(){return this._heading}set heading(val){this.direction=val}get img(){return this._img||this._ani?.frameImage}set img(val){this.image=val}get image(){return this._img||this._ani?.frameImage}set image(img){if(typeof img=="string"){if(!img.includes(".")){img=new $.EmojiImage(img,this.w)}else img=$.loadImage(img)}this._img=this._extendImage(img)}_extendImage(img){img.offset??={x:0,y:0};img._scale??={x:1,y:1};if(!img.scale){Object.defineProperty(img,"scale",{get:()=>img._scale,set:val=>{if(typeof val=="number")val={x:val,y:val};img._scale=val}})}return img}get isMoving(){return this.vel.x!=0||this.vel.y!=0}get isSuperFast(){return this.body?.isBullet()}set isSuperFast(val){if(this.watch)this.mod[16]=true;if(this.body)this.body.setBullet(val)}get kinematic(){return this.body?.isKinematic()}set kinematic(val){if(val)this.collider="kinematic";else this.collider="dynamic"}get layer(){return this._layer}set layer(val){if(this.watch)this.mod[17]=true;this._layer=val}get life(){return this._life}set life(val){if(this.watch)this.mod[18]=true;this._life=val}get mass(){return this.body?.getMass()}set mass(val){if(!this.body)return;if(this.watch)this.mod[19]=true;const com=new pl.Vec2(this.body.getLocalCenter());const t={I:0,center:com,mass:0};this.body.getMassData(t);t.mass=val>0?val:1e-8;this.body.setMassData(t);delete this._massUndef}resetMass(){if(!this.body)return;let com=new pl.Vec2(this.body.getLocalCenter());if(this.watch)this.mod[19]=true;this.body.resetMassData();this.body.setMassData({mass:this.body.getMass(),center:com,I:this.body.getInertia()})}resetCenterOfMass(){if(this.watch)this.mod[19]=true;this.body.resetMassData();let{x:x,y:y}=this.body.getLocalCenter();if(x==0&&y==0)return;this.__offsetCenterBy(-x,-y);this.body.resetMassData();let pos=this.body.getPosition();this.body.setPosition({x:pos.x+x,y:pos.y+y})}get mirror(){return this._mirror}set mirror(val){if(this.watch)this.mod[20]=true;if(val.x!==undefined)this._mirror.x=val.x;if(val.y!==undefined)this._mirror.y=val.y}get offset(){return this._offset}set offset(val){val.x??=this._offset._x;val.y??=this._offset._y;if(val.x==this._offset._x&&val.y==this._offset._y)return;if(this.watch)this.mod[21]=true;this._offsetCenterBy(val.x-this._offset._x,val.y-this._offset._y)}get opacity(){return this._opacity??1}set opacity(val){if(this.watch)this.mod[41]=true;this._opacity=val}get previousPosition(){return this.prevPos}set previousPosition(val){this.prevPos=val}get previousRotation(){return this.prevRotation}set previousRotation(val){this.prevRotation=val}get pixelPerfect(){return this._pixelPerfect}set pixelPerfect(val){if(this.watch)this.mod[22]=true;this._pixelPerfect=val}get removed(){return this._removed}set removed(val){if(!val||this._removed)return;if(this.watch)this.mod[23]=true;this._removed=true;this._remove()}get rotation(){if(!this.body||!usePhysics)return this._rotation||0;let val=this.body.getAngle();if($.p5play.friendlyRounding)val=fixRound(val,angularSlop);return $._angleMode==DEGREES?$.degrees(val):val}set rotation(val){this._rotation=val;if(this.body){if($._angleMode==DEGREES)val=$.radians(val%360);this.body.setAngle(val);this.body.synchronizeTransform()}}get rotationDrag(){return this.body?.getAngularDamping()}set rotationDrag(val){if(!this.body)return;if(this.watch)this.mod[24]=true;this.body.setAngularDamping(val)}get rotationLock(){return this.body?.isFixedRotation()}set rotationLock(val){if(!this.body)return;if(this.watch)this.mod[25]=true;let mass=this.mass;this.body.setFixedRotation(val);this.mass=mass}get rotationSpeed(){if(this.body){let val=this.body.getAngularVelocity()/60;return $._angleMode==DEGREES?$.degrees(val):val}return this._rotationSpeed}set rotationSpeed(val){if(this.body){val*=60;if($._angleMode==DEGREES)val=$.radians(val);this.body.setAngularVelocity(val)}else this._rotationSpeed=val}get scale(){return this._scale}set scale(val){if(val==0)val=.01;if(typeof val==="number"){val={x:val,y:val}}else{val.x??=this._scale._x;val.y??=this._scale._y}if(val.x==this._scale._x&&val.y==this._scale._y)return;if(this.watch)this.mod[26]=true;let scalars={x:Math.abs(val.x/this._scale._x),y:Math.abs(val.y/this._scale._y)};this._w*=scalars.x;this._hw*=scalars.x;if(this._h){this._h*=scalars.y;this._hh*=scalars.y}this._resizeColliders(scalars);this._scale._x=val.x;this._scale._y=val.y;this._scale._avg=val.x}get sleeping(){if(this.body)return!this.body.isAwake();return undefined}set sleeping(val){if(!this.body)return;if(this.watch)this.mod[28]=true;this.body.setAwake(!val)}get speed(){return $.createVector(this.vel.x,this.vel.y).mag()}set speed(val){let angle=this.direction;this.vel.x=$.cos(angle)*val;this.vel.y=$.sin(angle)*val}get static(){return this.body?.isStatic()}set static(val){if(val)this.collider="static";else this.collider="dynamic"}get tint(){return this._tint}set tint(val){if(this.watch)this.mod[38]=true;this._tint=this._parseColor(val)}get tintColor(){return this._tint}set tintColor(val){this.tint=val}set vertices(val){if(this.__collider==3){throw new Error('Cannot set vertices of a sprite with collider type of "none".')}if(this.watch)this.mod[27]=true;this._removeFixtures();this._originMode="start";this.addCollider(val);if(this._hasSensors){this.addDefaultSensors()}}get vertices(){return this._getVertices()}_getVertices(internalUse){let f=this.fixture;let s=f.getShape();let v=[...s.m_vertices];if(s.m_type=="polygon")v.unshift(v.at(-1));let x=this.x;let y=this.y;for(let i=0;i<v.length;i++){let arr=[v[i].x/this.tileSize*$.world.meterSize+x,v[i].y/this.tileSize*$.world.meterSize+y];if($.p5play.friendlyRounding){arr[0]=fixRound(arr[0]);arr[1]=fixRound(arr[1])}if(internalUse)v[i]=arr;else v[i]=$.createVector(arr[0],arr[1])}return v}get visible(){return this._visible}set visible(val){if(this.watch)this.mod[39]=true;this._visible=val}get x(){return this._pos.x}set x(val){this._pos.x=val}get y(){return this._pos.y}set y(val){this._pos.y=val}get pos(){return this._pos}set pos(val){if(this.body){let pos=new pl.Vec2(val.x*this.tileSize/$.world.meterSize,val.y*this.tileSize/$.world.meterSize);this.body.setPosition(pos)}this._position.x=val.x;this._position.y=val.y}get position(){return this._pos}set position(val){this.pos=val}get canvasPos(){return this._canvasPos}get w(){return this._w}set w(val){if(val<0)val=.01;if(val==this._w)return;if(this.watch)this.mod[40]=true;let scalarX=val/this._w;this._w=val;this._hw=val*.5;this._resizeColliders({x:scalarX,y:1});delete this._widthUndef;delete this._dimensionsUndef}get hw(){return this._hw}set hw(val){throw new FriendlyError("Sprite.hw")}get width(){return this._w}set width(val){this.w=val}get halfWidth(){return this.hw}set halfWidth(val){throw new FriendlyError("Sprite.hw")}get h(){return this._h||this._w}set h(val){if(val<0)val=.01;if(this.__shape==1){this.w=val;return}if(val==this._h)return;if(this.watch)this.mod[15]=true;let scalarY=val/this._h;this._h=val;this._hh=val*.5;this._resizeColliders({x:1,y:scalarY});delete this._heightUndef;delete this._dimensionsUndef}get hh(){return this._hh||this._hw}set hh(val){throw new FriendlyError("Sprite.hh")}get height(){return this.h}set height(val){this.h=val}get halfHeight(){return this.hh}set halfHeight(val){throw new FriendlyError("Sprite.hh")}get d(){return this._w}set d(val){if(val<0)val=.01;let shapeChange=this.__shape!=1;if(!shapeChange&&this._w==val)return;if(this.watch)this.mod[40]=true;if(!shapeChange){let scalar=val/this._w;this._resizeColliders({x:scalar,y:scalar})}this._w=val;this._hw=val*.5;if(shapeChange)this.shape="circle"}get diameter(){return this._w}set diameter(val){this.d=val}get r(){return this._hw}set r(val){this.d=val*2}get radius(){return this._hw}set radius(val){this.d=val*2}_resizeColliders(scalars){if(!this.body)return;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){if(fxt.m_isSensor)continue;let sh=fxt.m_shape;if(sh.m_type=="circle"){if(scalars.x!=1)sh.m_radius*=scalars.x;else sh.m_radius*=scalars.y}else{for(let vert of sh.m_vertices){vert.x*=scalars.x;vert.y*=scalars.y}}}if(this._widthUndef||this._heightUndef)this.resetMass();this.body.synchronizeFixtures()}_isConvexPoly(vecs){loopk:for(let k=0;k<2;k++){if(k==1)vecs=vecs.reverse();for(let i=0;i<vecs.length;++i){const i1=i;const i2=i<vecs.length-1?i1+1:0;const p=vecs[i1];const e=pl.Vec2.sub(vecs[i2],p);for(let j=0;j<vecs.length;++j){if(j==i1||j==i2){continue}const v=pl.Vec2.sub(vecs[j],p);const c=pl.Vec2.cross(e,v);if(c<0){if(k==0)continue loopk;else return false}}}break}return true}get shape(){return this._shape}set shape(val){if(val==this._shape)return;let __shape=$.Sprite.shapeTypes.indexOf(val);if(__shape==-1){throw new Error('Invalid shape type: "'+val+'"\nThe valid shape types are: "'+$.Sprite.shapeTypes.join('", "')+'"')}if(this.__collider==3&&__shape>=2){console.error('Cannot set the collider shape to chain or polygon if the sprite has a collider type of "none". To achieve the same effect, use .overlaps(allSprites) to have your sprite overlap with the allSprites group.');return}let prevShape=this.__shape;this.__shape=__shape;this._shape=val;if(this.watch)this.mod[27]=true;if(prevShape===undefined)return;if(this.__shape==0){this._h=this._w;this._hh=this._hw}else{this._h=undefined;this._hh=undefined}let v,w;if(prevShape!=1&&this.__shape!=1){v=this._getVertices(true)}else{w=this._w}this._removeFixtures();if(this.__collider!=3){if(v){this._originMode??="center";this.addCollider(v)}else if(prevShape==1){let side=this._w*Math.sin(Math.PI/12);this.addCollider(0,0,[side,-30,12])}else{this.addCollider()}}if(this._hasSensors){this.addDefaultSensors()}let ox=this._offset._x;let oy=this._offset._y;if(!ox&&!oy)return;this._offset._x=0;this._offset._y=0;this._offsetCenterBy(ox,oy)}get update(){return this._update}set update(val){this._customUpdate=val}get postDraw(){return this._postDraw}set postDraw(val){this._customPostDraw=val}get vel(){return this._vel}set vel(val){this.vel.x=val.x;this.vel.y=val.y}get velocity(){return this._vel}set velocity(val){this.vel=val}get gravityScale(){return this.body?.getGravityScale()}set gravityScale(val){if(!this.body)return;if(this.watch)this.mod[42]=true;this.body.setGravityScale(val)}_update(){if(this._customUpdate)this._customUpdate();if(this.autoUpdate)this.autoUpdate=null}_step(){this.life-=timeScale;if(this._life!=2147483647&&this._life<=0){this.remove()}if((!this.body||!usePhysics)&&!this._removed){this._position.x+=this.vel.x*timeScale;this._position.y+=this.vel.y*timeScale;this._rotation+=this._rotationSpeed*timeScale}if(this.watch){if(this.x!=this.prevX)this.mod[0]=this.mod[2]=true;if(this.y!=this.prevY)this.mod[1]=this.mod[2]=true;if(this.rotation!=this.prevRotation){this.mod[3]=this.mod[4]=true}}if(!this.body&&!this._removed)return;this.__step()}__step(){let a=this;let b;for(let event in eventTypes){for(let k in this[event]){if(k>=1e3){if(a._isGroup||a._uid>=k)continue;b=$.p5play.sprites[k]}else{if(a._isGroup&&a._uid>=k)continue;b=$.p5play.groups[k]}let v=a[event][k]+1;if(!b||v==0||v==-2){delete a[event][k];if(b)delete b[event][a._uid];continue}this[event][k]=v;b[event][a._uid]=v}}}___step(){let a=this;let b,contactType,shouldOverlap,cb;let checkCollisions=true;for(let event in eventTypes){for(let k in this[event]){if(k>=1e3){if(a._isGroup||a._uid>=k)continue;b=$.p5play.sprites[k]}else{if(a._isGroup&&a._uid>=k)continue;b=$.p5play.groups[k]}if(a._isGroup||b?._isGroup)continue;shouldOverlap=a._hasOverlap[b._uid]??b._hasOverlap[a._uid];if(checkCollisions&&shouldOverlap!==false||!checkCollisions&&shouldOverlap!==true){continue}let v=a[event][k];for(let i=0;i<3;i++){if(i==0&&v!=1&&v!=-3)continue;if(i==1&&v==-1)continue;if(i==2&&v>=1)continue;contactType=eventTypes[event][i];let la=$.p5play[contactType][a._uid];if(la){cb=la[b._uid];if(cb)cb.call(a,a,b,v);for(let g of b.groups){cb=la[g._uid];if(cb)cb.call(a,a,b,v)}}let lb=$.p5play[contactType][b._uid];if(lb){cb=lb[a._uid];if(cb)cb.call(b,b,a,v);for(let g of a.groups){cb=lb[g._uid];if(cb&&(!la||cb!=la[g._uid])){cb.call(b,b,a,v)}}}}}checkCollisions=false}if(this._removed){if(Object.keys(this._collisions).length==0&&Object.keys(this._overlappers).length==0){if(this._isSprite)delete $.p5play.sprites[this._uid];else if(!$.p5play.storeRemovedGroupRefs)delete $.p5play.groups[this._uid];for(let eventType in eventTypes){for(let contactType of eventTypes[eventType]){delete $.p5play[contactType][this._uid]}}}}}__draw(){if(!$.p5play.disableImages){if(this._ani){this._ani.draw(this._offset._x,this._offset._y,0,this._scale._x,this._scale._y)}else if(this._img){let img=this._img;let shouldScale=this._scale._x!=1||this._scale._y!=1||img.scale.x!=1||img.scale.y!=1;if(shouldScale){$.push();$.scale(this._scale._x*img.scale.x,this._scale._y*img.scale.y)}$.image(img,this._offset._x+img.offset.x,this._offset._y+img.offset.y);if(shouldScale)$.pop()}}if(!(this._ani||this._img)||this.debug||$.p5play.disableImages){if(this.debug){$.noFill();$.stroke(0,255,0);$.line(0,-2,0,2);$.line(-2,0,2,0)}if(this.__collider!=3){if(!this.debug&&this._strokeWeight!==0){if(this.__shape==2)$.stroke(this.stroke||this.color);else if(this._stroke)$.stroke(this._stroke)}else $.noStroke();for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){if(this.debug){if(!fxt.m_isSensor)$.stroke(0,255,0,127);else $.stroke(255,255,0,127)}else if(fxt.m_isSensor)continue;this._drawFixture(fxt)}}else{if(this._strokeWeight!==0)$.stroke(this._stroke||120);if(this.__shape==0){$.rect(this._offset._x,this._offset._y,this.w*this.tileSize,this.h*this.tileSize)}else if(this.__shape==1){$.circle(this._offset._x,this._offset._y,this.d*this.tileSize)}}}if(this.text!==undefined){$.textAlign($.CENTER,$.CENTER);$.fill(this._textFill);if(this._textStrokeWeight)$.strokeWeight(this._textStrokeWeight);if(this._textStroke)$.stroke(this._textStroke);else $.noStroke();$.textSize(this.textSize*this.tileSize);$.text(this.text,0,0)}}_postDraw(){if(this._ani?.update)this._ani.update();for(let prop in this.mouse){if(this.mouse[prop]==-1)this.mouse[prop]=0}if(this._customPostDraw)this._customPostDraw();this.autoDraw??=true;this.autoUpdate??=true}_display(){let x=this.x*this.tileSize+$.world.origin.x;let y=this.y*this.tileSize+$.world.origin.y;if(!this._userDefinedDraw){let largestSide;if(!this._totalWidth){largestSide=this._h!==undefined?Math.max(this._w,this._h):this._w}else{largestSide=Math.max(this._totalWidth,this._totalHeight)}if(this.ani&&!$.p5play.disableImages){largestSide=Math.max(largestSide,this.ani.w,this.ani.h)}if(this.shape!="chain"&&$.camera.isActive&&(x+largestSide<$.camera.bound.min.x||x-largestSide>$.camera.bound.max.x||y+largestSide<$.camera.bound.min.y||y-largestSide>$.camera.bound.max.y)){this._visible=null;return}}this._visible=true;$.p5play.spritesDrawn++;if(!this._pixelPerfect){x=fixRound(x);y=fixRound(y)}else{let w,h;if(this.ani&&this.ani.length&&!$.p5play.disableImages){w=this.ani[this.ani._frame].w;h=this.ani[this.ani._frame].h}else{w=this._w;h=this._h}if(w%2==0)x=Math.round(x);else x=Math.round(x-.5)+.5;if(h%2==0)y=Math.round(y);else y=Math.round(y-.5)+.5}for(let j of this.joints){if(!j.visible){j.visible??=true;continue}if(this._uid==j.spriteA._uid){if(!j.spriteB._visible||this.layer<=j.spriteB.layer){j._display()}}else if(!j.spriteA._visible||this.layer<j.spriteA.layer){j._display()}}if(this._opacity==0)return;$.push();$.imageMode("center");$.rectMode("center");$.ellipseMode("center");$.translate(x,y);if(this.rotation)$.rotate(this.rotation);if(this._mirror._x!=1||this._mirror._y!=1){$.scale(this._mirror._x,this._mirror._y)}$.fill(this.color);if(this._strokeWeight!==undefined){$.strokeWeight(this._strokeWeight)}let ogGlobalAlpha;if(this._opacity){ogGlobalAlpha=$.ctx.globalAlpha;$.ctx.globalAlpha=this._opacity}if(this._tint)$.tint(this._tint);this._draw();$.pop();if(this._opacity)$.ctx.globalAlpha=ogGlobalAlpha;this._cameraActiveWhenDrawn=$.camera.isActive;if(!$.camera.isActive)$.camera._wasOff=true;if(this.autoDraw)this.autoDraw=null}_drawFixture(fxt){const sh=fxt.m_shape;if(sh.m_type=="polygon"||sh.m_type=="chain"){if(sh.m_type=="chain"){if($._strokeWeight==0)return;$.push();$.noFill()}let v=sh.m_vertices;$.beginShape();for(let i=0;i<v.length;i++){$.vertex(v[i].x*$.world.meterSize,v[i].y*$.world.meterSize)}if(sh.m_type!="chain")$.endShape("close");else{$.endShape();$.pop()}}else if(sh.m_type=="circle"){const d=sh.m_radius*2*$.world.meterSize;$.ellipse(sh.m_p.x*$.world.meterSize,sh.m_p.y*$.world.meterSize,d,d)}else if(sh.m_type=="edge"){$.line(sh.m_vertex1.x*$.world.meterSize,sh.m_vertex1.y*$.world.meterSize,sh.m_vertex2.x*$.world.meterSize,sh.m_vertex2.y*$.world.meterSize)}}_args2Vec(x,y){if(Array.isArray(x)){return{x:x[0],y:x[1]}}else if(typeof x=="object"){y=x.y;x=x.x}return{x:x||0,y:y||0}}_parseForceArgs(){let args=arguments;if(typeof args[0]=="number"&&(args.length==1||typeof args[1]!="number")){args[3]=args[2];args[2]=args[1];args[1]=$.sin(this._bearing)*args[0];args[0]=$.cos(this._bearing)*args[0]}else if(args.length==2&&typeof args[1]!="number"){args[2]=args[1];args[1]=undefined}let o={};o.forceVector=new pl.Vec2(this._args2Vec(args[0],args[1]));if(args[2]!==undefined){o.poa=this._args2Vec(args[2],args[3]);o.poa=scaleTo(o.poa.x,o.poa.y,this.tileSize)}return o}applyForce(amount,origin){if(!this.body)return;if(location.host=="game.thegamebox.ca"){return this.applyForceScaled(...arguments)}let{forceVector:forceVector,poa:poa}=this._parseForceArgs(...arguments);if(!poa)this.body.applyForceToCenter(forceVector);else this.body.applyForce(forceVector,poa)}applyForceScaled(amount,origin){if(!this.body)return;let{forceVector:forceVector,poa:poa}=this._parseForceArgs(...arguments);forceVector.mul(this.mass);if(!poa)this.body.applyForceToCenter(forceVector);else this.body.applyForce(forceVector,poa)}attractTo(x,y,force,radius,easing){if(!this.body||this.__collider!=0){console.error("attractTo can only be used on sprites with dynamic colliders");return}if(typeof x!="number"){let obj=x;if(!obj||obj==$.mouse&&!$.mouse.isActive)return;force=y;y=obj.y;x=obj.x}if(this.x==x&&this.y==y)return;let a=y-this.y;let b=x-this.x;let c=Math.sqrt(a*a+b*b);let percent=force/c;let forceVector=new pl.Vec2(b*percent,a*percent);this.body.applyForceToCenter(forceVector)}repelFrom(x,y,force,radius,easing){if(!this.body||this.__collider!=0){console.error("repelFrom can only be used on sprites with dynamic colliders");return}if(typeof x!="number"){let obj=x;if(!obj||obj==$.mouse&&!$.mouse.isActive)return;force=y;y=obj.y;x=obj.x}this.attractTo(x,y,-force,radius,easing)}applyTorque(val){if(!this.body)return;this.body.applyTorque(val)}moveTowards(x,y,tracking){if(x===undefined)return;if(typeof x!="number"&&x!==null){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return;if(!obj||obj.x===undefined||obj.y===undefined){throw"sprite.moveTowards/moveAway ERROR: movement destination not defined."}tracking=y;y=obj.y;x=obj.x}tracking??=.1;if(x!==undefined&&x!==null){let diffX=x-this.x;if(!isSlop(diffX)){this.vel.x=diffX*tracking*this.tileSize}else this.vel.x=0}if(y!==undefined&&y!==null){let diffY=y-this.y;if(!isSlop(diffY)){this.vel.y=diffY*tracking*this.tileSize}else this.vel.y=0}}moveAway(x,y,repel){this.moveTowards(...arguments);this.vel.x*=-1;this.vel.y*=-1}move(distance,direction,speed){if(!distance)return Promise.resolve(false);let directionNamed=isNaN(arguments[0]);if(directionNamed){distance=1;direction=arguments[0];speed=arguments[1]}if(typeof direction=="string"){directionNamed=true;this._heading=direction;direction=this._getDirectionAngle(direction)}direction??=this.direction;let x=$.cos(direction)*distance;let y=$.sin(direction)*distance;if((this.tileSize!=1||$.p5play.snapToGrid)&&(directionNamed||direction%90==0)&&distance%$.p5play.gridSize==0){x=Math.round((this.x+Math.round(x))/$.p5play.gridSize)*$.p5play.gridSize;y=Math.round((this.y+Math.round(y))/$.p5play.gridSize)*$.p5play.gridSize}else{x+=this.x;y+=this.y;if(direction%45==0){x=fixRound(x);y=fixRound(y)}}return this.moveTo(x,y,speed)}moveTo(x,y,speed){if(typeof x!="number"&&x){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return;if(!obj||obj.x===undefined||obj.y===undefined){throw"sprite.moveTo ERROR: destination not defined."}speed=y;y=obj.y;x=obj.x}if(x!=null&&x!=this.x){this._dest.x=x;x=true}else{this._dest.x=this.x;x=false}if(y!=null&&y!=this.y){this._dest.y=y;y=true}else{this._dest.y=this.y;y=false}this._destIdx++;if(!x&&!y)return Promise.resolve(true);speed??=this.speed||(this.tileSize<=1?1:.1);if(speed<=0){console.warn("sprite.move: speed should be a positive number");return Promise.resolve(false)}let a=this._dest.y-this.y;let b=this._dest.x-this.x;let c=Math.sqrt(a*a+b*b);let percent=speed/c;this.vel.x=b*percent;this.vel.y=a*percent;let destD=this.direction<0?this.direction+360:this.direction;let destDMin=destD-.1;let destDMax=destD+.1;let velThresh=$.world.velocityThreshold;velThresh=Math.min(velThresh,speed*.1);let margin=speed*.51*($.world.meterSize/60);let checkDir=x&&y;let destIdx=this._destIdx;return(async()=>{let distX,distY;do{await $.sleep();if(destIdx!=this._destIdx)return false;let dir=this.direction<0?this.direction+360:this.direction;if(checkDir&&(dir<=destDMin||dir>=destDMax)||Math.abs(this.vel.x)<=velThresh&&Math.abs(this.vel.y)<=velThresh){return false}if(x){if(this.vel.x>0)distX=this._dest.x-this.x;else distX=this.x-this._dest.x}if(y){if(this.vel.y>0)distY=this._dest.y-this.y;else distY=this.y-this._dest.y}}while(x&&distX>margin||y&&distY>margin);this.x=this._dest.x;this.y=this._dest.y;this.vel.x=0;this.vel.y=0;return true})()}rotateTowards(angle,tracking){if(this.__collider==1){new FriendlyError(0);return}let args=arguments;let x,y,facing;if(typeof args[0]!="number"){x=args[0].x;y=args[0].y;tracking=args[1];facing=args[2]}else if(arguments.length>2){x=args[0];y=args[1];tracking=args[2];facing=args[3]}if(x!==undefined)angle=this.angleToFace(x,y,facing);else{angle-=this.rotation}tracking??=.1;this.rotationSpeed=angle*tracking}angleTo(x,y){if(typeof x=="object"){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return 0;if(obj.x===undefined||obj.y===undefined){console.error("sprite.angleTo ERROR: rotation destination not defined, object given with no x or y properties");return 0}y=obj.y;x=obj.x}return $.atan2(y-this.y,x-this.x)}rotationToFace(x,y,facing){if(typeof x=="object"){facing=y;y=x.y;x=x.x}if(Math.abs(x-this.x)<.01&&Math.abs(y-this.y)<.01){return 0}return this.angleTo(x,y)+(facing||0)}angleToFace(x,y,facing){let ang=this.rotationToFace(x,y,facing);return minAngleDist(ang,this.rotation)}rotateTo(angle,speed,facing){if(this.__collider==1){new FriendlyError(0);return}let args=arguments;if(typeof args[0]!="number"){angle=this.rotationToFace(args[0].x,args[0].y,facing)}else{if(args.length>2){facing=args[3];speed=args[2];angle=this.rotationToFace(args[0],args[1],facing)}}if(angle==this.rotation)return;let full=$._angleMode==DEGREES?360:$.TWO_PI;angle=(angle-this.rotation)%full;if(angle<0&&speed>0)angle+=full;if(angle>0&&speed<0)angle-=full;speed??=this.rotationSpeed||Math.sign(angle);return this.rotate(angle,speed)}rotateMinTo(angle,speed,facing){if(this.__collider==1){new FriendlyError(0);return}let args=arguments;if(typeof args[0]!="number"){angle=this.rotationToFace(args[0].x,args[0].y,facing)}else{if(args.length>2){facing=args[3];speed=args[2];angle=this.rotationToFace(args[0],args[1],facing)}}if(angle==this.rotation)return;angle=minAngleDist(angle,this.rotation);speed??=this.rotationSpeed>.1?this.rotationSpeed:1;speed=Math.abs(speed)*Math.sign(angle);return this.rotate(angle,speed)}rotate(angle,speed){if(this.__collider==1){new FriendlyError(0);return}if(isNaN(angle)){new FriendlyError(1,[angle]);return}if(angle==0)return;speed??=this.rotationSpeed||1;let cw=angle>0&&speed>0;if(!cw){angle=-Math.abs(angle);speed=-Math.abs(speed)}this.rotationSpeed=speed;let absSpeed=Math.abs(speed);let ang=this.rotation+angle;this._rotateIdx??=0;this._rotateIdx++;let _rotateIdx=this._rotateIdx;return(async()=>{let slop=.01;do{let remaining=Math.abs(ang-this.rotation);if(absSpeed>remaining){this.rotationSpeed=remaining*Math.sign(speed)}await $.sleep();if(this._rotateIdx!=_rotateIdx)return false;if(cw&&this.rotationSpeed<slop||!cw&&this.rotationSpeed>-slop){return false}}while((cw&&ang>this.rotation||!cw&&ang<this.rotation)&&slop<Math.abs(ang-this.rotation));this.rotationSpeed=0;this.rotation=ang;return true})()}addAni(){if($.p5play.disableImages){this._ani=new $.Ani;return}let args=[...arguments];let name,ani;if(args[0]instanceof $.Ani){ani=args[0];if(ani._addedToSpriteOrGroup)ani=ani.clone();name=ani.name||"default";ani.name=name}else if(args[1]instanceof $.Ani){name=args[0];ani=args[1];if(ani._addedToSpriteOrGroup)ani=ani.clone();ani.name=name}else{ani=new $.Ani(this,...args);name=ani.name}this.animations[name]=ani;this._ani=ani;ani._addedToSpriteOrGroup=true;if(this._dimensionsUndef&&(ani.w!=1||ani.h!=1)){this.w=ani.w;this.h=ani.h}return ani}addAnis(){let args=arguments;let atlases;if(args.length==1){atlases=args[0]}else{this.spriteSheet=args[0];atlases=args[1]}for(let name in atlases){let atlas=atlases[name];this.addAni(name,atlas)}}async changeAni(anis){if($.p5play.disableImages)return;if(arguments.length>1)anis=[...arguments];else if(anis instanceof $.Ani){if(anis==this._ani)return;anis=[anis]}else if(!Array.isArray(anis)){if(anis==this._ani?.name)return;anis=[anis]}this._aniChangeCount++;let loop,stopOnLastAni;for(let i=0;i<anis.length;i++){let ani=anis[i];if(ani instanceof $.Ani||ani instanceof p5.Image||typeof ani=="string"&&ani.length!=1&&ani.includes(".")){ani=this.addAni(ani);anis[i]=ani}if(typeof ani=="string"){ani={name:ani};anis[i]=ani}if(ani.name.length>1){if(ani.name[0]=="!"){ani.name=ani.name.slice(1);ani.start=-1;ani.end=0}if(ani.name[0]=="<"||ani.name[0]==">"){ani.name=ani.name.slice(1);ani.flipX=true}if(ani.name[0]=="^"){ani.name=ani.name.slice(1);ani.flipY=true}if(ani.name=="**"){loop=true;anis=anis.slice(0,-1)}if(ani.name==";;"){stopOnLastAni=true;anis=anis.slice(0,-1)}}}let count=this._aniChangeCount;do{for(let i=0;i<anis.length;i++){let ani=anis[i];if(!ani.start&&anis.length>1)ani.start=0;await this._playSequencedAni(ani)}}while(loop&&count==this._aniChangeCount);if(anis.length!=1&&stopOnLastAni)this._ani.stop()}_playSequencedAni(ani){return new Promise((resolve=>{let{name:name,start:start,end:end,flipX:flipX,flipY:flipY}=ani;this._changeAni(name);if(flipX)this._ani.scale.x=-this._ani.scale.x;if(flipY)this._ani.scale.y=-this._ani.scale.y;if(start<0)start=this._ani.length+start;if(start!==undefined)this._ani._frame=start;if(end!==undefined)this._ani.goToFrame(end);else if(this._ani._frame==this._ani.lastFrame)resolve();this._ani._onComplete=this._ani._onChange=()=>{if(flipX)this._ani.scale.x=-this._ani.scale.x;if(flipY)this._ani.scale.y=-this._ani.scale.y;this._ani._onComplete=this._ani._onChange=null;resolve()}}))}changeAnimation(){return this.changeAni(...arguments)}_changeAni(label){if(this._ani?._onChange)this._ani._onChange();if(this._ani?.onChange)this._ani.onChange();let ani=this.animations[label];if(!ani){for(let i=this.groups.length-1;i>=0;i--){let g=this.groups[i];ani=g.animations[label];if(ani){ani=ani.clone();break}}}if(!ani){$.noLoop();throw new FriendlyError("Sprite.changeAnimation",[label])}this._ani=ani;this._ani.name=label;if(this.resetAnimationsOnChange)this._ani._frame=0}remove(){this.removed=true}_remove(){if(this.body)$.world.destroyBody(this.body);this.body=null;for(let g of this.groups){g.remove(this)}}toString(){return"s"+this.idNum}_setContactCB(target,cb,contactType,eventType){let type;if(contactType==0)type=eventTypes._collisions[eventType];else type=eventTypes._overlappers[eventType];let ledger=$.p5play[type];let l=ledger[this._uid]??={};if(l[target._uid]==cb)return;l[target._uid]=cb;l=ledger[target._uid];if(!l||!l[this._uid])return;delete l[this._uid];if(Object.keys(l).length==0){delete ledger[target._uid]}}_validateCollideParams(target,cb){if(!target){throw new FriendlyError("Sprite.collide",2)}if(!target._isSprite&&!target._isGroup){throw new FriendlyError("Sprite.collide",0,[target])}if(cb&&typeof cb!="function"){throw new FriendlyError("Sprite.collide",1,[cb])}}_ensureCollide(target,cb,type){if(this._hasOverlap[target._uid]!==false){this._hasOverlap[target._uid]=false}if(target._hasOverlap[this._uid]!==false){target._hasOverlap[this._uid]=false;if(target._isGroup){for(let s of target){s._hasOverlap[this._uid]=false;this._hasOverlap[s._uid]=false}}}}collide(target,callback){return this.collides(target,callback)}collides(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,0);return this._collisions[target._uid]==1||this._collisions[target._uid]<=-3}colliding(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,1);let val=this._collisions[target._uid];if(val<=-3)return 1;return val>0?val:0}collided(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,2);return this._collisions[target._uid]<=-1}_validateOverlapParams(target,cb){if(!target){throw new FriendlyError("Sprite.overlap",2)}if(!target._isSprite&&!target._isGroup){throw new FriendlyError("Sprite.overlap",0,[target])}if(cb&&typeof cb!="function"){throw new FriendlyError("Sprite.overlap",1,[cb])}}_ensureOverlap(target){if(!this._hasSensors)this.addDefaultSensors();if(!target._hasSensors){if(target._isSprite){target.addDefaultSensors()}else{for(let s of target){if(!s._hasSensors)s.addDefaultSensors()}target._hasSensors=true}}if(!this._hasOverlap[target._uid]){this._removeContactsWith(target);this._hasOverlap[target._uid]=true}if(!target._hasOverlap[this._uid]){target._removeContactsWith(this);target._hasOverlap[this._uid]=true;if(target._isGroup){for(let s of target){s._hasOverlap[this._uid]=true;this._hasOverlap[s._uid]=true}}}}overlap(target,callback){return this.overlaps(target,callback)}overlaps(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,0);return this._overlappers[target._uid]==1||this._overlappers[target._uid]<=-3}overlapping(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,1);let val=this._overlappers[target._uid];if(val<=-3)return 1;return val>0?val:0}overlapped(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,2);return this._overlappers[target._uid]<=-1}_removeContactsWith(target){if(target._isGroup){for(let s of target){this._removeContactsWith(s)}}else{this.__removeContactsWith(target)}}__removeContactsWith(o){if(!this.body)return;for(let ce=this.body.getContactList();ce;ce=ce.next){let c=ce.contact;if(c.m_fixtureA.m_body.sprite._uid==o._uid||c.m_fixtureB.m_body.sprite._uid==o._uid){$.world.destroyContact(c)}}}_sortFixtures(){let colliders=null;let sensors=null;let lastColl,lastSens;for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){if(fxt.m_isSensor){if(!sensors)sensors=fxt;else sensors.m_next=fxt;lastSens=fxt}else{if(!colliders)colliders=fxt;else colliders.m_next=fxt;lastColl=fxt}}if(sensors)lastSens.m_next=null;if(colliders)lastColl.m_next=sensors;this.body.m_fixtureList=colliders||sensors}addDefaultSensors(){let shape;if(this.body&&this.fixtureList){for(let fxt=this.fixtureList;fxt;fxt=fxt.getNext()){if(fxt.m_isSensor)continue;shape=fxt.m_shape;this.body.createFixture({shape:shape,isSensor:true})}this._sortFixtures()}else{this.addSensor()}this._hasSensors=true}distanceTo(o){return $.dist(this.x,this.y,o.x,o.y)}};$.Sprite.propTypes={x:"Float64",y:"Float64",vel:"Vec2",rotation:"number",rotationSpeed:"number",allowSleeping:"boolean",bearing:"number",bounciness:"number",collider:"Uint8",color:"color",debug:"boolean",density:"number",direction:"number",drag:"number",friction:"number",h:"number",isSuperFast:"boolean",layer:"number",life:"Int32",mass:"number",mirror:"Vec2_boolean",offset:"Vec2",pixelPerfect:"boolean",removed:"boolean",rotationDrag:"number",rotationLock:"boolean",scale:"Vec2",shape:"Uint8",sleeping:"boolean",stroke:"color",strokeWeight:"number",text:"string",textColor:"color",textSize:"number",textStroke:"color",textStrokeWeight:"number",tile:"string",tileSize:"number",tint:"color",visible:"boolean",w:"number",opacity:"number",gravityScale:"number"};$.Sprite.props=Object.keys($.Sprite.propTypes);$.Sprite.propsAll=$.Sprite.props.concat(["autoDraw","autoUpdate","colour","d","diameter","dynamic","fill","height","heading","kinematic","resetAnimationsOnChange","speed","spriteSheet","static","textColour","textFill","width"]);$.Sprite.colliderTypes=["d","s","k","n"];$.Sprite.shapeTypes=["box","circle","chain","polygon"];$.Turtle=function(size){if($.allSprites.tileSize>1){throw new Error(`Turtle can't be used when allSprites.tileSize is greater than 1.`)}size??=25;let t=new $.Sprite(size,size,[[size,size*.4],[-size,size*.4],[0,-size*.8]]);t.color="green";t._isTurtleSprite=true;t._prevPos={x:t.x,y:t.y};let _move=t.move;t.move=function(){this._prevPos.x=this.x;this._prevPos.y=this.y;return _move.call(this,...arguments)};return t};this.Ani=class extends Array{constructor(){super();let args=[...arguments];this.name="default";let owner;if(typeof args[0]=="object"&&(args[0]._isSprite||args[0]._isGroup)){owner=args[0];args=args.slice(1);this._addedToSpriteOrGroup=true}owner??=$.allSprites;if(typeof args[0]=="string"&&(args[0].length==1||!args[0].includes("."))){this.name=args[0];args=args.slice(1)}this._frame=0;this._cycles=0;this.targetFrame=-1;this.offset={x:owner.anis.offset.x??0,y:owner.anis.offset.y??0};this._frameDelay=owner.anis.frameDelay||4;this.demoMode=owner.anis.demoMode??false;this.playing=true;this.visible=true;this.looping=owner.anis.looping??true;this.endOnFirstFrame=owner.anis.endOnFirstFrame??false;this.frameChanged=false;this.onComplete=this.onChange=null;this._onComplete=this._onChange=null;this.rotation=owner.anis.rotation??0;this._scale=new Scale;if(args.length==0||typeof args[0]=="number")return;owner.animations[this.name]=this;owner._ani=this;if(Array.isArray(args[0])&&typeof args[0][0]=="string"){args=[...args[0]]}if(args.length==2&&typeof args[0]=="string"&&(typeof args[1]=="string"||typeof args[1]=="number")){let from=args[0];let to,num2;if(!isNaN(args[1]))num2=Number(args[1]);else to=args[1];let extIndex=from.lastIndexOf(".");let digits1=0;let digits2=0;for(let i=extIndex-1;i>=0;i--){if(!isNaN(from.charAt(i)))digits1++;else break}if(to){for(let i=to.length-5;i>=0;i--){if(!isNaN(to.charAt(i)))digits2++;else break}}let ext=from.slice(extIndex);let prefix1=from.slice(0,extIndex-digits1);let prefix2;if(to)prefix2=to.slice(0,extIndex-digits2);if(to&&prefix1!=prefix2){this.push($.loadImage(from));this.push($.loadImage(to))}else{let num1=parseInt(from.slice(extIndex-digits1,extIndex),10);num2??=parseInt(to.slice(extIndex-digits2,extIndex),10);if(num2<num1){let t=num2;num2=num1;num1=t}let fileName;if(!to||digits1==digits2){for(let i=num1;i<=num2;i++){fileName=prefix1+$.nf(i,digits1)+ext;this.push($.loadImage(fileName))}}else{for(let i=num1;i<=num2;i++){fileName=prefix1+i+ext;this.push($.loadImage(fileName))}}}}else if(typeof args.at(-1)!="string"&&!(args.at(-1)instanceof p5.Image)){let sheet=owner.spriteSheet;let atlas;if(args[0]instanceof p5.Image||typeof args[0]=="string"){if(args.length>=3){throw new FriendlyError("Ani",1)}sheet=args[0];atlas=args[1]}else{atlas=args[0]}let _this=this;if(sheet instanceof p5.Image&&sheet.width!=1&&sheet.height!=1){this.spriteSheet=sheet;_generateSheetFrames()}else{let url;if(typeof sheet=="string")url=sheet;else url=sheet.url;$._incrementPreload();this.spriteSheet=$.loadImage(url,(()=>{_generateSheetFrames();$._decrementPreload()}));if(typeof sheet=="string"){owner.spriteSheet=this.spriteSheet}}function _generateSheetFrames(){if(Array.isArray(atlas)){if(typeof atlas[0]=="object"){atlas={frames:atlas}}else if(atlas.length==4){atlas={pos:atlas.slice(0,2),size:atlas.slice(2)}}else{atlas={pos:atlas}}}let{w:w,h:h,width:width,height:height,size:size,row:row,col:col,line:line,x:x,y:y,pos:pos,frames:frames,frameCount:frameCount,frameDelay:frameDelay,frameSize:frameSize,delay:delay,rotation:rotation}=atlas;frameSize??=size||owner.anis.frameSize;if(delay)_this.frameDelay=delay;if(frameDelay)_this.frameDelay=frameDelay;if(rotation)_this.rotation=rotation;if(frames&&Array.isArray(frames)){frameCount=frames.length}else frameCount??=frames||1;w??=width||owner.anis.w;h??=height||owner.anis.h;x??=col||0;y??=line||row||0;if(pos){x=pos[0];y=pos[1]}if(typeof frameSize=="number"){w=h=frameSize}else if(frameSize){w=frameSize[0];h=frameSize[1]}let tileSize=owner.tileSize;if(!w||!h){if(!owner._dimensionsUndef&&owner.w&&owner.h){w??=owner.w*tileSize;h??=owner.h*tileSize}else if(tileSize!=1){w??=tileSize;h??=tileSize}else if(frameCount){w??=_this.spriteSheet.width/frameCount;h??=_this.spriteSheet.height}else{if(_this.spriteSheet.width<_this.spriteSheet.height){w=h=_this.spriteSheet.width}else{w=h=_this.spriteSheet.height}}}else{w*=tileSize;h*=tileSize}if(!Array.isArray(frames)){if(tileSize!=1||pos||line!==undefined||row!==undefined||col!==undefined){x*=w;y*=h}for(let i=0;i<frameCount;i++){let f={x:x,y:y,w:w,h:h};f.defaultWidth=w*$._defaultImageScale;f.defaultHeight=h*$._defaultImageScale;_this.push(f);x+=w;if(x>=_this.spriteSheet.width){x=0;y+=h;if(y>=_this.spriteSheet.height)y=0}}}else{let sw=Math.round(_this.spriteSheet.width/w);for(let frame of frames){let f;if(typeof frame=="number"){y=Math.floor(frame/sw)*h;x=frame%sw*w;f={x:x,y:y,w:w,h:h}}else{if(frame.length==2){x=frame[0]*w;y=frame[1]*h;f={x:x,y:y,w:w,h:h}}else{f={x:frame[0],y:frame[1],w:frame[2],h:frame[3]}}}f.defaultWidth=f.w*$._defaultImageScale;f.defaultHeight=f.h*$._defaultImageScale;_this.push(f)}}}}else{for(let i=0;i<args.length;i++){if(args[i]instanceof p5.Image)this.push(args[i]);else this.push($.loadImage(args[i]))}}if(this.length==1)this.playing=false}get frame(){return this._frame}set frame(val){if(val<0||val>=this.length){throw new FriendlyError("Ani.frame",[val,this.length])}this._frame=val;this._cycles=0}get frameDelay(){return this._frameDelay}set frameDelay(val){if(val<=0)val=1;this._frameDelay=val}get scale(){return this._scale}set scale(val){if(typeof val=="number"){val={x:val,y:val}}this._scale._x=val.x;this._scale._y=val.y;this._scale._avg=val.x}clone(){if(!this.length){console.error(`The animation named "${this.name}" must be loaded before it can be properly copied. Sprites need their own copy of a group's animation. Try loading the animation in the preload function and creating new group sprites in the setup function.`)}let ani=new $.Ani;ani.spriteSheet=this.spriteSheet;for(let i=0;i<this.length;i++){ani.push(this[i])}ani.name=this.name;ani.offset.x=this.offset.x;ani.offset.y=this.offset.y;ani.frameDelay=this.frameDelay;ani.playing=this.playing;ani.looping=this.looping;ani.rotation=this.rotation;return ani}draw(x,y,r,sx,sy){this.x=x||0;this.y=y||0;r??=this.rotation;if(!this.visible)return;sx??=1;sy??=1;$.push();$.imageMode("center");$.translate(this.x,this.y);$.rotate(r);$.scale(sx*this._scale._x,sy*this._scale._y);let ox=this.offset.x;let oy=this.offset.y;let img=this[this._frame];if(img!==undefined){if(this.spriteSheet){let{x:x,y:y,w:w,h:h}=img;if(!this.demoMode){$.image(this.spriteSheet,ox,oy,img.defaultWidth||w,img.defaultHeight||h,x,y,w,h)}else{$.image(this.spriteSheet,ox,oy,this.spriteSheet.w,this.spriteSheet.h,x-this.spriteSheet.w/2+w/2,y-this.spriteSheet.h/2+h/2)}}else{$.image(img,ox,oy)}}else{console.warn('p5play: "'+this.name+'"'+" animation not loaded yet or frame "+this._frame+" does not exist. Load this animation in the preload function if you need to use it at the start of your program.")}$.pop()}update(){if(!this.playing)return;this._cycles++;if(this._cycles%this.frameDelay==0){this._cycles=0;this.frameChanged=true;if(this.targetFrame==-1&&this._frame==this.lastFrame||this._frame==this.targetFrame){if(this.endOnFirstFrame)this._frame=0;if(this.looping)this.targetFrame=-1;else this.playing=false;if(this._onComplete)this._onComplete();if(this.onComplete)this.onComplete();if(!this.looping)return}if(this.targetFrame>this._frame&&this.targetFrame!==-1){this._frame++}else if(this.targetFrame<this._frame&&this.targetFrame!==-1){this._frame--}else if(this.targetFrame===this._frame&&this.targetFrame!==-1){this.playing=false}else if(this.looping){if(this._frame>=this.lastFrame){this._frame=0}else this._frame++}else{if(this._frame<this.lastFrame)this._frame++}}else{this.frameChanged=false}}play(frame){this.playing=true;if(frame!==undefined&&this._frame!=frame){this._frame=frame;this._cycles=0}this.targetFrame=-1;return new Promise((resolve=>{this._onComplete=()=>{this._onComplete=null;resolve()}}))}pause(frame){this.playing=false;if(frame)this._frame=frame}stop(frame){this.playing=false;if(frame)this._frame=frame}rewind(){this.looping=false;return this.goToFrame(0)}loop(){this.looping=true;this.playing=true}noLoop(){this.looping=false}nextFrame(){if(this._frame<this.length-1)this._frame=this._frame+1;else if(this.looping)this._frame=0;this.targetFrame=-1;this.playing=false;this._cycles=0}previousFrame(){if(this._frame>0)this._frame=this._frame-1;else if(this.looping)this._frame=this.length-1;this.targetFrame=-1;this.playing=false;this._cycles=0}goToFrame(toFrame){if(toFrame<0||toFrame>=this.length){return}this.targetFrame=toFrame;this._cycles=0;if(this.targetFrame!==this._frame){this.playing=true}return new Promise((resolve=>{this._onComplete=()=>{this._onComplete=null;resolve()}}))}get lastFrame(){return this.length-1}get frameImage(){let f=this._frame;let img=this[f];if(img instanceof p5.Image)return img;let{x:x,y:y,w:w,h:h}=img;let image=$.createImage(w,h);image.copy(this.spriteSheet,this.offset.x,this.offset.y,w,h,x,y,w,h);return image}get w(){return this.width}get width(){let frameInfo=this[this._frame];if(frameInfo instanceof p5.Image)return frameInfo.width;else if(frameInfo)return frameInfo.w;return 1}get defaultWidth(){return this[this._frame].defaultWidth}get h(){return this.height}get height(){let frameInfo=this[this._frame];if(frameInfo instanceof p5.Image)return frameInfo.height;else if(frameInfo)return frameInfo.h;return 1}get defaultHeight(){return this[this._frame].defaultHeight}};$.Ani.props=["demoMode","endOnFirstFrame","frameDelay","frameSize","looping","offset","rotation","scale"];this.Anis=class{#_={};constructor(){let _this=this;let props=[...$.Ani.props,"w","h"];let vecProps=["offset","scale"];for(let prop of props){Object.defineProperty(this,prop,{get(){return _this.#_[prop]},set(val){_this.#_[prop]=val;for(let k in _this){let x=_this[k];if(!(x instanceof Ani))continue;x[prop]=val}}})}for(let vecProp of vecProps){this.#_[vecProp]={_x:0,_y:0};for(let prop of["x","y"]){Object.defineProperty(this.#_[vecProp],prop,{get(){return _this.#_[vecProp]["_"+prop]},set(val){_this.#_[vecProp]["_"+prop]=val;for(let k in _this){let x=_this[k];if(!(x instanceof Ani))continue;x[vecProp][prop]=val}}})}}}get width(){return this.w}set width(val){this.w=val}get height(){return this.h}set height(val){this.h=val}};this.Group=class extends Array{constructor(...args){let parent;if(args[0]instanceof $.Group){parent=args[0];args=args.slice(1)}super(...args);if(typeof args[0]=="number")return;for(let s of this){if(!(s instanceof $.Sprite)){throw new Error("A group can only contain sprites")}}this._isGroup=true;this.x;this.y;this.vel;this.rotation;this.rotationSpeed;this.autoDraw;this.allowSleeping;this.autoUpdate;this.bounciness;this.collider;this.color;this.debug;this.density;this.direction;this.drag;this.friction;this.h;this.isSuperFast;this.layer;this.life;this.mass;this.mirror;this.offset;this.pixelPerfect;this.removed;this.rotationDrag;this.rotationLock;this.scale;this.shape;this.sleeping;this.stroke;this.strokeWeight;this.text;this.textColor;this.tile;this.tileSize;this.visible;this.w;this.bearing;this.d;this.dynamic;this.heading;this.kinematic;this.resetAnimationsOnChange;this.speed;this.static;this.idNum;if($.p5play.groupsCreated<999){this.idNum=$.p5play.groupsCreated}else{for(let i=1;i<$.p5play.groups.length;i++){if(!$.p5play.groups[i]?.removed){this.idNum=i;break}}if(!this.idNum){console.warn("ERROR: Surpassed the limit of 999 groups in memory. Try setting `p5play.storeRemovedGroupRefs = false`. Use less groups or delete groups from the p5play.groups array to recycle ids.");for(let i=1;i<$.p5play.groups.length;i++){if(!$.p5play.groups[i]?.length){this.idNum=i;break}}this.idNum??=1}}this._uid=this.idNum;$.p5play.groups[this._uid]=this;$.p5play.groupsCreated++;if(!$.allSprites)this._isAllSpritesGroup=true;this.subgroups=[];if(parent instanceof $.Group){parent.subgroups.push(this);let p=parent;do{p=$.p5play.groups[p.parent];p.subgroups.push(this)}while(!p._isAllSpritesGroup);this.parent=parent._uid}else if(!this._isAllSpritesGroup){$.allSprites.subgroups.push(this);this.parent=0}this.animations=new $.Anis;this._hasOverlap={};this._collisions={};this._overlappers={};let _this=this;this.Sprite=class extends $.Sprite{constructor(){super(_this,...arguments)}};this.GroupSprite=this.Sprite;this.Group=class extends $.Group{constructor(){super(_this,...arguments)}};this.Subgroup=this.Group;this.mouse={presses:null,pressing:null,pressed:null,holds:null,holding:null,held:null,released:null,hovers:null,hovering:null,hovered:null};for(let state in this.mouse){this.mouse[state]=function(inp){for(let s of _this){if(s.mouse[state](inp))return true}return false}}for(let prop of $.Sprite.propsAll){if(prop=="ani"||prop=="velocity"||prop=="width"||prop=="height"||prop=="diameter")continue;Object.defineProperty(this,prop,{get(){let val=_this["_"+prop];if(val===undefined&&!_this._isAllSpritesGroup){let parent=$.p5play.groups[_this.parent];if(parent){val=parent[prop]}}return val},set(val){_this["_"+prop]=val;for(let g of _this.subgroups){g["_"+prop]=val}for(let i=0;i<_this.length;i++){let s=_this[i];let v=val;if(typeof val=="function")v=val(i);s[prop]=v}}})}let vecProps=["mirror","offset","scale","vel"];for(let vecProp of vecProps){vecProp="_"+vecProp;if(vecProp!="vel")this[vecProp]={};else this[vecProp]=new $.Vector;this[vecProp]._x=0;this[vecProp]._y=0;for(let prop of["x","y"]){Object.defineProperty(this[vecProp],prop,{get(){let val=_this[vecProp]["_"+prop];let i=_this.length-1;if(val===undefined&&!_this._isAllSpritesGroup){let parent=$.p5play.groups[_this.parent];if(parent){val=parent[vecProp][prop];i=parent.length-1}}return val},set(val){_this[vecProp]["_"+prop]=val;for(let i=0;i<_this.length;i++){let s=_this[i];let v=val;if(typeof val=="function")v=val(i);s[vecProp][prop]=v}}})}}if(this._isAllSpritesGroup){this.autoCull=true;this.tileSize=1;this.autoDraw=true;this.autoUpdate=true}this.add=this.push;this.contains=this.includes}_getTopLayer(){if(this.length==0)return 0;if(this.length==1&&this[0]._layer===undefined)return 0;let max=this[0]._layer;for(let s of this){if(s._layer>max)max=s._layer}return max}get ani(){return this._ani}set ani(val){this.addAni(val);for(let s of this)s.changeAni(val)}get animation(){return this._ani}set animation(val){this.ani=val}get anis(){return this.animations}get img(){return this._img}set img(val){this.image=val}get image(){return this._img}set image(img){if(typeof img=="function"){this._img=img;return}if(typeof img=="string"){if(!img.includes(".")){img=new $.EmojiImage(img,this.w||this.width||this.d||this.diameter)}else img=$.loadImage(img)}this._img=$.Sprite.prototype._extendImage(img)}get amount(){return this.length}set amount(val){let diff=val-this.length;let shouldAdd=diff>0;diff=Math.abs(diff);for(let i=0;i<diff;i++){if(shouldAdd)new this.Sprite;else this[this.length-1].remove()}}get diameter(){return this.d}set diameter(val){this.d=val}get width(){return this.w}set width(val){this.w=val}get height(){return this.h}set height(val){this.h=val}get velocity(){return this.vel}set velocity(val){this.vel=val}_resetCentroid(){let x=0;let y=0;for(let s of this){x+=s.x;y+=s.y}this.centroid={x:x/this.length,y:y/this.length};return this.centroid}_resetDistancesFromCentroid(){for(let s of this){s.distCentroid={x:s.x-this.centroid.x,y:s.y-this.centroid.y}}}_validateCollideParams(target,cb){if(cb&&typeof cb!="function"){throw new FriendlyError("Group.collide",1,[cb])}if(!target){throw new FriendlyError("Group.collide",2)}if(!target._isGroup&&!target._isSprite){throw new FriendlyError("Group.collide",0,[target])}}_setContactCB(target,cb,contactType,eventType){if(target._isSprite){let reversedCB=function(a,b,v){return cb.call(b,b,a,v)};target._setContactCB(this,reversedCB,contactType,eventType);return}let type;if(contactType==0)type=eventTypes._collisions[eventType];else type=eventTypes._overlappers[eventType];let ledger=$.p5play[type];let l=ledger[this._uid]??={};if(l[target._uid]==cb)return;l[target._uid]=cb;for(let s of this){let c2=ledger[s._uid]??={};c2[target._uid]=cb}if(this._uid==target._uid)return;l=ledger[target._uid];if(!l||!l[this._uid])return;if(this._uid!=target._uid)delete l[this._uid];for(let s of target){l=ledger[s._uid];if(!l||!l[this._uid])continue;delete l[this._uid];if(Object.keys(l).length==0){delete ledger[s._uid]}}if(Object.keys(l).length==0){delete ledger[target._uid]}}_ensureCollide(target){if(this._hasOverlap[target._uid]!==false){this._hasOverlap[target._uid]=false;for(let s of this){s._hasOverlap[target._uid]=false;target._hasOverlap[s._uid]=false;if(this._uid==target._uid){for(let s2 of target){s._hasOverlap[s2._uid]=false;s2._hasOverlap[s._uid]=false}}}}if(target._hasOverlap[this._uid]!==false){target._hasOverlap[this._uid]=false;if(target._isGroup){for(let s of target){s._hasOverlap[this._uid]=false;this._hasOverlap[s._uid]=false;for(let s2 of this){s._hasOverlap[s2._uid]=false;s2._hasOverlap[s._uid]=false}}}}}collide(target,callback){return this.collides(target,callback)}collides(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,0);return this._collisions[target._uid]==1||this._collisions[target._uid]<=-3}colliding(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,1);let val=this._collisions[target._uid];if(val<=-3)return 1;return val>0?val:0}collided(target,callback){this._validateCollideParams(target,callback);this._ensureCollide(target);if(callback)this._setContactCB(target,callback,0,2);return this._collisions[target._uid]<=-1}_validateOverlapParams(target,cb){if(cb&&typeof cb!="function"){throw new FriendlyError("Group.overlap",1,[cb])}if(!target){throw new FriendlyError("Group.overlap",2)}if(!target._isGroup&&!target._isSprite){throw new FriendlyError("Group.overlap",0,[target])}}_ensureOverlap(target){if(!this._hasSensors){for(let s of this){if(!s._hasSensors)s.addDefaultSensors()}this._hasSensors=true}if(!target._hasSensors){if(target._isSprite){target.addDefaultSensors()}else{for(let s of target){if(!s._hasSensors)s.addDefaultSensors()}target._hasSensors=true}}if(this._hasOverlap[target._uid]!=true){this._removeContactsWith(target);this._hasOverlap[target._uid]=true;for(let s of this){s._hasOverlap[target._uid]=true;target._hasOverlap[s._uid]=true;if(this._uid==target._uid){for(let s2 of target){s._hasOverlap[s2._uid]=true;s2._hasOverlap[s._uid]=true}}}}if(target._hasOverlap[this._uid]!=true){target._removeContactsWith(this);target._hasOverlap[this._uid]=true;if(target._isGroup){for(let s of target){s._hasOverlap[this._uid]=true;this._hasOverlap[s._uid]=true;for(let s2 of this){s._hasOverlap[s2._uid]=true;s2._hasOverlap[s._uid]=true}}}}}overlap(target,callback){return this.overlaps(target,callback)}overlaps(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,0);return this._overlappers[target._uid]==1||this._overlappers[target._uid]<=-3}overlapping(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,1);let val=this._overlappers[target._uid];if(val<=-3)return 1;return val>0?val:0}overlapped(target,callback){this._validateOverlapParams(target,callback);this._ensureOverlap(target);if(callback)this._setContactCB(target,callback,1,2);return this._overlappers[target._uid]<=-1}_removeContactsWith(o){for(let s of this){s._removeContactsWith(o)}}applyForce(){for(let s of this){s.applyForce(...arguments)}}applyForceScaled(){for(let s of this){s.applyForceScaled(...arguments)}}attractTo(){for(let s of this){s.attractTo(...arguments)}}applyTorque(){for(let s of this){s.applyTorque(...arguments)}}move(distance,direction,speed){let movements=[];for(let s of this){movements.push(s.move(distance,direction,speed))}return Promise.all(movements)}moveTo(x,y,speed){if(typeof x!="number"){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return;speed=y;y=obj.y;x=obj.x}let centroid=this._resetCentroid();let movements=[];for(let s of this){let dest={x:s.x-centroid.x+x,y:s.y-centroid.y+y};movements.push(s.moveTo(dest.x,dest.y,speed))}return Promise.all(movements)}moveTowards(x,y,tracking){if(typeof x!="number"){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return;tracking=y;y=obj.y;x=obj.x}if(x===undefined&&y===undefined)return;this._resetCentroid();for(let s of this){if(s.distCentroid===undefined)this._resetDistancesFromCentroid();let dest={x:s.distCentroid.x+x,y:s.distCentroid.y+y};s.moveTowards(dest.x,dest.y,tracking)}}moveAway(x,y,repel){if(typeof x!="number"){let obj=x;if(obj==$.mouse&&!$.mouse.isActive)return;repel=y;y=obj.y;x=obj.x}if(x===undefined&&y===undefined)return;this._resetCentroid();for(let s of this){if(s.distCentroid===undefined)this._resetDistancesFromCentroid();let dest={x:s.distCentroid.x+x,y:s.distCentroid.y+y};s.moveAway(dest.x,dest.y,repel)}}push(...sprites){if(this.removed){console.warn("Adding a sprite to a group that was removed. Use `group.removeAll()` to remove all of a group's sprites without removing the group itself. Restoring the group in p5play's memory.");$.p5play.groups[this._uid]=this;this.removed=false}for(let s of sprites){if(!(s instanceof $.Sprite)){throw new Error("You can only add sprites to a group, not "+typeof s)}if(s.removed){console.error("Can't add a removed sprite to a group");continue}let b;for(let tuid in this._hasOverlap){let hasOverlap=this._hasOverlap[tuid];if(hasOverlap&&!s._hasSensors){s.addDefaultSensors()}if(tuid>=1e3)b=$.p5play.sprites[tuid];else b=$.p5play.groups[tuid];if(!b||b.removed)continue;if(!hasOverlap)b._ensureCollide(s);else b._ensureOverlap(s)}for(let event in eventTypes){let contactTypes=eventTypes[event];for(let contactType of contactTypes){let ledger=$.p5play[contactType];let lg=ledger[this._uid];if(!lg)continue;let ls=ledger[s._uid]??={};for(let b_uid in lg){ls[b_uid]=lg[b_uid]}}}super.push(s);if(this.parent)$.p5play.groups[this.parent].push(s);s.groups.push(this)}return this.length}repelFrom(){for(let s of this){s.repelFrom(...arguments)}}size(){return this.length}toString(){return"g"+this.idNum}cull(top,bottom,left,right,cb){if(left===undefined){let size=top;cb=bottom;top=bottom=left=right=size}if(isNaN(top)||isNaN(bottom)||isNaN(left)||isNaN(right)){throw new TypeError("The culling boundary must be defined with numbers")}if(cb&&typeof cb!="function"){throw new TypeError("The callback to group.cull must be a function")}let cx=$.camera.x-$.canvas.hw/$.camera.zoom;let cy=$.camera.y-$.canvas.hh/$.camera.zoom;let minX=-left+cx;let minY=-top+cy;let maxX=$.width+right+cx;let maxY=$.height+bottom+cy;let culled=0;for(let i=0;i<this.length;i++){let s=this[i];if(s.shape=="chain")continue;if(s.x<minX||s.y<minY||s.x>maxX||s.y>maxY){culled++;if(cb)cb(s,culled);else s.remove();if(s.removed)i--}}return culled}remove(item){if(item===undefined){this.removeAll();if(!this._isAllSpritesGroup)this.removed=true;return}let idx;if(typeof item=="number"){if(item>=0)idx=item;else idx=this.length+item}else{idx=this.indexOf(item)}if(idx==-1)return;let s=this[idx];this.splice(idx,1);return s}splice(idx,amount){let removed=super.splice(idx,amount);if(!removed)return;let gIDs=[];for(let s of removed){if(s.removed)continue;let gID=this._uid;do{gIDs.push(gID);let gIdx=s.groups.findIndex((g=>g._uid==gID));let g=s.groups.splice(gIdx,1);gID=g[0].parent}while(gID)}for(let gID of gIDs){let a=$.p5play.groups[gID];for(let eventType in eventTypes){for(let b_uid in a[eventType]){if(a[eventType][b_uid]==0)continue;let b;if(b_uid>=1e3)b=$.p5play.sprites[b_uid];else b=$.p5play.groups[b_uid];let inContact=false;for(let s of a){if(s[eventType][b._uid]>0){inContact=true;break}}if(!inContact){a[eventType][b._uid]=-2;b[eventType][a._uid]=-2}}}}return removed}pop(){return this.remove(this.length-1)}shift(){return this.remove(0)}unshift(){console.error("unshift is not supported for groups");return this.length}removeAll(){while(this.length>0){this.at(-1).remove()}}_step(){this.__step()}update(){for(let s of this){if(!$.p5play._inPostDraw||s.autoUpdate){s.update()}}if(this._autoUpdate)this._autoUpdate=null}draw(){let g=[...this];g.sort(((a,b)=>a._layer-b._layer));for(let s of g){if(s._visible!==false&&(!$.p5play._inPostDraw||s.autoDraw)){s.draw()}}if(this._autoDraw)this._autoDraw=null}postDraw(){for(let s of this){s.postDraw()}}};$.Group.prototype.addAni=$.Group.prototype.addAnimation=$.Sprite.prototype.addAnimation=$.Sprite.prototype.addAni;$.Group.prototype.addAnis=$.Group.prototype.addAnimations=$.Sprite.prototype.addAnimations=$.Sprite.prototype.addAnis;$.Group.prototype.__step=$.Sprite.prototype.__step;$.Group.prototype.___step=$.Sprite.prototype.___step;this.World=class extends planck.World{constructor(){super(new pl.Vec2(0,0),true);this.mod={};this.origin={x:0,y:0};this.contacts=[];this.on("begin-contact",this._beginContact);this.on("end-contact",this._endContact);let _this=this;this._gravity={get x(){return _this.m_gravity.x},set x(val){val=Math.round(val||0);if(val==_this.m_gravity.x)return;_this.mod[0]=true;for(let s of $.allSprites){s.sleeping=false}_this.m_gravity.x=val},get y(){return _this.m_gravity.y},set y(val){val=Math.round(val||0);if(val==_this.m_gravity.y)return;_this.mod[0]=true;for(let s of $.allSprites){s.sleeping=false}_this.m_gravity.y=val}};this._timeScale=1;this._updateRate=60;this._syncedToFrameRate=true;this._lastStepTime=0;this._setTimeStep();this.velocityIterations=8;this.positionIterations=3;this.velocityThreshold=.19;this.physicsTime=0;this.meterSize=60;this.mouseTracking??=true;this.mouseSprite=null;this.mouseSprites=[];this.autoStep=true;this.step=this.physicsUpdate;if(window.Event){this.steppedEvent=new window.Event("p5play_worldStepped")}}get gravity(){return this._gravity}set gravity(val){this._gravity.x=val.x;this._gravity.y=val.y}get timeScale(){return this._timeScale}set timeScale(val){if(val<0||val>2){return console.error("world.timeScale must be between 0 and 2")}if(this._timeScale==val)return;this._timeScale=val;this._setTimeStep()}get updateRate(){return this._updateRate}set updateRate(val){this._updateRate=val;this._syncedToFrameRate=val==$._targetFrameRate;this._setTimeStep()}_setTimeStep(){this._timeStep=1/this._updateRate*this._timeScale}get velocityThreshold(){return pl.Settings.velocityThreshold}set velocityThreshold(val){pl.Settings.velocityThreshold=val}physicsUpdate(timeStep,velocityIterations,positionIterations){usePhysics=true;timeScale=this._timeScale;for(let s of $.allSprites){s.prevPos.x=s.x;s.prevPos.y=s.y;s.prevRotation=s.rotation}timeStep??=this._timeStep;super.step(timeStep,velocityIterations||this.velocityIterations,positionIterations||this.positionIterations);this.physicsTime+=timeStep;let sprites=Object.values($.p5play.sprites);let groups=Object.values($.p5play.groups);for(let s of sprites)s._step();for(let g of groups)g._step();for(let s of sprites)s.___step();for(let g of groups)g.___step();if($.canvas.dispatchEvent){$.canvas.dispatchEvent(this.steppedEvent)}if(!this._syncedToFrameRate){for(let s of $.allSprites)s._syncWithPhysicsBody()}if(this.autoStep)this.autoStep=null}extrapolationUpdate(timeStep){timeStep??=this._timeStep;for(let s of $.allSprites){s.prevPos.x=s.x;s.prevPos.y=s.y;s.prevRotation=s.rotation}usePhysics=false;timeScale=timeStep/this._timeStep*this._timeScale;let sprites=Object.values($.p5play.sprites);let groups=Object.values($.p5play.groups);for(let s of sprites)s._step();for(let g of groups)g._step();if(this.autoStep)this.autoStep=null}get realTime(){return $.millis()/1e3}getSpritesAt(x,y,group,cameraActiveWhenDrawn=true){if(typeof x=="object"){cameraActiveWhenDrawn=group??true;group=y;y=x.y;x=x.x}const point=new pl.Vec2(x/this.meterSize,y/this.meterSize);const aabb=new pl.AABB;aabb.lowerBound=new pl.Vec2(point.x-.001,point.y-.001);aabb.upperBound=new pl.Vec2(point.x+.001,point.y+.001);let fxts=[];this.queryAABB(aabb,(fxt=>{if(fxt.getShape().testPoint(fxt.getBody().getTransform(),point)){fxts.push(fxt)}return true}));if(fxts.length==0)return[];group??=$.allSprites;let sprites=[];for(let fxt of fxts){const s=fxt.m_body.sprite;if(s._cameraActiveWhenDrawn==cameraActiveWhenDrawn){if(!sprites.find((x=>x._uid==s._uid)))sprites.push(s)}}sprites.sort(((a,b)=>(a._layer-b._layer)*-1));return sprites}getSpriteAt(x,y,group){const sprites=this.getSpritesAt(x,y,group);return sprites[0]}getMouseSprites(){let sprites=this.getSpritesAt($.mouse.x,$.mouse.y);if($.camera._wasOff){let uiSprites=this.getSpritesAt($.mouse.canvasPos.x,$.mouse.canvasPos.y,$.allSprites,false);if(uiSprites.length)sprites=[...uiSprites,...sprites]}return sprites}_beginContact(contact){let a=contact.m_fixtureA;let b=contact.m_fixtureB;let t="_collisions";if(a.m_isSensor)t="_overlappers";a=a.m_body.sprite;b=b.m_body.sprite;a[t][b._uid]=0;b[t][a._uid]=0;for(let g of b.groups){if(!a[t][g._uid]||a[t][g._uid]<0){a[t][g._uid]=0;g[t][a._uid]=0}}for(let g of a.groups){if(!b[t][g._uid]||b[t][g._uid]<0){b[t][g._uid]=0;g[t][b._uid]=0}for(let g2 of b.groups){if(!g[t][g2._uid]||g[t][g2._uid]<0){g[t][g2._uid]=0;g2[t][g._uid]=0}}}}_endContact(contact){let a=contact.m_fixtureA;let b=contact.m_fixtureB;let contactType="_collisions";if(a.m_isSensor)contactType="_overlappers";a=a.m_body.sprite;b=b.m_body.sprite;a[contactType][b._uid]=a[contactType][b._uid]!=0?-2:-4;b[contactType][a._uid]=b[contactType][a._uid]!=0?-2:-4;for(let g of b.groups){let inContact=false;for(let s of g){if(s[contactType][a._uid]>=0){inContact=true;break}}if(!inContact){g[contactType][a._uid]=g[contactType][a._uid]!=0?-2:-4;a[contactType][g._uid]=a[contactType][g._uid]!=0?-2:-4}}for(let g of a.groups){let inContact=false;for(let s of g){if(s[contactType][b._uid]>=0){inContact=true;break}}if(!inContact){g[contactType][b._uid]=g[contactType][b._uid]!=0?-2:-4;b[contactType][g._uid]=b[contactType][g._uid]!=0?-2:-4;for(let g2 of b.groups){g[contactType][g2._uid]=g[contactType][g2._uid]!=0?-2:-4;g2[contactType][g._uid]=g2[contactType][g._uid]!=0?-2:-4}}}}_findContact(type,s0,s1){let cb=s0[type][s1._uid];if(cb)return cb;for(let g1 of s1.groups){cb=s0[type][g1._uid];if(cb)return cb}for(let g0 of s0.groups){cb=g0[type][s1._uid];if(cb)return cb;for(let g1 of s1.groups){if(g0._uid!=g1._uid)continue;cb=g0[type][g1._uid];if(cb)return cb}}return false}get allowSleeping(){return this.getAllowSleeping()}set allowSleeping(val){this.setAllowSleeping(val)}rayCast(startPos,direction,maxDistance){let sprites=this.rayCastAll(startPos,direction,maxDistance,(()=>true));return sprites[0]}rayCastAll(startPos,direction,maxDistance,limiter){let ts=$.allSprites.tileSize;let start=scaleTo(startPos.x,startPos.y,ts);let end;if(typeof arguments[1]=="number"){end=scaleTo(startPos.x+maxDistance*$.cos(direction),startPos.y+maxDistance*$.sin(direction),ts)}else{let endPos=arguments[1];limiter??=arguments[2];end=scaleTo(endPos.x,endPos.y,ts)}let results=[];let maxFraction=1;super.rayCast(start,end,(function(fixture,point,normal,fraction){let sprite=fixture.getBody().sprite;let shouldLimit=limiter&&limiter(sprite);results.push({sprite:sprite,fraction:fraction});if(shouldLimit){if(fraction<maxFraction){maxFraction=fraction}return fraction}return 1}));results.sort(((a,b)=>a.fraction-b.fraction));let sprites=[];for(let res of results){if(res.fraction<=maxFraction){sprites.push(res.sprite)}}return sprites}};this.Camera=class{constructor(){this._pos=$.createVector.call($);this.__pos={x:0,y:0,rounded:{}};this.isActive=false;this.bound={min:{x:0,y:0},max:{x:0,y:0}};this._zoomIdx=-1;this._zoom=1;this._destIdx=0}get pos(){return this._pos}set pos(val){this.x=val.x;this.y=val.y}get position(){return this._pos}set position(val){this.x=val.x;this.y=val.y}_calcBoundsX(val){let mod=$.canvas.hw/this._zoom;this.bound.min.x=val-mod;this.bound.max.x=val+mod}_calcBoundsY(val){let mod=$.canvas.hh/this._zoom;this.bound.min.y=val-mod;this.bound.max.y=val+mod}get x(){return this._pos.x}set x(val){if(val===undefined||isNaN(val))return;this._pos.x=val;let x=-val;if($.canvas.renderer=="2d")x+=$.canvas.hw/this._zoom;this.__pos.x=x;if($.allSprites.pixelPerfect){this.__pos.rounded.x=Math.round(x)}this._calcBoundsX(val)}get y(){return this._pos.y}set y(val){if(val===undefined||isNaN(val))return;this._pos.y=val;let y=-val;if($.canvas.renderer=="2d")y+=$.canvas.hh/this._zoom;this.__pos.y=y;if($.allSprites.pixelPerfect){this.__pos.rounded.y=Math.round(y)}this._calcBoundsY(val)}moveTo(x,y,speed){if(x===undefined)return;if(isNaN(x)){speed=y;y=x.y;x=x.x}speed??=1;if(speed<=0){console.warn("camera.moveTo: speed should be a positive number");return Promise.resolve(false)}let a=y-this.y;let b=x-this.x;let c=Math.sqrt(a*a+b*b);let percent=speed/c;let velX=b*percent;let velY=a*percent;this._destIdx++;let destIdx=this._destIdx;let steps=Math.ceil(c/speed);return(async()=>{for(let i=0;i<steps;i++){this.x+=velX;this.y+=velY;await $.sleep();if(destIdx!=this._destIdx)return false}this.x=x;this.y=y;return true})()}get zoom(){return this._zoom}set zoom(val){if(val===undefined||isNaN(val))return;this._zoom=val;let x=-this._pos.x;if($.canvas.renderer=="2d")x+=$.canvas.hw/val;let y=-this._pos.y;if($.canvas.renderer=="2d")y+=$.canvas.hh/val;this.__pos.x=x;this.__pos.y=y;if($.allSprites.pixelPerfect){this.__pos.rounded.x=Math.round(x);this.__pos.rounded.y=Math.round(y)}this._calcBoundsX(this._pos.x);this._calcBoundsY(this._pos.y)}zoomTo(target,speed){if(target==this._zoom)return Promise.resolve(true);speed??=.1;let delta=Math.abs(target-this._zoom);let frames=Math.round(delta/speed);if(target<this.zoom)speed=-speed;this._zoomIdx++;let zoomIdx=this._zoomIdx;return(async()=>{for(let i=0;i<frames;i++){if(zoomIdx!=this._zoomIdx)return false;this.zoom+=speed;await $.sleep()}this.zoom=target;return true})()}on(){if(!this.isActive){$.push();$.scale(this._zoom);if(!$.allSprites.pixelPerfect){$.translate(this.__pos.x,this.__pos.y)}else{this.__pos.rounded.x??=Math.round(this.__pos.x);this.__pos.rounded.y??=Math.round(this.__pos.y);$.translate(this.__pos.rounded.x,this.__pos.rounded.y)}this.isActive=true}}off(){if(this.isActive){$.pop();this.isActive=false}}};pl.Fixture.prototype.shouldCollide=function(that){let a=this;let b=that;if(a.m_isSensor&&b.m_isSensor)return true;if(a.m_isSensor||b.m_isSensor)return false;a=a.m_body.sprite;b=b.m_body.sprite;let shouldOverlap=a._hasOverlap[b._uid]??b._hasOverlap[a._uid];if(shouldOverlap)return false;return true};this.Tiles=class{constructor(tiles,x,y,w,h){if(typeof tiles=="string"){if(tiles[0]=="\n")tiles=tiles.slice(1);tiles=tiles.replaceAll("\t"," ");tiles=tiles.split("\n")}x??=0;y??=0;w??=1;h??=1;let sprites=new $.Group;for(let row=0;row<tiles.length;row++){for(let col=0;col<tiles[row].length;col++){let t=tiles[row][col];if(t==" "||t==".")continue;let ani,g;let groups=Object.values($.p5play.groups);for(g of groups){ani=g.animations[t];if(ani)break}if(ani){sprites.push(new g.Sprite(ani,x+col*w,y+row*h));continue}let wasFound=false;for(g of groups){if(g.tile==t){wasFound=true;break}}if(wasFound){sprites.push(new g.Sprite(x+col*w,y+row*h));continue}let s;for(s of $.allSprites){if(s.tile==t){wasFound=true;break}}if(wasFound){s.x=x+col*w;s.y=y+row*h;continue}throw"Tile not found: "+t}}return sprites}};this.createTiles=function(tiles,x,y,w,h){return new $.Tiles(tiles,x,y,w,h)};this.Joint=class{constructor(spriteA,spriteB,type){if(!spriteA?._isSprite||!spriteB?._isSprite){throw new Error("The Joint constructor requires two sprites as input.")}if(!spriteA.body)spriteA.addDefaultSensors();if(!spriteB.body)spriteB.addDefaultSensors();this.spriteA=spriteA;this.spriteB=spriteB;type??="glue";this.type=type;if(type=="glue"){let j=pl.WeldJoint({},spriteA.body,spriteB.body,spriteA.body.getWorldCenter());this._createJoint(j)}let _this=this;if(type!="glue"&&type!="slider"&&type!="rope"){for(let l of["A","B"]){if(l=="A"&&type=="wheel")continue;const prop="_offset"+l;this[prop]=$.createVector.call($);for(let axis of["x","y"]){Object.defineProperty(this[prop],axis,{get(){let val=_this._j["m_localAnchor"+l][axis]/_this["sprite"+l].tileSize*$.world.meterSize;return $.p5play.friendlyRounding?fixRound(val):val},set(val){_this._j["m_localAnchor"+l][axis]=val/$.world.meterSize*_this["sprite"+l].tileSize;if(_this.type=="distance"||_this.type=="rope"){_this._j.m_length=pl.Vec2.distance(_this._j.m_bodyA.getWorldPoint(_this._j.m_localAnchorA),_this._j.m_bodyB.getWorldPoint(_this._j.m_localAnchorB))}else if(_this.type=="hinge"||_this.type=="wheel"){let o;if(l=="A")o="B";else o="A";_this._j["m_localAnchor"+o][axis]=_this._j["m_body"+o].getLocalPoint(_this._j["m_body"+l].getWorldPoint(_this._j["m_localAnchor"+l]))[axis]}}})}}}let removeProps=[];if(type=="distance"||type=="glue"||type=="rope"){removeProps.push("enableMotor","maxPower","motorSpeed","power","speed")}if(type=="rope"){removeProps.push("damping","springiness")}let def={};for(let prop of removeProps){def[prop]={value:null,enumerable:false}}Object.defineProperties(this,def);this.visible=true;spriteA.joints.push(this);spriteB.joints.push(this)}_createJoint(j){this._j=$.world.createJoint(j)}_display(){this._draw(this.spriteA.x,this.spriteA.y,this.spriteB.x,this.spriteB.y);this.visible=null}_draw(xA,yA,xB,yB){if(yB){$.line(xA,yA,xB,yB)}else{$.point(xA,yA)}}get draw(){return this._display}set draw(val){this._draw=val}get offsetA(){return this._offsetA}set offsetA(val){this._offsetA.x=val.x;this._offsetA.y=val.y}get offsetB(){return this._offsetB}set offsetB(val){this._offsetB.x=val.x;this._offsetB.y=val.y}get springiness(){return this._springiness}set springiness(val){if(val>0){if(val<.1){val=$.map(val,0,.1,30,4)}else if(val<.5){val=$.map(val,.1,.5,4,2.5)}else if(val<.8){val=$.map(val,.5,.8,2.5,1)}else if(val<.9){val=$.map(val,.8,.9,1,.5)}else{val=$.map(val,.9,1,.5,.2)}}this._springiness=val;if(this.type!="wheel")return this._j.setFrequency(val);this._j.setSpringFrequencyHz(val)}get damping(){if(this.type!="wheel"){return this._j.getDampingRatio()}return this._j.getSpringDampingRatio()}set damping(val){if(this.type!="wheel"){this._j.setDampingRatio(val);return}this._j.setSpringDampingRatio(val)}get speed(){return this._j.getJointSpeed()}set speed(val){if(!this._j.isMotorEnabled()){this._j.enableMotor(true)}this._j.setMotorSpeed(val)}get motorSpeed(){return this._j.getMotorSpeed()}get enableMotor(){return this._j.isMotorEnabled()}set enableMotor(val){this._j.enableMotor(val)}get maxPower(){return this._j.getMaxMotorTorque()}set maxPower(val){if(!this._j.isMotorEnabled()&&val){this._j.enableMotor(true)}this._j.setMaxMotorTorque(val);if(!val)this._j.enableMotor(false)}get power(){return this._j.getMotorTorque()}get collideConnected(){return this._j.getCollideConnected()}set collideConnected(val){this._j.m_collideConnected=val}get reactionForce(){return this._j.getReactionForce($.world._timeStep)}get reactionTorque(){return this._j.getReactionTorque($.world._timeStep)}remove(){if(this._removed)return;this.spriteA.joints.splice(this.spriteA.joints.indexOf(this),1);this.spriteB.joints.splice(this.spriteB.joints.indexOf(this),1);$.world.destroyJoint(this._j);this._removed=true}};this.GlueJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"glue")}};this.DistanceJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"distance");let j=pl.DistanceJoint({},spriteA.body,spriteB.body,spriteA.body.getWorldCenter(),spriteB.body.getWorldCenter());this._createJoint(j)}_display(){let ancA,ancB;if(this.offsetA.x||this.offsetA.y){ancA=this.spriteA.body.getWorldPoint(this._j.m_localAnchorA);ancA=scaleFrom(ancA.x,ancA.y,this.spriteA.tileSize)}if(this.offsetB.x||this.offsetB.y){ancB=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB);ancB=scaleFrom(ancB.x,ancB.y,this.spriteB.tileSize)}this._draw(!ancA?this.spriteA.x:ancA.x,!ancA?this.spriteA.y:ancA.y,!ancB?this.spriteB.x:ancB.x,!ancB?this.spriteB.y:ancB.y);this.visible=null}};this.WheelJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"wheel");let j=pl.WheelJoint({maxMotorTorque:1e3,frequencyHz:4,dampingRatio:.7},spriteA.body,spriteB.body,spriteB.body.getWorldCenter(),new pl.Vec2(0,1));this._createJoint(j);this._angle=$._angleMode==DEGREES?90:1.5707963267948966}_display(){let xA=this.spriteA.x;let yA=this.spriteA.y;let xB,yB;if(!this.offsetB.x&&!this.offsetB.y){xB=this.spriteB.x;yB=this.spriteB.y}else{let ancB=this.spriteB.body.getWorldPoint(this._j.m_localAnchorB);ancB=scaleFrom(ancB.x,ancB.y,this.spriteB.tileSize);xB=ancB.x;yB=ancB.y}let slopeA=$.tan(this.spriteA.rotation);let slopeB=$.tan(this._angle+this.spriteA.rotation);let xI=(yB-yA+slopeA*xA-slopeB*xB)/(slopeA-slopeB);let yI=slopeA*(xI-xA)+yA;this._draw(xI,yI,xB,yB);this.visible=null}get angle(){return this._angle}set angle(val){if(val==this._angle)return;this._angle=val;this._j.m_localXAxisA=new pl.Vec2($.cos(val),$.sin(val));this._j.m_localXAxisA.normalize();this._j.m_localYAxisA=pl.Vec2.crossNumVec2(1,this._j.m_localXAxisA)}};this.HingeJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"hinge");let j=pl.RevoluteJoint({},spriteA.body,spriteB.body,spriteA.body.getWorldCenter());this._createJoint(j)}_display(){const offsetAx=this.offsetA.x;const offsetAy=this.offsetA.y;const rotationA=this.spriteA.rotation;const rotatedOffsetAx=offsetAx*$.cos(rotationA)-offsetAy*$.sin(rotationA);const rotatedOffsetAy=offsetAx*$.sin(rotationA)+offsetAy*$.cos(rotationA);this._draw(this.spriteA.x+rotatedOffsetAx,this.spriteA.y+rotatedOffsetAy);this.visible=null}get range(){return this.upperLimit-this.lowerLimit}set range(val){val/=2;this.upperLimit=val;this.lowerLimit=-val}get lowerLimit(){let val=this._j.getLowerLimit();if($._angleMode=="radians")return val;return $.degrees(val)}set lowerLimit(val){if(!this._j.isLimitEnabled()){this._j.enableLimit(true)}this.spriteA.body.setAwake(true);this.spriteB.body.setAwake(true);if($._angleMode==DEGREES)val=$.radians(val);this._j.m_lowerAngle=val}get upperLimit(){let val=this._j.getUpperLimit();if($._angleMode=="radians")return val;return $.degrees(val)}set upperLimit(val){if(!this._j.isLimitEnabled()){this._j.enableLimit(true)}this.spriteA.body.setAwake(true);this.spriteB.body.setAwake(true);if($._angleMode==DEGREES)val=$.radians(val);this._j.m_upperAngle=val}get angle(){let ang=this._j.getJointAngle();if($._angleMode=="radians")return ang;return $.radians(ang)}};$.RevoluteJoint=$.HingeJoint;this.SliderJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"slider");let j=pl.PrismaticJoint({lowerTranslation:-1,upperTranslation:1,enableLimit:true,maxMotorForce:50,motorSpeed:0,enableMotor:true},spriteA.body,spriteB.body,spriteA.body.getWorldCenter(),new pl.Vec2(1,0));this._createJoint(j);this._angle=0}get angle(){return this._angle}set angle(val){if(val==this._angle)return;this._angle=val;this._j.m_localXAxisA=new pl.Vec2($.cos(val),$.sin(val));this._j.m_localXAxisA.normalize();this._j.m_localYAxisA=pl.Vec2.crossNumVec2(1,this._j.m_localXAxisA)}get range(){return this.upperLimit-this.lowerLimit}set range(val){val/=2;this.upperLimit=val;this.lowerLimit=-val}get lowerLimit(){return this._j.getLowerLimit()/this.spriteA.tileSize*$.world.meterSize}set lowerLimit(val){if(!this._j.isLimitEnabled()){this._j.enableLimit(true)}val=val*this.spriteA.tileSize/$.world.meterSize;this._j.setLimits(val,this._j.getUpperLimit())}get upperLimit(){return this._j.getUpperLimit()/this.spriteA.tileSize*$.world.meterSize}set upperLimit(val){if(!this._j.isLimitEnabled()){this._j.enableLimit(true)}val=val*this.spriteA.tileSize/$.world.meterSize;this._j.setLimits(this._j.getLowerLimit(),val)}};$.PrismaticJoint=$.SliderJoint;this.RopeJoint=class extends $.Joint{constructor(spriteA,spriteB){super(...arguments,"rope");let j=pl.RopeJoint({maxLength:1},spriteA.body,spriteB.body,spriteA.body.getWorldCenter());this._createJoint(j);this._j.m_localAnchorB.x=0;this._j.m_localAnchorB.y=0}get maxLength(){return scaleXFrom(this._j.getMaxLength(),this.spriteA.tileSize)}set maxLength(val){this._j.setMaxLength(scaleXTo(val,this.spriteA.tileSize))}};this.GrabberJoint=class extends this.Joint{constructor(sprite){super(sprite,sprite,"grab");this._target={x:0,y:0};this.__target=new pl.Vec2(0,0);let j=pl.MouseJoint({maxForce:1e3,frequencyHz:3,dampingRatio:.9,target:sprite.body.getPosition()},sprite.body,sprite.body);this._createJoint(j)}_draw(){$.line(this.spriteA.x,this.spriteA.y,this._target.x,this._target.y)}get target(){return this._target}set target(pos){this._target.x=pos.x;this._target.y=pos.y;this.__target.x=pos.x/$.world.meterSize;this.__target.y=pos.y/$.world.meterSize;this._j.setTarget(this.__target)}get maxForce(){return this._j.getMaxForce()}set maxForce(val){this._j.setMaxForce(val)}};class Scale{constructor(){let _this=this;Object.defineProperties(this,{x:{get(){return _this._x},set(val){if(val==_this._x)return;_this._x=val;_this._avg=(_this._x+_this._y)*.5},configurable:true,enumerable:true},y:{get(){return _this._y},set(val){if(val==_this._y)return;_this._y=val;_this._avg=(_this._x+_this._y)*.5},configurable:true,enumerable:true},_x:{value:1,enumerable:false,writable:true},_y:{value:1,enumerable:false,writable:true},_avg:{value:1,enumerable:false,writable:true}})}valueOf(){return this._avg}}function isArrowFunction(fn){return!/^(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*(?:(?:(?:async\s(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*\s*)?function|class)(?:\s|(?:(?:\/\*[^(?:\*\/)]*\*\/\s*)|(?:\/\/[^\r\n]*))*)|(?:[_$\w][\w0-9_$]*\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\()|(?:\[\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*(?:(?:['][^']+['])|(?:["][^"]+["]))\s*(?:\/\*[^(?:\*\/)]*\*\/\s*)*\s*\]\())/.test(fn.toString())}function isColliderType(t){if(t=="d"||t=="s"||t=="k"||t=="n")return true;let abr=t.slice(0,2);return abr=="dy"||abr=="st"||abr=="ki"||abr=="no"}function getRegularPolygon(lineLength,name){let l=lineLength;let n=name.toLowerCase();if(n=="triangle")l=[l,-120,3];else if(n=="square")l=[l,-90,4];else if(n=="pentagon")l=[l,-72,5];else if(n=="hexagon")l=[l,-60,6];else if(n=="septagon")l=[l,-51.4285714286,7];else if(n=="octagon")l=[l,-45,8];else if(n=="enneagon")l=[l,-40,9];else if(n=="decagon")l=[l,-36,10];else if(n=="hendecagon")l=[l,-32.7272727273,11];else if(n=="dodecagon")l=[l,-30,12];if(l==lineLength)throw new Error("Invalid, not a regular polygon: "+name);return l}$.p5play.palettes=[{a:"aqua",b:"black",c:"crimson",d:"darkviolet",e:"peachpuff",f:"olive",g:"green",h:"hotpink",i:"indigo",j:"navy",k:"khaki",l:"lime",m:"magenta",n:"brown",o:"orange",p:"pink",q:"turquoise",r:"red",s:"skyblue",t:"tan",u:"blue",v:"violet",w:"white",x:"gold",y:"yellow",z:"gray"}];this.colorPal=(c,palette)=>{if(c instanceof p5.Color)return c;if(typeof palette=="number"){palette=$.p5play.palettes[palette]}palette??=$.p5play.palettes[0];let clr=palette[c];if(!clr)return $.color(0,0,0,0);return $.color(clr)};this.EmojiImage=function(emoji,textSize){$.push();$.textSize(textSize);let g=$.createGraphics(textSize,textSize*1.25);g.textSize(textSize);g.textAlign($.CENTER);g.text(emoji,textSize/2,textSize);let ctx=g.drawingContext;let pd=g._pixelDensity||1;let w=g.canvas.width;let h=g.canvas.height;let data=ctx.getImageData(0,0,w,h).data;let left=w,right=0,top=h,bottom=0;let i=3;for(let y=0;y<h;y++){for(let x=0;x<w;x++){if(data[i]!==0){if(x<left)left=x;if(x>right)right=x;if(y<top)top=y;if(y>bottom)bottom=y}i+=4}}top=Math.floor(top/pd);bottom=Math.floor(bottom/pd);left=Math.floor(left/pd);right=Math.floor(right/pd);g=g.get(left,top,right-left+1,bottom-top+1);$.pop();g.url=emoji;return g};this.spriteArt=(txt,scale,palette)=>{scale??=1;if(typeof palette=="number"){palette=$.p5play.palettes[palette]}palette??=$.p5play.palettes[0];let lines=txt;if(typeof txt=="string"){txt=txt.trim();txt=txt.replace(/\r*\n\t+/g,"\n");txt=txt.replace(/\s+$/g,"");lines=txt.split("\n")}let w=0;for(let line of lines){if(line.length>w)w=line.length}let h=lines.length;let img=$.createImage(w*scale,h*scale);img.loadPixels();for(let i=0;i<lines.length;i++){for(let j=0;j<lines[i].length;j++){for(let sX=0;sX<scale;sX++){for(let sY=0;sY<scale;sY++){let c=this.colorPal(lines[i][j],palette);img.set(j*scale+sX,i*scale+sY,c)}}}}img.updatePixels();img.w=img.width;img.h=img.height;$.p5play.onImageLoad(img);return img};this.createSprite=function(){return new $.Sprite(...arguments)};this.createGroup=function(){return new $.Group(...arguments)};this.loadAnimation=this.loadAni=function(){return new $.Ani(...arguments)};this.animation=function(ani,x,y,r,sX,sY){if(ani.visible)ani.update();ani.draw(x,y,r,sX,sY)};this.delay=milliseconds=>{if(!milliseconds)return new Promise(requestAnimationFrame);return new Promise((resolve=>{setTimeout(resolve,milliseconds)}))};this.sleep=milliseconds=>{if(!milliseconds){return new Promise((resolve=>{if($.canvas.dispatchEvent){function handler(){$.canvas.removeEventListener("p5play_worldStepped",handler);resolve()}$.canvas.addEventListener("p5play_worldStepped",handler)}else{setTimeout(resolve,$.world._timeStep*1e3)}}))}return $.delay(milliseconds)};this.play=sound=>{if(!sound?.play){throw new Error("Tried to play your sound but it wasn't a sound object.")}return new Promise((resolve=>{sound.play();sound.onended((()=>resolve()))}))};async function playIntro(){if(document.getElementById("p5play-intro"))return;$._incrementPreload();let d=document.createElement("div");d.id="p5play-intro";d.style="position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 1000; background-color: black;";let logo=document.createElement("img");logo.style=`position: absolute; top: 50%; left: 50%; width: 80vmin; height: 40vmin; margin-left: -40vmin; margin-top: -20vmin; z-index: 1001; opacity: 1; scale: 1; transition: scale 1.5s, opacity 0.4s ease-in-out;`;logo.onerror=()=>{logo.style.imageRendering="pixelated";logo.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABACAYAAADS1n9/AAABbGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAACiRfZC/S0JhGIWfm4VgNkQNDg13igYr0SCXBjWQIkisQG26Xn+C2sfVCKMtWkPoP8igOWgoIgxaGhqCqCGitqamgpaSL+69hS51lvfhcDgcXujxaEKUeoFypWbEo2E1kUypzhcUFCxpelWEYrEFk39vlxT4uLezt+Nm12u7uRvciV6Wj88XNx88k/wvVyZb1YEvwKcLowaKF4ht1ITJW8CwkUimQGmYnLf5wOS0zSdWZjkeAeUaUPWClgHlFfCmu/x8F5dL6/rPMnO9O1tZWTJ7gBFmKVJFUEKjjkqMwB/5KSsfYQ1BHYMieQrUUAkhrIYsKnNU0JnAi4ofH3785p/tuo+7n/95O972M8y0pJRnHW++BUfT4DrteGNBGOyHq1OhGZplOYCeXA7eDmEgCUM34Fqt5gJ+e707DH1PUr6PgnMP2g0pP/elbDfB8QgXlW8Y/mq9pjC8gwAABSxJREFUeJztnb9y2zAMxulcpnbNntfJ3D5n97xO966Z3aNP9NHgBxAgQVmO8bvLNZZIiCI+gH8kpyl4bk7P3gErOJ/PZ0+zp9NpmZ9CAM54O7+wSgQhAEdWOb+wQgSvzZHAj5+/50x9/WkOeRMZwIkm+medXyAi8M4CL82R4KkIATjQRL8nJJN4XysEsAKv9L8DIYAnJyaBk8CUTDLA51/bbP7jHWSQRZPByADeTDp/tM4ozT4AVHSwO1kEMBMY/dTLFNcMcN5oSgTHYHBi2fPrS4qo98Mh/a+C8/ErdyJYw8cbb/bzH/ncGQY8aOYAnpThZ4XGerZdrn209fxIe6rVQw52Oif4NquAfF+d+Y6NSeej9C9F/714WAHkyP5uoxcSCBKSic5WMhwCciTlcnUaRSmVRlw5x0UiVx6VqW1Ru1zbaHl6TXS9Efae3GmuNzpXYDMA7VT6OxKE9nhPKNy1ZlHbEdL/qPNRdHsy2i5WAIk41yt6emM1Jw5OcL12eg4VR1rWmRCGAVEAGjhncseLQ7SOebZV6t4TxWEBcFHHOayO7PoHUcpy/y5FSP+jWJ06KoKRDAUngZxDUXrVlOsdR0jX8vjsxaqI1dilG0ciWdjgHcN4GqgERdcR1/VayjwgBFDzQG/yJEaASKgSIYBnAgg8BKAARRWKvkcjDwMhgAKIjkcACREJlgOuAu5K7Qgwaz0KeQaOOn9vTCsBwLwApMiZdOBROpnj3u2bdX5aPQfwaOBuDIr1HveYryldl30wBO4RZ4AS1aXCbFr2skezTa5b2+7Z7Z2nNjZKh3Jja3HGHtlAcnwyOj+/HIIFUACd0TizbhzTQU1ddAzYg+WYY5d0TM5dXql6A2VzO7n0jUS6kTtXuseVQ4Im01icXxgfApgOuvy8pevPjD3VuRrhRpu29trG2GI7eWPFkKCJerZdzH2UV8NUAsiqR8pnG5YdJjjNZA+8aYvqIq6dQqNfC9N5YofvDNuO3HbQ/tNG+dwVQOmwS8QAg/kY26lABF17Aqq65DgSlSkzMR2ZpM53hmsve32mvehLIvIcoFyIaUB9vhZB3bBmbJ6cLJkfrb4PRj+FmSAeCsbxiXF+0mSAG5WhDtjSfT32S3TtUb6wsMS6Qkd4TtKQoI62b0FTPkW3EQQ6G908KgcB5aA9BKir4WFf59q4ZNneF0eYZ/4SUxtB4lg88rVoLnqEa7CAOqz9J0Y9Caw/N44FnX0zYQPHRXsI4RqQ0Zk/B1iNUB5RYKohgN4svNG8GiApCpbr2QN2uHN08nmBGSK4ttyLkd1D1TBgxGUV4F1OOk/PSWUTENsRqJ3ovo1M5gHo+4A13/YPRd4sS2c7V/m1795WMJvZlNvIUv1RTtzXw2mqncXbnsSSqCJwIuCua3GetX4zBBj+ntDlBCeCYGNg2Vo7UXIeR6nv9fSPE0EIoAdwfs095xis85NeAC/SyWDSCQLXJ6cT9T2Ajo+MQOhkgWTMBMh55iecPSxDQHBLEwCG7WfJkd13CYS6mvpXrJPAoKURQdILATnSkrKbjTJLugc7piGAQWZEkDS7dMIj5utWulQf2SNIzk8hgD6zIoBQRy36n0U0k/sQgAIogjT/Z9saHO1pV3YhACUuImCcNWRPsGVZ1ocAjEAh9JwmOAsyaG9kPycEMAAUQWIcp3CWt71gB84SP34JJ7Gzm0I1A/a0hGomsTigF6VWZ3pEfQjAAY3jLM7yticRAnAEOW7GUd72ECEAZ2qneTjL294NKaX/gKttC9Kft4MAAAAASUVORK5CYII="};let src=window._p5play_intro_image;if(src==""||src?.includes("made_with_p5play")){if(src.includes("bit.")||src.includes("pixel")){logo.style.imageRendering="pixelated"}logo.src=src}else{logo.src="https://p5play.org/assets/made_with_p5play.webp"}await new Promise((r=>logo.onload=r));d.append(logo);document.body.append(d);await $.delay();logo.offsetHeight;logo.style.scale=1.2;await $.delay(1100);logo.style.opacity=0;await $.delay(400);d.style.display="none";d.remove();document.getElementById("p5play-intro")?.remove();$._decrementPreload()}if(window.location){let lh=location.hostname;switch(lh){case"":case"127.0.0.1":case"localhost":case"p5play.org":case"editor.p5js.org":case"codepen.io":case"codera.app":case"aug4th.com":case"cdpn.io":case"glitch.com":case"replit.com":case"stackblitz.com":case"jsfiddle.net":case"aijs.io":case"preview-aijs.web.app":case"quinton-ashley.github.io":break;default:if(/^[\d\.]+$/.test(lh)||lh.endsWith(".lan")||lh.endsWith("stackblitz.io")||lh.endsWith("glitch.me")||lh.endsWith("replit.dev")||lh.endsWith("codehs.com")||lh.endsWith("openprocessing.org")||location.origin.endsWith("preview.p5js.org")){break}playIntro()}}let userDisabledP5Errors=p5.disableFriendlyErrors;p5.disableFriendlyErrors=true;const _createCanvas=$.createCanvas;this.createCanvas=function(){let args=[...arguments];let displayMode,renderQuality,displayScale;if(typeof args[0]=="string"){if(args[0].includes(":")){let ratio=args[0].split(":");let rW=Number(ratio[0]);let rH=Number(ratio[1]);let w=window.innerWidth;let h=window.innerWidth*(rH/rW);if(h>window.innerHeight){w=window.innerHeight*(rW/rH);h=window.innerHeight}args[0]=Math.round(w);args.splice(1,0,Math.round(h));displayMode="fullscreen"}else{args=[0,0,...args]}}if(!args[0]){args[0]=window.innerWidth;args[1]=window.innerHeight;displayMode="fullscreen"}if(typeof args[2]=="string"){let rend=args[2].toLowerCase().split(" ");if(rend[0]=="pixelated"){renderQuality="pixelated";if(!rend[1])displayMode="fullscreen";else{displayMode="centered";displayScale=Number(rend[1].slice(1))}args.splice(2,1)}else if(rend[0]=="fullscreen"){displayMode="fullscreen";args.splice(2,1)}}let rend=_createCanvas.call($,...args);$.ctx=$.drawingContext;let c=rend.canvas||rend;if(rend.GL)c.renderer="webgl";if(c.renderer!="webgpu")c.renderer="2d";c.tabIndex=0;c.w=args[0];c.h=args[1];if(c.addEventListener){c.addEventListener("keydown",(function(e){if(e.key==" "||e.key=="/"||e.key=="ArrowUp"||e.key=="ArrowDown"||e.key=="ArrowLeft"||e.key=="ArrowRight"){e.preventDefault()}}));c.addEventListener("mouseover",(()=>{this.mouse.isOnCanvas=true;this.mouse.isActive=true}));c.addEventListener("mouseleave",(()=>{this.mouse.isOnCanvas=false}));c.addEventListener("touchstart",(e=>e.preventDefault()));c.addEventListener("contextmenu",(e=>e.preventDefault()))}c.save??=$.saveCanvas.bind($);c.resize??=$.resizeCanvas.bind($);c.hw=c.w*.5;c.hh=c.h*.5;c.mouse={x:$.mouseX,y:$.mouseY};if(c.renderer=="2d"&&!$._webgpuFallback){$.camera.x=$.camera.ogX=c.hw;$.camera.y=$.camera.ogY=c.hh}else{$.camera.x=0;$.camera.y=0;if(c.renderer=="webgl")$._textCache=false;if(!$._webgpuFallback){$.p5play._renderStats={x:-c.hw+10,y:-c.hh+20}}}if(!userDisabledP5Errors)p5.disableFriendlyErrors=false;$.displayMode(displayMode,renderQuality,displayScale);return rend};this.Canvas=class{constructor(width,height,renderer,options){this.w;this.width;this.h;this.height;this.hw;this.hh;this.mouse}resize(){}save(){}};this.canvas=$.canvas;$.Canvas=function(){return $.createCanvas(...arguments).canvas};const _resizeCanvas=$.resizeCanvas;this.resizeCanvas=(w,h)=>{w??=window.innerWidth;h??=window.innerHeight;_resizeCanvas.call($,w,h);let c=$.canvas;c.w=c.width/$.pixelDensity();c.h=c.height/$.pixelDensity();c.hw=c.w*.5;c.hh=c.h*.5;if(c.fullscreen){if(c.w/c.h>window.innerWidth/window.innerHeight){c.style.width="100%!important";c.style.height="auto!important"}else{c.style.width="auto!important";c.style.height="100%!important"}}if(c.renderer=="2d"){$.camera.x=c.hw;$.camera.y=c.hh}else{$.camera.x=0;$.camera.y=0}};const _frameRate=$.frameRate;this.frameRate=function(hz){let ret=_frameRate.call($,hz);if(hz)$.world._setTimeStep();return ret};const _background=$.background;this.background=function(){let args=arguments;if(args.length==1&&args[0]?.length==1){_background.call($,$.colorPal(args[0]))}else _background.call($,...args)};const _fill=$.fill;this.fill=function(){let args=arguments;if(args.length==1&&args[0]?.length==1){_fill.call($,$.colorPal(args[0]))}else _fill.call($,...args)};const _stroke=$.stroke;this.stroke=function(){let args=arguments;if(args.length==1&&args[0]?.length==1){_stroke.call($,$.colorPal(args[0]))}else _stroke.call($,...args)};const _loadImage=$.loadImage;this.loadImage=this.loadImg=function(){if($.p5play.disableImages){$._decrementPreload();return{w:16,width:16,h:16,height:16,pixels:[]}}let args=arguments;let url=args[0];let img=$.p5play.images[url];let cb;if(typeof args[args.length-1]=="function"){cb=args[args.length-1]}if(img){if(img.width<=1&&img.height<=1||!img.pixels?.length){if(cb){img.cbs.push(cb);img.calls++}else $._decrementPreload()}else{if(cb)cb();$._decrementPreload()}return img}const _cb=_img=>{if(!_img.w){Object.defineProperty(_img,"w",{get:function(){return this.width}});Object.defineProperty(_img,"h",{get:function(){return this.height}})}if(_img.cbs){for(let cb of _img.cbs){cb(_img)}for(let i=1;i<_img.calls;i++){$._decrementPreload()}_img.cbs=[]}$.p5play.onImageLoad(img)};img=_loadImage.call($,url,_cb);img.cbs=[];img.calls=1;if(cb)img.cbs.push(cb);img.url=url;$.p5play.images[url]=img;return img};const _image=$.image;$.image=function(){if($.p5play.disableImages)return;_image.call($,...arguments)};if(!$.displayMode&&typeof document=="object"){document.head.insertAdjacentHTML("beforeend",`<style>\nhtml, body {\n\tmargin: 0;\n\tpadding: 0;\n}\nbody.hasFrameBorder {\n\tdisplay: block;\n}\n.p5Canvas {\n\toutline: none;\n\t-webkit-touch-callout: none;\n\t-webkit-text-size-adjust: none;\n\t-webkit-user-select: none;\n\toverscroll-behavior: none;\n}\n.p5-pixelated {\n\timage-rendering: pixelated;\n\tfont-smooth: never;\n\t-webkit-font-smoothing: none;\n}\n.p5-centered,\n.p5-maxed,\n.p5-fullscreen {\n display: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\nmain.p5-centered,\nmain.p5-maxed,\n.p5-fullscreen {\n\theight: 100vh;\n}\nmain {\n\toverscroll-behavior: none;\n}\n</style>`);$._adjustDisplay=()=>{let c=$.canvas;let s=c.style;let p=c.parentElement;if(!s||!p||!c.displayMode)return;if(c.renderQuality=="pixelated"){c.classList.add("p5-pixelated");$.pixelDensity(1);if($.noSmooth)$.noSmooth();if($.textFont)$.textFont("monospace")}if(c.displayMode=="normal"){p.classList.remove("p5-centered","p5-maxed","p5-fullscreen");s.width=c.w*c.displayScale+"px";s.height=c.h*c.displayScale+"px"}else{p.classList.add("p5-"+c.displayMode);p=p.getBoundingClientRect();if(c.w/c.h>p.width/p.height){if(c.displayMode=="centered"){s.width=c.w*c.displayScale+"px";s.maxWidth="100%"}else s.width="100%";s.height="auto";s.maxHeight=""}else{s.width="auto";s.maxWidth="";if(c.displayMode=="centered"){s.height=c.h*c.displayScale+"px";s.maxHeight="100%"}else s.height="100%"}}};$.displayMode=(displayMode="normal",renderQuality="default",displayScale=1)=>{let c=$.canvas;if(typeof displayScale=="string"){displayScale=parseFloat(displayScale.slice(1))}Object.assign(c,{displayMode:displayMode,renderQuality:renderQuality,displayScale:displayScale});$._adjustDisplay()}}let errMsgs={generic:["Ah! I found an error","Oh no! Something went wrong","Oof! Something went wrong","Houston, we have a problem","Whoops, having trouble here"],Sprite:{constructor:{base:"Sorry I'm unable to make a new Sprite",0:"What is $0 for? If you're trying to specify the x position of the sprite, please specify the y position as well.",1:"If you're trying to specify points for a chain Sprite, please use an array of position arrays.\n$0",2:"Invalid input parameters: $0"},hw:{0:"I can't change the halfWidth of a Sprite directly, change the sprite's width instead."},hh:{1:"I can't change the halfHeight of a Sprite directly, change the sprite's height instead."},rotate:{0:"Can't use this function on a sprite with a static collider, try changing the sprite's collider type to kinematic.",1:'Can\'t use "$0" for the angle of rotation, it must be a number.'},rotateTo:{},rotateMinTo:{},rotateTowards:{},changeAnimation:`I can't find any animation named "$0".`,collide:{0:"I can't make that sprite collide with $0. Sprites can only collide with another sprite or a group.",1:"The collision callback has to be a function.",2:"You're trying to check for an collision with a sprite or group that doesn't exist!"},overlap:{0:"I can't make that sprite overlap with $0. Sprites can only overlap with another sprite or a group.",1:"The overlap callback has to be a function.",2:"You're trying to check for an overlap with a sprite or group that doesn't exist!"}},Ani:{constructor:{base:"Hey so, I tried to make a new Ani but couldn't",1:"The name of the animation must be the first input parameter."},frame:"Index $0 out of bounds. That means there is no frame $0 in this animation. It only has $1 frames!"},Group:{constructor:{base:"Hmm awkward! Well it seems I can't make that new Group you wanted"}}};errMsgs.Group.collide=errMsgs.Sprite.collide;errMsgs.Group.overlap=errMsgs.Sprite.overlap;errMsgs.Sprite.rotateTo[0]=errMsgs.Sprite.rotateMinTo[0]=errMsgs.Sprite.rotateTowards[0]=errMsgs.Sprite.rotate[0];class FriendlyError extends Error{constructor(func,errorNum,e){super();if(typeof func!="string"){e=errorNum;errorNum=func;func=this.stack.match(/\n\s*at ([^\(]*)/)[1];func=func.slice(0,-1)}if(typeof errorNum!="number"){e=errorNum;errorNum=undefined}if(func.slice(0,3)=="new")func=func.slice(4);func=func.split(".");let className=func[0];func=func[1]||"constructor";let ln=this.stack.match(/\/([^p\/][^5][^\/:]*:[^\/:]+):/);if(ln){ln=ln[1].split(":");ln=" in "+ln[0]+" at line "+ln[1]}ln=" using "+className+"."+func+". ";e=e||[];let m=errMsgs[className][func];let msg;if(m.base)msg=m.base+ln;else msg=errMsgs.generic[Math.floor(Math.random()*errMsgs.generic.length)]+ln;if(errorNum!==undefined)m=m[errorNum];if(m){m=m.replace(/\$([0-9]+)/g,((m,n)=>e[n]));msg+=m}p5._friendlyError(msg,func)}}this.allSprites=new $.Group;this.world=new $.World;this.camera=new $.Camera;this.InputDevice=class{constructor(){this.holdThreshold=12;this._default=0}_ac(inp){return inp}presses(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);return this[inp]==1||this[inp]==-3}pressing(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);if(this[inp]==-3)return 1;return this[inp]>0?this[inp]:0}pressed(inp){return this.released(inp)}holds(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);return this[inp]==this.holdThreshold}holding(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);return this[inp]>=this.holdThreshold?this[inp]:0}held(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);return this[inp]==-2}released(inp){inp??=this._default;if(this[inp]===undefined)inp=this._ac(inp);return this[inp]<=-1}releases(inp){return this.released(inp)}};this._Mouse=class extends $.InputDevice{constructor(){super();this._default="left";let _this=this;this._pos=$.createVector.call($);Object.defineProperty(this._pos,"x",{get(){return _this.x},set(val){_this.x=val}});Object.defineProperty(this._pos,"y",{get(){return _this.y},set(val){_this.y=val}});this.x=0;this.y=0;this.canvasPos={};this.left=0;this.center=0;this.right=0;this.drag={left:0,center:0,right:0};this._dragFrame={left:false,center:false,right:false};this.isOnCanvas=false;this.isActive=false;this._visible=true;this._cursor="default";this._ogX=0;this._ogY=0}_ac(inp){inp=inp.toLowerCase();if(inp.slice(0,4)=="left")inp="left";else if(inp.slice(0,5)=="right")inp="right";else if(inp.slice(0,6)=="middle")inp="center";return inp}_update(){$.mouse.canvasPos.x=$.mouseX;$.mouse.canvasPos.y=$.mouseY;if($.camera.x==$.camera.ogX&&$.camera.y==$.camera.ogY&&$.camera.zoom==1){this.x=$.mouseX;this.y=$.mouseY}else if($.canvas.renderer!="webgpu"){this.x=($.mouseX-$.canvas.hw)/$.camera.zoom+$.camera.x;this.y=($.mouseY-$.canvas.hh)/$.camera.zoom+$.camera.y}else{this.x=$.mouseX/$.camera.zoom+$.camera.x;this.y=$.mouseY/$.camera.zoom+$.camera.y}}get pos(){return this._pos}get position(){return this._pos}get cursor(){return $.canvas.style.cursor}set cursor(val){if(val!=this._cursor){$.cursor(val);this._cursor=val}}get visible(){return this._visible}set visible(val){this._visible=val;if(val)$.canvas.style.cursor="default";else $.canvas.style.cursor="none"}drags(inp){inp??=this._default;return this.drag[inp]==1}dragging(inp){inp??=this._default;return this.drag[inp]>0?this.drag[inp]:0}dragged(inp){inp??=this._default;return this.drag[inp]<=-1}};this.mouse=new $._Mouse;this._SpriteMouse=class extends $._Mouse{constructor(){super();delete this.canvasPos;this.hover=0}hovers(){return this.hover==1}hovering(){return this.hover>0?this.hover:0}hovered(){return this.hover<=-1}};const __onmousedown=function(btn){$.mouse.isActive=true;$.mouse[btn]++;if($.world.mouseSprites.length){let msm=$.world.mouseSprite?.mouse;if(msm){msm[btn]=0;msm.hover=0;msm.drag[btn]=0}ms=$.world.mouseSprites[0];$.world.mouseSprite=ms;msm=ms.mouse;msm[btn]=1;if(msm.hover<=0)msm.hover=1}};const _onmousedown=$._onmousedown;$._onmousedown=function(e){if(!$._setupDone)return;let btn="left";if(e.button===1)btn="center";else if(e.button===2)btn="right";__onmousedown.call($,btn);_onmousedown.call($,e)};const __onmousemove=function(btn){let m=$.mouse;if(m[btn]>0)m._dragFrame[btn]=true};const _onmousemove=$._onmousemove;$._onmousemove=function(e){if(!$._setupDone)return;let btn="left";if(e.button===1)btn="center";else if(e.button===2)btn="right";__onmousemove.call($,btn);_onmousemove.call($,e)};const __onmouseup=function(btn){let m=$.mouse;if(m[btn]>=m.holdThreshold)m[btn]=-2;else if(m[btn]>1)m[btn]=-1;else m[btn]=-3;if(m.drag[btn]>0)m.drag[btn]=-1;let msm=$.world.mouseSprite?.mouse;if(!msm)return;if(msm.hover>1){if(msm[btn]>=$.mouse.holdThreshold)msm[btn]=-2;else if(msm[btn]>1)msm[btn]=-1;else msm[btn]=-3;if(msm.drag[btn]>0)msm.drag[btn]=-1}else{msm[btn]=0;msm.drag[btn]=0}};const _onmouseup=$._onmouseup;$._onmouseup=function(e){if(!$._setupDone)return;let btn="left";if(e.button===1)btn="center";else if(e.button===2)btn="right";__onmouseup.call($,btn);_onmouseup.call($,e)};this._Touch=class extends $.InputDevice{constructor(touch){super();this.x;this.y;this.id=touch.identifier;this._default="duration";this.holdThreshold=$.touches.holdThreshold;this.duration=1;this.drag=0;this._dragFrame=false;this.canvasPos={};this._update(touch)}_update(v){let c=$.canvas;const rect=c.getBoundingClientRect();const sx=c.scrollWidth/c.w||1;const sy=c.scrollHeight/c.h||1;const x=this.canvasPos.x=(v.clientX-rect.left)/sx;const y=this.canvasPos.y=(v.clientY-rect.top)/sy;if($.camera.x==c.hw&&$.camera.y==c.hh&&$.camera.zoom==1){this.x=x;this.y=y}else{this.x=(x-c.hw)/$.camera.zoom+$.camera.x;this.y=(y-c.hh)/$.camera.zoom+$.camera.y}this.force=v.force}};this.touches=[];$.touches.holdThreshold=12;$._ontouchstart=function(e){if(!$._setupDone)return;if($.getAudioContext&&$.getAudioContext()?.state=="suspended")$.userStartAudio();for(let touch of e.changedTouches){$.touches.push(new $._Touch(touch));if($.touches.length==1){$.mouseX=$.touches[0].x;$.mouseY=$.touches[0].y;$.mouse._update();$.world.mouseSprites=$.world.getMouseSprites();$._onmousedown(e)}}if($.touchStarted&&!$.touchStarted(e))e.preventDefault()};$._ontouchmove=function(e){if(!$._setupDone)return;for(let touch of e.changedTouches){let t=$.touches.find((t=>t.id==touch.identifier));t._update(touch);t._dragFrame=true;if(t.id==$.touches[0].id){$.mouseX=$.touches[0].x;$.mouseY=$.touches[0].y;$.mouse._update();$._onmousemove(e)}}if($.touchMoved&&!$.touchMoved(e))e.preventDefault()};$._ontouchend=function(e){if(!$._setupDone)return;for(let touch of e.changedTouches){let t=$.touches.find((t=>t.id==touch.identifier));t._update(touch);if(t.duration>=t.holdThreshold)t.duration=-2;else if(t.duration>1)t.duration=-1;else t.duration=-3;if(t.drag>0)t.drag=-1;if(t.id==$.touches[0].id){$.mouseX=$.touches[0].x;$.mouseY=$.touches[0].y;$.mouse._update();$._onmouseup(e)}}if($.touchEnded&&!$.touchEnded(e))e.preventDefault()};this._Keyboard=class extends $.InputDevice{constructor(){super();this._default=" ";this.alt=0;this.arrowUp=0;this.arrowDown=0;this.arrowLeft=0;this.arrowRight=0;this.backspace=0;this.capsLock=0;this.control=0;this.enter=0;this.meta=0;this.shift=0;this.tab=0;let k=this._simpleKeyControls={arrowUp:"up",arrowDown:"down",arrowLeft:"left",arrowRight:"right"};k.w=k.W="up";k.s=k.S="down";k.a=k.A="left";k.d=k.D="right";k.i=k.I="up2";k.k=k.K="down2";k.j=k.J="left2";k.l=k.L="right2"}get visible(){return this._inp==document.activeElement}set visible(v){if(!this._inp){this._inp=Object.assign(document.createElement("input"),{type:"text",style:"position: fixed; height: 0; padding: 0; border: none; opacity: 0.0001; pointer-events: none;"});document.body.appendChild(this._inp)}this._visible=v;v?this._inp.focus():this._inp.blur()}_ac(inp){if(inp.length!=1){if(!isNaN(inp)){if(inp==38)return"arrowUp";if(inp==40)return"arrowDown";if(inp==37)return"arrowLeft";if(inp==39)return"arrowRight";if(inp>=10){throw new Error("Use key names with the keyboard input functions, not keyCode numbers!")}return inp}inp=inp.replaceAll(/[ _-]/g,"")}inp=inp.toLowerCase();if(inp.length!=1){if(inp=="arrowup")return"arrowUp";if(inp=="arrowdown")return"arrowDown";if(inp=="arrowleft")return"arrowLeft";if(inp=="arrowright")return"arrowRight";if(inp=="capslock")return"capsLock"}return inp}_pre(k){if(!this[k]||this[k]<0){this[k]=1}}_rel(k){if(this[k]>=this.holdThreshold)this[k]=-2;else if(this[k]>1)this[k]=-1;else this[k]=-3}get cmd(){return this["meta"]}get command(){return this["meta"]}get ctrl(){return this["control"]}get space(){return this[" "]}get spacebar(){return this[" "]}get opt(){return this["alt"]}get option(){return this["alt"]}get win(){return this["meta"]}get windows(){return this["meta"]}};this.kb=new $._Keyboard;this.keyboard=$.kb;if(typeof navigator=="object"&&navigator.keyboard){const keyboard=navigator.keyboard;if(window==window.top){keyboard.getLayoutMap().then((keyboardLayoutMap=>{const key=keyboardLayoutMap.get("KeyW");if(key!="w")$.p5play.standardizeKeyboard=true}))}else{$.p5play.standardizeKeyboard=true}}else{$.p5play.standardizeKeyboard=true}function _getKeyFromCode(e){let code=e.code;if(code.length==4&&code.slice(0,3)=="Key"){return code[3].toLowerCase()}return e.key}const _onkeydown=$._onkeydown;$._onkeydown=function(e){let key=e.key;if(this.p5play.standardizeKeyboard){key=_getKeyFromCode(e)}if(key.length>1){key=key[0].toLowerCase()+key.slice(1)}else{let lower=key.toLowerCase();let upper=key.toUpperCase();if(lower!=upper){if(key!=upper)this.kb._pre(upper);else this.kb._pre(lower)}}this.kb._pre(key);let k=this.kb._simpleKeyControls[key];if(k)this.kb._pre(k);_onkeydown.call(this,e)};const _onkeyup=$._onkeyup;$._onkeyup=function(e){let key=e.key;if(this.p5play.standardizeKeyboard){key=_getKeyFromCode(e)}if(key.length>1){key=key[0].toLowerCase()+key.slice(1)}else{let lower=key.toLowerCase();let upper=key.toUpperCase();if(lower!=upper){if(key!=upper)this.kb._rel(upper);else this.kb._rel(lower)}}this.kb._rel(key);let k=this.kb._simpleKeyControls[key];if(k)this.kb._rel(k);if(e.shiftKey){let k=key.toLowerCase();if(this.kb[k]>0)this.kb._rel(k)}_onkeyup.call(this,e)};this.Contro=class extends $.InputDevice{constructor(gp){super();this._default="a";this.connected=true;this.a=0;this.b=0;this.x=0;this.y=0;this.l=0;this.r=0;this.lt=0;this.rt=0;this.select=0;this.start=0;this.lsb=0;this.rsb=0;this.up=0;this.down=0;this.left=0;this.right=0;this.leftStick={x:0,y:0};this.rightStick={x:0,y:0};this.leftTrigger=0;this.rightTrigger=0;this.buttonMapping={a:0,b:1,x:2,y:3,l:4,r:5,lt:6,rt:7,select:8,start:9,lsb:10,rsb:11,up:12,down:13,left:14,right:15};this.axeMapping={leftStick:{x:0,y:1},rightStick:{x:2,y:3},leftTrigger:4,rightTrigger:5};this.isMock=false;if(typeof gp!="string"){this.gamepad=gp;this.id=gp.id}else{this.gamepad={};this.id=gp;this.isMock=true}this._axeTriggers=this.gamepad.axes&&this.gamepad.axes[this.axeMapping.leftTrigger]!==undefined;this.hasAnalogTriggers=this._axeTriggers||undefined;if(this.id.includes("GuliKit")){this.buttonMapping.a=1;this.buttonMapping.b=0;this.buttonMapping.x=3;this.buttonMapping.y=2}}_ac(inp){inp=inp.toLowerCase();if(inp=="lb")inp="l";else if(inp=="rb")inp="r";else if(inp=="leftstickbutton")inp="lsb";else if(inp=="rightstickbutton")inp="rsb";return inp}_update(){if(this.isMock)return;this.gamepad=navigator.getGamepads()[this.gamepad.index];if(!this.gamepad?.connected)return;let pad=this.gamepad;for(let name in this.buttonMapping){let idx=this.buttonMapping[name];let b=pad.buttons[idx];if(!b)continue;if(b.pressed)this[name]++;else this[name]=this[name]>0?-1:0}this.leftStick.x=pad.axes[this.axeMapping.leftStick.x];this.leftStick.y=pad.axes[this.axeMapping.leftStick.y];this.rightStick.x=pad.axes[this.axeMapping.rightStick.x];this.rightStick.y=pad.axes[this.axeMapping.rightStick.y];if(this._axeTriggers){this.leftTrigger=pad.axes[this.axeMapping.leftTrigger];this.rightTrigger=pad.axes[this.axeMapping.rightTrigger]}else{this.leftTrigger=pad.buttons[this.buttonMapping.lt].value;this.rightTrigger=pad.buttons[this.buttonMapping.rt].value;if(this.hasAnalogTriggers===undefined&&(this.leftTrigger||this.rightTrigger)){this.hasAnalogTriggers=!Number.isInteger(this.leftTrigger)||!Number.isInteger(this.rightTrigger)}}return true}_reset(){for(let name in this.buttonMapping){this[name]=0}this.leftStick.x=0;this.leftStick.y=0;this.rightStick.x=0;this.rightStick.y=0;this.leftTrigger=0;this.rightTrigger=0}get cross(){return this.a}get circle(){return this.b}get square(){return this.x}get triangle(){return this.y}get ls(){return this.leftStick}get rs(){return this.rightStick}get lb(){return this.l}get rb(){return this.r}get l1(){return this.l}get r1(){return this.r}get zl(){return this.lt}get zr(){return this.rt}get l2(){return this.leftTrigger}get r2(){return this.rightTrigger}get leftStickButton(){return this.lsb}get rightStickButton(){return this.rsb}get l3(){return this.lsb}get r3(){return this.rsb}};this._Contros=class extends Array{constructor(){super();if(window){window.addEventListener("gamepadconnected",(e=>{this._onConnect(e.gamepad)}));window.addEventListener("gamepaddisconnected",(e=>{this._onDisconnect(e.gamepad)}))}if(typeof navigator!="object"||!navigator.getGamepads)return;let gps=navigator.getGamepads();for(let gp of gps){if(gp)this._onConnect(gp)}}swap(indexA,indexB){let tmp=this[indexA];this[indexA]=this[indexB];this[indexB]=tmp;if(indexA==0||indexB==0){$.contro=this[0];if(!$._q5&&$._isGlobal){window.contro=this[0]}}}remove(index){this[index]=null}onConnect(gamepad){return true}onDisconnect(gamepad){return false}_onConnect(gp){if(!gp)return;for(let i=0;i<this.length;i++){if(gp.index==this[i].gamepad?.index){this[i].connected=true;log("contros["+i+"] reconnected: "+gp.id);return}}log(gp);if(this.onConnect(gp)){let c=new $.Contro(gp);let index=0;for(let i=0;i<=this.length;i++){if(!this[i]){index=i;break}}this[index]=c;log("contros["+index+"] connected: "+gp.id);if(index==0){$.contro=c;if($._isGlobal)window.contro=c}}}_onDisconnect(gp){if(!gp)return;for(let i=0;i<this.length;i++){if(this[i].gamepad?.index===gp.index){this[i].connected=false;log("contros["+i+"] disconnected: "+gp.id);if(this.onDisconnect(gp))this.remove(i);else this[i]._reset();return}}}_update(){for(let c of this){if(c.connected)c._update()}}};this.contros=new $._Contros;this.controllers=$.contros;this.contro=new $.Contro("mock0");if($._webgpuFallback)$._beginRender=false;this.getFPS??=()=>$.p5play._fps;$.renderStats=()=>{let rs=$.p5play._renderStats;if(!rs.fontSize){if($.allSprites.tileSize==1||$.allSprites.tileSize>16){rs.fontSize=16}else{rs.fontSize=10}rs.gap=rs.fontSize*1.25}if(!$.p5play._fpsAvg||$.frameCount%20===0){let avg=0;let len=$.p5play._fpsArr.length;for(let i=0;i<len;i++){avg+=$.p5play._fpsArr[i]}avg=Math.round(avg/len);let min=Math.min(...$.p5play._fpsArr);$.p5play._fpsAvg=avg;$.p5play._fpsMin=min;$.p5play._fpsMax=Math.max(...$.p5play._fpsArr);$.p5play._fpsArr=[];let c;if(min>55)c=$.color(30,255,30);else if(min>25)c=$.color(255,100,30);else c=$.color(255,30,30);$.p5play._statsColor=c}$.p5play._fpsArr.push($.getFPS());$.push();$.fill(0,0,0,128);$.rect(rs.x-5,rs.y-rs.fontSize,rs.fontSize*8.5,rs.gap*5+5);$.fill($.p5play._statsColor);$.textAlign("left");$.textSize(rs.fontSize);if(rs.font)$.textFont(rs.font);let x=rs.x;let y=rs.y;$.text("sprites: "+$.p5play.spritesDrawn,x,y);$.text("display: "+Math.round($.frameRate())+"hz",x,y+rs.gap);$.text("fps avg: "+$.p5play._fpsAvg,x,y+rs.gap*2);$.text("fps min: "+$.p5play._fpsMin,x,y+rs.gap*3);$.text("fps max: "+$.p5play._fpsMax,x,y+rs.gap*4);$.pop()};this.update??=()=>{};this.drawFrame??=()=>{};if($._isGlobal&&window.update){$.update=window.update}if($._isGlobal&&window.drawFrame){$.drawFrame=window.drawFrame}}));p5.prototype.registerMethod("pre",(function p5playPreDraw(){const $=this;if(!$._q5){$.p5play._preDrawFrameTime=performance.now()}$.p5play.spritesDrawn=0;$.mouse._update();$.contros._update();$.update();if($.allSprites._autoUpdate){$.allSprites.update()}$.allSprites._autoUpdate??=true}));p5.prototype.registerMethod("post",(function p5playPostDraw(){const $=this;$.p5play._inPostDraw=true;if($.allSprites.autoCull){$.allSprites.cull(1e4)}if($.world.autoStep&&$.world.timeScale>0){$.world.physicsUpdate()}$.world.autoStep??=true;$.drawFrame();if($.allSprites._autoDraw){$.camera.on();$.allSprites.draw()}$.allSprites._autoDraw??=true;$.camera.off();$.allSprites.postDraw();if($.p5play.renderStats)$.renderStats();for(let k in $.kb){if(k=="holdThreshold")continue;if($.kb[k]<0)$.kb[k]=0;else if($.kb[k]>0)$.kb[k]++}for(let i=0;i<$.touches.length;i++){let t=$.touches[i];t.duration++;if(t._dragFrame){t.drag++;t._dragFrame=false}else if(t.drag<0){t.drag=0}if(t.duration<=0){$.touches.splice(i,1);i--}}let m=$.mouse;let msm=$.world.mouseSprite?.mouse;for(let btn of["left","center","right"]){if(m[btn]<0)m[btn]=0;else if(m[btn]>0)m[btn]++;if(msm?.hover)msm[btn]=m[btn];if(m._dragFrame[btn]){m.drag[btn]++;if(msm)msm.drag[btn]=m.drag[btn];m._dragFrame[btn]=false}else if(m.drag[btn]<0){m.drag[btn]=0;if(msm)msm.drag[btn]=0}}if($.world.mouseTracking&&$.mouse.isActive){let sprites=$.world.getMouseSprites();for(let i=0;i<sprites.length;i++){let s=sprites[i];if(i==0)s.mouse.hover++;else if(s.mouse.hover>0)s.mouse.hover=-1;else if(s.mouse.hover<0)s.mouse.hover=0}if(m.left<=0&&m.center<=0&&m.right<=0){$.world.mouseSprite=null}let ms=$.world.mouseSprite;let isDragging=m.drag.left>0||m.drag.center>0||m.drag.right>0;for(let s of $.world.mouseSprites){if(!sprites.includes(s)){let sm=s.mouse;if(sm.hover>0){sm.hover=-1;sm.left=sm.center=sm.right=0}if(!isDragging&&s==ms)$.world.mouseSprite=ms=null}}if(ms){if(!sprites.includes(ms))sprites.push(ms);msm.x=ms.x-m.x;msm.y=ms.y-m.y}$.world.mouseSprites=sprites}if(!$._q5){$.p5play._postDrawFrameTime=performance.now();$.p5play._fps=Math.round(1e3/($.p5play._postDrawFrameTime-$.p5play._preDrawFrameTime))||1}$.p5play._inPostDraw=false}));