UNPKG

p5.raycaster

Version:

a simple p5js library for semi 3d rendering with ray casting

1 lines 33.5 kB
!function(t,i){"object"==typeof exports&&"object"==typeof module?module.exports=i():"function"==typeof define&&define.amd?define([],i):"object"==typeof exports?exports.RayCaster=i():t.RayCaster=i()}(self,(()=>(()=>{"use strict";var t={d:(i,e)=>{for(var s in e)t.o(e,s)&&!t.o(i,s)&&Object.defineProperty(i,s,{enumerable:!0,get:e[s]})},o:(t,i)=>Object.prototype.hasOwnProperty.call(t,i),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},i={};t.r(i),t.d(i,{createCamera:()=>c,createSkyBox:()=>w,createSprite:()=>y,createTextureMap:()=>m,createWorld:()=>u,initKeyboardControl:()=>M,initMouseControl:()=>g,initPointerLockControl:()=>x});const e=class{constructor(t,i,e,s,o=0,h=0,r=0,a=null){if(this.pos={x:i.x,y:i.y},this.ang=o,this.src=t,this.width=e,this.height=s,this.pInst=a,this.yAdjustment=h,this.animationGap=r,this.scaleP={x:1,y:1},this.buffer=null,null!==this.pInst)this.buffer=this.pInst.createGraphics(this.width,this.height);else{if(!window.createGraphics)throw new Error("p5 is not found!");this.buffer=window.createGraphics(this.width,this.height)}this.animationFrames=Math.floor(this.src.height/this.height),this.animationGroups=[];let l=[];for(let t=0;t<this.animationFrames;t++)l.push(t);this.animationGroups.push(l),this.rotationFrames=Math.floor(this.src.width/this.width),this.currentRotation=0,this.currentAnimation=0,this.currentAnimationGroup=0,this.currentAnimationIdx=0,this.rotationFrames>1&&(this.rotationDivision=2*Math.PI/this.rotationFrames,this.updateRotationFrame(Math.PI)),this.drawBuffer()}setAnimationGap(t){this.animationGap=t}setAnimationGroups(t){this.animationGroups=t}setCurrentAnimationGroup(t){this.animationGroups&&t>-1&&t<this.animationGroups.length&&(this.currentAnimationGroup=t,this.currentAnimationIdx=0,this.currentAnimation=this.animationGroups[this.currentAnimationGroup][this.currentAnimationIdx])}setYAdjustment(t){this.yAdjustment=t}update(t){this.animationGap<=0||1===this.animationFrames||t%this.animationGap==0&&this.nextAnimationFrame()}nextAnimationFrame(){this.currentAnimationIdx++,this.currentAnimationIdx=this.currentAnimationIdx%this.animationGroups[this.currentAnimationGroup].length,this.currentAnimation=this.animationGroups[this.currentAnimationGroup][this.currentAnimationIdx],this.drawBuffer()}updateAnimationFrame(t){if(this.currentAnimation!==t){let i,e;this.currentAnimation=t,this.animationGroups.forEach(((t,s)=>{let o=t.indexOf(this.currentAnimation);o>-1&&(i=s,e=o)})),this.currentAnimationGroup=i,this.currentAnimationIdx=e,this.drawBuffer()}}updateRotationFrame(t){let i,e;if(1===this.rotationFrames)e=0;else{for(i=t-this.ang+this.rotationDivision/2;i<0;)i+=2*Math.PI;for(;i>2*Math.PI;)i-=2*Math.PI;e=Math.floor(i/this.rotationDivision)}this.currentRotation!==e&&(this.currentRotation=e,this.drawBuffer())}move(t){if(!this.world)return;let i=Math.floor(this.pos.x+t.x)+Math.floor(this.pos.y)*this.world.width,e=Math.floor(this.pos.x)+Math.floor(this.pos.y+t.y)*this.world.width;this.world.map[i]!==this.world.table.MAP_FLOOR&&this.world.doorStates[i]!==this.world.table.DOOR_OPEN||Math.floor(this.pos.x+t.x)>-1&&Math.floor(this.pos.x+t.x)<this.world.width&&(this.pos.x+=t.x),this.world.map[e]!==this.world.table.MAP_FLOOR&&this.world.doorStates[e]!==this.world.table.DOOR_OPEN||Math.floor(this.pos.y+t.y)>-1&&Math.floor(this.pos.y+t.y)<this.world.height&&(this.pos.x+=t.y)}rotate(t){this.ang+=t}rotateTo(t){this.ang=t}scale(t,i){1===arguments.length&&(i=t),this.scaleP.x*=t,this.scaleP.y*=i}scaleTo(t,i){1===arguments.length&&(i=t),this.scaleP.x=t,this.scaleP.y=i}drawBuffer(){this.buffer.clear(),this.buffer.image(this.src,0,0,this.width,this.height,this.currentRotation*this.width,this.currentAnimation*this.height,this.width,this.height)}destroy(){this.drawBuffer.remove()}};class s{static defaultTypeTable={MAP_FLOOR:0,MAP_WALL:1,MAP_WALL_SHADOW:2,MAP_DOOR:3,MAP_DOOR_FRAME:4,MAP_PUSH_WALL:5,MAP_CIRCULAR_COLUMN:6,MAP_DIA_WALL_TR_BL:7,MAP_DIA_WALL_TL_BR:8,MAP_TRANSPARENT_WALL:9,DOOR_CLOSED:0,DOOR_OPENING:1,DOOR_OPEN:2,DOOR_CLOSING:3};static defaultSkyBox={sky:"black",ground:"grey",front:null,middle:null,back:null};constructor(t=24,i=24,e=null,o=null,h=s.defaultSkyBox,r=s.defaultTypeTable,a=null){this.width=t,this.height=i,this.map=new Array(this.width*this.height).fill(0),this.table=r,this.skyBox=h,this.sprites=[],this.cameras=[],this.textureMap=o,this.loadMap(e,a)}loadMap(t,i){if(t&&t.length)if("string"==typeof t)t.split(",").forEach(((t,i)=>{this.map[i]=parseInt(t),this.map[i]%10===this.table.MAP_WALL_SHADOW&&(console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[i]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[i]/10)+this.table.MAP_WALL}`),this.map[i]=Math.floor(this.map[i]/10)+this.table.MAP_WALL)}));else if("number"==typeof t[0])t.forEach(((t,i)=>{this.map[i]=t,this.map[i]%10===this.table.MAP_WALL_SHADOW&&(console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[i]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[i]/10)+this.table.MAP_WALL}`),this.map[i]=Math.floor(this.map[i]/10)+this.table.MAP_WALL)}));else if("number"==typeof t[0][0])for(let i=0;i<t.length;i++)for(let e=0;e<t[i].length;e++){let s=e+i*this.width;this.map[s]=t[i][e],this.map[s]%10===this.table.MAP_WALL_SHADOW&&(console.warn(`[p5RayCaster]: MAP_WALL_SHADOW ${this.map[s]} should not be used in the map, changed to MAP_WALL ${Math.floor(this.map[s]/10)+this.table.MAP_WALL}`),this.map[s]=Math.floor(this.map[s]/10)+this.table.MAP_WALL)}this.doorOffsets=new Array(this.width*this.height).fill(0),this.doorStates=new Array(this.width*this.height).fill(0),this.doorSpeed=i&&i.doorSpeed?i.doorSpeed:.1,this.doorAutoClose=!(!i||!i.doorAutoClose)&&i.doorAutoClose,this.doorClosingTime=i&&i.doorClosingTime?i.doorClosingTime:0}loadFloor(t){if("number"!=typeof t)if(this.floor=new Array(this.width*this.height),"string"!=typeof t){if(Array.isArray(t)&&t.length){if("number"==typeof t[0])return void t.forEach((t=>this.floor.push(t)));if("number"==typeof t[0][0])for(let i=0;i<t.length;i++)for(let e=0;e<t[0].length;e++){let s=e+i*this.width;this.floor[s]=t[i][e]}}}else t.split(",").forEach((t=>{this.floor.push(parseInt(t))}));else this.floor=t}loadCeiling(t){if("number"!=typeof t)if(this.ceiling=new Array(this.width*this.height),"string"!=typeof t){if(Array.isArray(t)&&t.length){if("number"==typeof t[0])return void t.forEach((t=>this.ceiling.push(t)));if("number"==typeof t[0][0])for(let i=0;i<t.length;i++)for(let e=0;e<t[0].length;e++){let s=e+i*this.width;this.ceiling[s]=t[i][e]}}}else t.split(",").forEach((t=>{this.ceiling.push(parseInt(t))}));else this.ceiling=t}loadTextureMap(t){this.textureMap=t}addSprite(t){this.sprites.push(t),t.world=this,this.cameras.forEach((t=>{t.updateSpritesBuffers()}))}removeSprite(t){if(t instanceof e){delete t.world;let i=this.sprites.indexOf(t);if(-1===i)return void console.warn("invalid remove: sprite is not in the world");t=i}delete this.sprites[t].world,this.sprites.splice(t,1),this.cameras.forEach((t=>{t.updateSpritesBuffers()}))}update(t=30){const i=1/t;for(let t=0;t<this.map.length;t++){const e=this.map[t];e===this.table.MAP_DOOR?this.doorStates[t]===this.table.DOOR_OPENING?(this.doorOffsets[t]+=i*this.doorSpeed,this.doorOffsets[t]>1&&(this.doorOffsets[t]=1,this.doorStates[t]=this.table.DOOR_OPEN,this.doorAutoClose&&setTimeout((t=>{this.doorStates[t]=this.table.DOOR_CLOSING}),this.doorClosingTime,t))):this.doorStates[t]===this.table.DOOR_CLOSING&&(this.doorOffsets[t]-=i*this.doorSpeed,this.doorOffsets[t]<0&&(this.doorOffsets[t]=0,this.doorStates[t]=this.table.DOOR_CLOSED)):e===this.table.MAP_PUSH_WALL&&this.doorStates[t]===this.table.DOOR_OPENING&&(this.doorOffsets[t]+=i*this.doorSpeed,this.doorOffsets[t]>1&&(this.doorOffsets[t]=1,this.doorStates[t]=this.table.DOOR_OPEN))}}openDoor(t,i){let e=1===arguments.length?t:t+i*this.width;this.map[e]!==this.table.MAP_DOOR&&this.map[e]!==this.table.MAP_PUSH_WALL||this.doorStates[e]===this.table.DOOR_CLOSED&&(this.doorStates[e]=this.table.DOOR_OPENING)}closeDoor(t,i){let e=1===arguments.length?t:t+i*this.width;this.map[e]===this.table.MAP_DOOR&&this.doorStates[e]===this.table.DOOR_OPEN&&(this.doorStates[e]=this.table.DOOR_CLOSING)}moveDoor(t,i){let e=1===arguments.length?t:t+i*this.width;this.map[e]===this.table.MAP_DOOR&&(this.doorStates[e]===this.table.DOOR_OPEN?this.doorStates[e]=this.table.DOOR_CLOSING:this.doorStates[e]===this.table.DOOR_CLOSED&&(this.doorStates[e]=this.table.DOOR_OPENING)),this.map[e]===this.table.MAP_PUSH_WALL&&this.doorStates[e]===this.table.DOOR_CLOSED&&(this.doorStates[e]=this.table.DOOR_OPENING)}}const o=s,h=class{constructor(t,i,e,s,o,h){this.mapX=i,this.mapY=e,this.camera=t,this.side=s,this.screenX=[o],this.tex=h}getRayDir(t,i,e){return e||(e=this.camera.cameraXCoords),1===i?this.camera.dir.y+this.camera.plane.y*e[t]:this.camera.dir.x+this.camera.plane.x*e[t]}getPerpDist(t){let i=1,e=this.getRayDir(t,this.side);return e<0&&(i=-1),1===this.side?(this.mapY-this.camera.pos.y+.5*i+(1-i)/2)/e:(this.mapX-this.camera.pos.x+.5*i+(1-i)/2)/e}display(t,i){const e=t._isMainCanvas?t._pInst:t,s=this.camera.world.textureMap.get(this.tex);e.push(),e.drawingContext.globalAlpha=.5;for(let o=this.screenX[0];o<this.screenX[0]+this.screenX.length;o++){let h,r=this.getPerpDist(o),a=Math.round(t.height/r),l=(.5+i)*t.height-a/2;if(0===this.side?h=this.camera.pos.y+r*this.getRayDir(o,1):1===this.side&&(h=this.camera.pos.x+r*this.getRayDir(o,0)),h-=Math.floor(h),"string"==typeof s)e.stroke(s),e.line(o,l,o,l+a);else{let t=Math.floor(h*s.width);e.image(s,o,l,1,a,t,0,1,s.height)}}e.pop()}},r=class{static lineIntersection(t,i,e,s,o=!1){let h=i.y-t.y,r=t.x-i.x,a=h*t.x+r*t.y,l=s.y-e.y,n=e.x-s.x,d=l*e.x+n*e.y,p=h*n-l*r;if(0===p)return null;let f=(n*a-r*d)/p,m=(h*d-l*a)/p;if(o){let e=(f-t.x)/(i.x-t.x),s=(m-t.y)/(i.y-t.y);return e>=0&&e<=1||s>=0&&s<=1?{x:f,y:m}:null}return{x:f,y:m}}static lineCircleIntersection(t,i,e,s,o=!1){let h,r,a,l,n={x:0,y:0};if(n.x=i.x-t.x,n.y=i.y-t.y,h=n.x*n.x+n.y*n.y,r=2*(n.x*(t.x-e.x)+n.y*(t.y-e.y)),a=e.x*e.x+e.y*e.y,a+=t.x*t.x+t.y*t.y,a-=2*(e.x*t.x+e.y*t.y),a-=s*s,l=r*r-4*h*a,l<0)return null;if(o)return{b:(-r-Math.sqrt(l))/(2*h)};let d=(-r+sqrt(l))/(2*h),p=(-r-sqrt(l))/(2*h);return[{x:t.x+d*(i.x-t.x),y:t.y+d*(i.y-t.y)},{x:t.x+p*(i.x-t.x),y:t.y+p*(i.y-t.y)}]}static rotateVector(t,i){return{x:t.x*Math.cos(i)-t.y*Math.sin(i),y:t.x*Math.sin(i)+t.y*Math.cos(i)}}static combineSort(t,i,e){let s=e,o=!1;for(;s>1||o;){s=Math.floor(10*s/13),9!=s&&10!=s||(s=11),s<1&&(s=1),o=!1;for(let h=0;h<e-s;h++){let e=h+s;i[h]<i[e]&&([i[h],i[e]]=[i[e],i[h]],[t[h],t[e]]=[t[e],t[h]],o=!0)}}}static normalize(t){let i=t.x*t.x+t.y*t.y;return 1===i?{x:t.x,y:t.y}:{x:t.x/Math.sqrt(i),y:t.y/Math.sqrt(i)}}};class a{static defaultMiniMapOptions={border:{stroke:"white",strokeWeight:3},background:{fill:"grey"},sprite:{fill:"purple",stroke:void 0,strokeWeight:0,dia:.5},camera:{fill:"yellow",stroke:void 0,strokeWeight:0,dia:.5},fov:{stroke:"black",strokeWeight:1},blocks:new Map([[0,{}],[1,{fill:"red"}],[3,{fill:"blue"}],[4,{fill:"blue"}],[5,{fill:"red",stroke:"blue",strokeWeight:1}],[6,{fill:"cyan"}],[7,{stroke:"red",strokeWeight:3}],[8,{stroke:"red",strokeWeight:3}],[9,{fill:"rgba(255,0,0,0.25)"}]]),MAP_FLOOR:{fill:void 0,stroke:void 0,strokeWeight:0},MAP_WALL:{fill:"red",stroke:void 0,strokeWeight:0},MAP_DOOR:{fill:"blue",stroke:void 0,strokeWeight:0},MAP_DOOR_FRAME:{fill:"black",stroke:"blue",strokeWeight:2},MAP_PUSH_WALL:{fill:"red",stroke:"blue",strokeWeight:1},MAP_CIRCULAR_COLUMN:{fill:"cyan",stroke:void 0,strokeWeight:0},MAP_DIA_WALL_TR_BL:{fill:void 0,stroke:"red",strokeWeight:3},MAP_DIA_WALL_TL_BR:{fill:void 0,stroke:"red",strokeWeight:3},MAP_TRANSPARENT_WALL:{fill:"rgba(255,0,0,0.25)",stroke:void 0,strokeWeight:0}};constructor(t,i,e,s=null,o=null){if(this.fov=e,this.pos={x:t.x,y:t.y},this.dir=r.normalize(i),this.tilting=0,this.tiltingRange=[-Math.PI/4,Math.PI/4],this.plane=r.rotateVector(this.dir,-Math.PI/2),this.plane.x=this.plane.x*e,this.plane.y=this.plane.y*e,this.attachToWorld(s),this.canvas=o,null!==this.canvas){this.cameraXCoords=[];for(let t=0;t<this.canvas.width;t++)this.cameraXCoords.push(2*t/this.canvas.width-1)}this.zBuffer=o?new Array(o.width):[],this.spritesOrderBuffer=[],this.spritesDistanceBuffer=[],this.spritesUpdateGap=4,null!==s&&this.updateSpritesBuffers(),this.miniMapOptions=a.defaultMiniMapOptions}attachToWorld(t){this.world=t,null!==t&&t.cameras.push(this)}removeFromWorld(){this.world.camera.splice(this.world.cameras.indexOf(this),1),this.world=null}updateSpritesBuffers(){if(null===this.world||this.world.sprites.length<1)return;const t=this.world.sprites;for(let i=0;i<t.length;i++)this.spritesOrderBuffer[i]=i,this.spritesDistanceBuffer[i]=(this.pos.x-t[i].pos.x)*(this.pos.x-t[i].pos.x)+(this.pos.y-t[i].pos.y)*(this.pos.y-t[i].pos.y);r.combineSort(this.spritesOrderBuffer,this.spritesDistanceBuffer,t.length)}setMiniMapRenderOptions(t){this.miniMapOptions=t}teleportTo(t,i,e=null){this.pos.x=t.x,this.pos.y=t.y,i&&(i=r.normalize(i),this.dir.x=i.x,this.dir.y=i.y,this.plane=r.rotateVector(this.dir,-Math.PI/2),this.plane.x=this.plane.x*this.fov,this.plane.y=this.plane.y*this.fov),e&&null!==e&&(this.removeFromWorld(),this.attachToWorld(e))}move(t){if(null===this.world)throw new Error("world should be set before manipulating camera");let i=Math.floor(this.pos.x+t.x)+Math.floor(this.pos.y)*this.world.width,e=Math.floor(this.pos.x)+Math.floor(this.pos.y+t.y)*this.world.width;this.world.map[i]!==this.world.table.MAP_FLOOR&&this.world.doorStates[i]!==this.world.table.DOOR_OPEN||Math.floor(this.pos.x+t.x)>-1&&Math.floor(this.pos.x+t.x)<this.world.width&&(this.pos.x+=t.x),this.world.map[e]!==this.world.table.MAP_FLOOR&&this.world.doorStates[e]!==this.world.table.DOOR_OPEN||Math.floor(this.pos.y+t.y)>-1&&Math.floor(this.pos.y+t.y)<this.world.height&&(this.pos.y+=t.y)}rotate(t){this.dir=r.rotateVector(this.dir,t),this.plane=r.rotateVector(this.plane,t)}tilt(t){this.tilting+=t,this.tilting>this.tiltingRange[1]&&(this.tilting=this.tiltingRange[1]),this.tilting<this.tiltingRange[0]&&(this.tilting=this.tiltingRange[0])}updateTiltingRange(t,i){this.tiltingRange[0]=t,this.tiltingRange[1]=i}openDoor(){let t=Math.floor(this.pos.x+this.dir.x),i=Math.floor(this.pos.y+this.dir.y),e=Math.floor(this.pos.x+2*this.dir.x),s=Math.floor(this.pos.y+2*this.dir.y),o=t+i*this.world.width,h=e+s*this.world.width;this.world.openDoor(o),this.world.openDoor(h);let r=Math.floor(this.pos.x)+Math.floor(this.pos.y)*this.world.width;this.world.map[r]===this.world.table.MAP_DOOR&&(this.world.doorStates[r]=this.world.table.DOOR_OPENING)}closeDoor(){let t=Math.floor(this.pos.x+this.dir.x),i=Math.floor(this.pos.y+this.dir.y),e=Math.floor(this.pos.x+2*this.dir.x),s=Math.floor(this.pos.y+2*this.dir.y),o=t+i*this.world.width,h=e+s*this.world.width;this.world.closeDoor(o),this.world.closeDoor(h);let r=Math.floor(this.pos.x)+Math.floor(this.pos.y)*this.world.width;this.world.map[r]===this.world.table.MAP_DOOR&&(this.world.doorStates[r]=this.world.table.DOOR_OPENING)}moveDoor(){let t=Math.floor(this.pos.x+this.dir.x),i=Math.floor(this.pos.y+this.dir.y),e=Math.floor(this.pos.x+2*this.dir.x),s=Math.floor(this.pos.y+2*this.dir.y),o=t+i*this.world.width,h=e+s*this.world.width;this.world.moveDoor(o),this.world.moveDoor(h);let r=Math.floor(this.pos.x)+Math.floor(this.pos.y)*this.world.width;this.world.map[r]===this.world.table.MAP_DOOR&&(this.world.doorStates[r]=this.world.table.DOOR_OPENING)}renderMiniMap(t,i,e,s,o,h=this.canvas){const r=h._isMainCanvas?h._pInst:h;let a=Math.floor(this.pos.x),l=Math.floor(this.pos.y),n={x:s/(2*t.x+1),y:o/(2*t.y+1)};r.push(),r.fill(this.miniMapOptions.background.fill),r.rect(i,e,s,o);for(let o=0;o<2*t.x+1;o++)for(let h=0;h<2*t.y+1;h++){let d=a-t.x+o,p=l-t.y+h;if(d<0||d>this.world.width-1||p<0||p>this.world.height-1)continue;let f=d+p*this.world.width,m=i+s-(o+1)*n.x,w=e+h*n.y;if(this.miniMapOptions.blocks.has(this.world.map[f])){let t=this.miniMapOptions.blocks.get(this.world.map[f]);if(t.icon)r.image(t.icon,m,w,n.x,n.y);else switch(t.fill?r.fill(t.fill):r.noFill(),t.stroke?(r.stroke(t.stroke),t.strokeWeight&&r.strokeWeight(t.strokeWeight)):r.noStroke(),this.world.map[f]%10){default:r.rect(m,w,n.x,n.y);break;case this.world.table.MAP_DIA_WALL_TR_BL:r.line(m,w,m+n.x,w+n.y);break;case this.world.table.MAP_DIA_WALL_TL_BR:r.line(m+n.x,w,m,w+n.y);break;case this.world.table.MAP_CIRCULAR_COLUMN:r.ellipse(m+n.x/2,w+n.y/2,n.x,n.y)}}else{let t;switch(this.world.map[f]%10){case this.world.table.MAP_FLOOR:t=this.miniMapOptions.MAP_FLOOR;break;case this.world.table.MAP_WALL:case this.world.table.MAP_WALL_SHADOW:t=this.miniMapOptions.MAP_WALL;break;case this.world.table.MAP_DOOR:t=this.miniMapOptions.MAP_DOOR;break;case this.world.table.MAP_DOOR_FRAME:t=this.miniMapOptions.MAP_DOOR_FRAME;break;case this.world.table.MAP_PUSH_WALL:t=this.miniMapOptions.MAP_PUSH_WALL;break;case this.world.table.MAP_CIRCULAR_COLUMN:t=this.miniMapOptions.MAP_CIRCULAR_COLUMN;break;case this.world.table.MAP_DIA_WALL_TR_BL:t=this.miniMapOptions.MAP_DIA_WALL_TR_BL;break;case this.world.table.MAP_DIA_WALL_TL_BR:t=this.miniMapOptions.MAP_DIA_WALL_TL_BR;break;case this.world.table.MAP_TRANSPARENT_WALL:t=this.miniMapOptions.MAP_TRANSPARENT_WALL}if(t.icon)r.image(t.icon,m,w,n.x,n.y);else switch(t.fill?r.fill(t.fill):r.noFill(),t.stroke?(r.stroke(t.stroke),t.strokeWeight&&r.strokeWeight(t.strokeWeight)):r.noStroke(),this.world.map[f]%10){default:r.rect(m,w,n.x,n.y);break;case this.world.table.MAP_DIA_WALL_TR_BL:r.line(m,w,m+n.x,w+n.y);break;case this.world.table.MAP_DIA_WALL_TL_BR:r.line(m+n.x,w,m,w+n.y);break;case this.world.table.MAP_CIRCULAR_COLUMN:r.ellipse(m+n.x/2,w+n.y/2,n.x,n.y)}}}let d=i+s-(this.pos.x-Math.floor(this.pos.x)+t.x)*n.x,p=e+(this.pos.y-Math.floor(this.pos.y)+t.y)*n.y;this.miniMapOptions.camera.fill?r.fill(this.miniMapOptions.camera.fill):r.noFill(),this.miniMapOptions.camera.stroke?(r.stroke(this.miniMapOptions.camera.stroke),this.miniMapOptions.camera.strokeWeight&&r.strokeWeight(this.miniMapOptions.camera.strokeWeight)):r.noStroke(),r.ellipse(d,p,this.miniMapOptions.camera.dia*n.x,this.miniMapOptions.camera.dia*n.y),this.miniMapOptions.fov.stroke&&(r.stroke(this.miniMapOptions.fov.stroke),this.miniMapOptions.fov.strokeWeight&&r.strokeWeight(this.miniMapOptions.fov.strokeWeight),r.line(d,p,d-(this.dir.x+this.plane.x)*n.x,p+(this.dir.y+this.plane.y)*n.y),r.line(d,p,d-(this.dir.x-this.plane.x)*n.x,p+(this.dir.y-this.plane.y)*n.y)),this.miniMapOptions.sprite.fill?r.fill(this.miniMapOptions.sprite.fill):r.noFill(),this.miniMapOptions.sprite.stroke?(r.stroke(this.miniMapOptions.sprite.stroke),this.miniMapOptions.sprite.strokeWeight&&r.strokeWeight(this.miniMapOptions.sprite.strokeWeight)):r.noStroke(),this.world.sprites.forEach((o=>{if(o.pos.x>a-t.x&&o.pos.x<a+t.x&&o.pos.y>l-t.y&&o.pos.y<l+t.y){let h=i+s-(o.pos.x-(a-t.x))*n.x,d=e+(o.pos.y-(l-t.y))*n.y;r.ellipse(h,d,this.miniMapOptions.sprite.dia*n.x,this.miniMapOptions.sprite.dia*n.y)}})),r.pop()}renderSkyBox(t=!0,i=!0,e=this.canvas){if(!t&&!i)return;const s=.5+Math.tan(this.tilting),o=1-s,h=e._isMainCanvas?e._pInst:e,r=this.world.skyBox;if(h.push(),t){if("string"==typeof r.sky)h.fill(r.sky),h.noStroke(),h.rect(0,0,h.width,h.height*s);else{let t=r.sky;h.image(t,0,0,h.width,h.height*s,0,t.height-h.height*s,h.width,h.height*s)}if(r.back||r.front||r.middle){let t=this.world.width/2-this.pos.x,i=this.world.height/2-this.pos.y,e={x:this.world.width/2*this.dir.x+t,y:this.world.height/2*this.dir.y+i},o={x:this.pos.x+e.x,y:this.pos.y+e.y},a=Math.sqrt((o.x-this.pos.x)*(o.x-this.pos.x)+(o.y-this.pos.y)*(o.y-this.pos.y)),l=a+a,n=(Math.atan2(this.dir.y,this.dir.x)+Math.PI)/Math.PI,d=Math.floor(n*h.width),p=Math.floor(d/1.5),f=Math.floor(d/2),m=h.height*s;if(r.back){let t=h.width/2,i=m/2;h.image(r.back,f,i,t,i,0,m-r.back.height,r.back.width,r.back.height),h.image(r.back,f-t,i,t,i,0,m-r.back.height,r.back.width,r.back.height),n>1&&h.image(r.back,f-h.width,i,t,i,0,m-r.back.height,r.back.width,r.back.height),n<1&&h.image(r.background,f+t,i,t,i,0,m-r.background.height,r.background.width,r.background.height)}if(r.middle){let t=h.width/1.5,i=m/1.5,e=m/3-this.world.width+a;h.image(r.middle,p-t,e,t,i,0,m-r.middle.height,r.middle.width,r.middle.height),n<1.5&&h.image(r.middle,p,e,t,i,0,m-r.middle.height,r.middle.width,r.middle.height),n<.5&&h.image(r.middle,p+t,e,t,i,0,m-r.middle.height,r.middle.width,r.middle.height),n>1&&h.image(r.middle,p-2*t,e,t,i,0,m-r.middle.height,r.middle.width,r.middle.height)}r.front&&(h.image(r.front,d-h.width,2*-this.world.width+l,h.width,m,0,m-r.front.height,r.front.width,r.front.height),n<1&&h.image(r.front,d,2*-this.world.width+l,h.width,m,0,m-r.front.height,r.front.width,r.front.height),n>1&&h.image(r.front,d-2*h.width,2*-this.world.width+l,h.width,m,0,m-r.front.height,r.front.width,r.front.height))}}if(i)if("string"==typeof r.ground)h.fill(r.ground),h.noStroke(),h.rect(0,h.height*s,h.width,h.height*o);else{let t=r.sky;h.image(t,0,h.height*s,h.width,h.height*o,0,t.height-h.height*o,h.width,h.height*o)}h.pop()}renderFloorAndCeiling(t=!0,i=!0,e=this.canvas){const s=e._isMainCanvas?e._pInst:e;s.pixels&&s.pixels.length>0||s.loadPixels();const o=Math.tan(this.tilting),h=s.pixelDensity();for(let e=0;e<s.height;e++){let r=e-(.5+o)*s.height;if(0===r)continue;if(!t&&r>0)return;if(!i&&r<0)continue;let a={x:this.dir.x-this.plane.x,y:this.dir.y-this.plane.y},l={x:this.dir.x+this.plane.x,y:this.dir.y+this.plane.y},n=.5*s.height/r,d=n*(l.x-a.x)/s.width,p=n*(l.y-a.y)/s.width,f=this.pos.x+n*a.x,m=this.pos.y+n*a.y;for(let t=0;t<s.width;t++){let i,o=Math.floor(f),a=Math.floor(m),l=o+a*this.world.width;i=r>0?"number"==typeof this.world.floor?this.world.floor:this.world.floor[l]:"number"==typeof this.world.ceiling?this.world.ceiling:this.world.ceiling[l];let n=this.world.textureMap.get(i),w=Math.floor((f-o)*n.width)&n.width-1,u=Math.floor((m-a)*n.height)&n.height-1;n.pixels&&n.pixels.length>0||n.loadPixels();let y=4*(w+u*n.width);for(let i=0;i<h;i++)for(let o=0;o<h;o++){let r=4*((e*h+o)*s.width*h+(t*h+i));s.pixels[r]=n.pixels[y],s.pixels[r+1]=n.pixels[y+1],s.pixels[r+2]=n.pixels[y+2],s.pixels[r+3]=n.pixels[y+3]}f+=d,m+=p}}s.updatePixels()}renderRayCasting(t=!1,i=this.canvas){const e=i._isMainCanvas?i._pInst:i,s=Math.tan(this.tilting);e.push();let o=[],a=[];if(i===this.canvas)o=this.cameraXCoords;else for(let t=0;t<i.width;t++)o.push(2*t/i.width-1);for(let t=0;t<i.width;t++){let u,y,c,M,g,x,O,A,b={x:this.dir.x+this.plane.x*o[t],y:this.dir.y+this.plane.y*o[t]},_=Math.floor(this.pos.x),k=Math.floor(this.pos.y),L=Math.abs(1/b.x),P=Math.abs(1/b.y),D=0,R={x:0,y:0};for(b.x<0?(M=-1,u=(this.pos.x-_)*L):(M=1,u=(_+1-this.pos.x)*L),b.y<0?(g=-1,y=(this.pos.y-k)*P):(g=1,y=(k+1-this.pos.y)*P);0===D&&(u<y?(u+=L,_+=M,x=0):(y+=P,k+=g,x=1),!(_<0||_>this.world.width||k<0||k>this.world.height));){let i=_+k*this.world.width;var l;if(O=this.world.map[i],O!==this.world.table.MAP_FLOOR)switch(O%10){case this.world.table.MAP_DOOR:this.world.doorStates[i]!==this.world.table.DOOR_OPEN&&(D=1,1==x?(R.y=.5*g,c=(k-this.pos.y+R.y+(1-g)/2)/b.y,l=this.pos.x+c*b.x,l-=Math.floor(l),y-P/2<u?1-l<=this.world.doorOffsets[i]&&(D=0,R.y=0):(_+=M,i=_+k*this.world.width,x=0,O=Math.floor(O/10)+this.world.table.MAP_DOOR_FRAME,R.y=0)):(R.x=.5*M,c=(_-this.pos.x+R.x+(1-M)/2)/b.x,l=this.pos.y+c*b.y,l-=Math.floor(l),u-L/2<y?1-l<this.world.doorStates[i]&&(D=0,R.x=0):(k+=g,x=1,O=Math.floor(O/10)+this.world.table.MAP_DOOR_FRAME,R.x=0)));break;case this.world.table.MAP_PUSH_WALL:this.world.doorStates[i]!==this.world.table.DOOR_OPEN&&(1==x&&y-P*(1-this.world.doorOffsets[i])<u?(D=1,R.y=this.world.doorOffsets[i]*g):0==x&&u-L*(1-this.world.doorOffsets[i])<y&&(D=1,R.x=this.world.doorOffsets[i]*M));break;case this.world.table.MAP_CIRCULAR_COLUMN:let e=r.lineCircleIntersection({x:this.pos.x,y:this.pos.y},{x:this.pos.x+b.x,y:this.pos.y+b.y},{x:_+.5,y:k+.5},.5,!0);if(e){D=1,x=3;let t={x:this.pos.x+b.x*e.b,y:this.pos.y+b.y*e.b};c=(t.x-this.pos.x+t.y-this.pos.y)/2/((b.x+b.y)/2),l=Math.atan2(k+.5-t.y,_+.5-t.x)/(2*Math.PI),l+=l}break;case this.world.table.MAP_DIA_WALL_TR_BL:var n=_,d=k+1,p=_+1,f=k,m=r.lineIntersection({x:this.pos.x,y:this.pos.y},{x:this.pos.x+b.x,y:this.pos.y+b.y},{x:n,y:d},{x:p,y:f},!1);m&&m.x>=_&&m.x<=_+1&&m.y>=k&&m.y<=k+1&&((1==x&&g<0||0==x&&M<0)&&(A=1),D=1,x=2,c=(m.x-this.pos.x+m.y-this.pos.y)/2/((b.x+b.y)/2));break;case this.world.table.MAP_DIA_WALL_TL_BR:n=_,d=k,p=_+1,f=k+1,(m=r.lineIntersection({x:this.pos.x,y:this.pos.y},{x:this.pos.x+b.x,y:this.pos.y+b.y},{x:n,y:d},{x:p,y:f},!1))&&m.x>=_&&m.x<=_+1&&m.y>=k&&m.y<=k+1&&((1==x&&g>0||0==x&&M<0)&&(A=1),D=1,x=2,c=(m.x-this.pos.x+m.y-this.pos.y)/2/((b.x+b.y)/2));break;case this.world.table.MAP_TRANSPARENT_WALL:if(1==x){if(y-P/2<u){let i=!1;for(let e=0;e<a.length;e++)if(a[e].mapX===_&&a[e].mapY===k){a[e].screenX.push(t),i=!0;break}i||a.push(new h(this,_,k,x,t,O))}}else if(u-L/2<y){let i=!1;for(let e=0;e<a.length;e++)if(a[e].mapX===_&&a[e].mapY===k){a[e].screenX.push(t),i=!0;break}i||a.push(new h(this,_,k,x,t,O))}break;case this.world.table.MAP_WALL_SHADOW:O=1===x&&this.world.map[_+(k-g)*this.world.width]===this.world.table.MAP_DOOR?Math.floor(this.world.map[_+(k-g)*this.world.width]/10)+this.world.table.MAP_DOOR_FRAME:0===x&&this.world.map[_-M+k*this.world.width]===this.world.table.MAP_DOOR?Math.floor(this.world.map[_-M+k*this.world.width]/10)+this.world.table.MAP_DOOR_FRAME:10*Math.floor(O/10)+this.world.table.MAP_WALL,D=1;break;default:1===x&&this.world.map[_+(k-g)*this.world.width]===this.world.table.MAP_DOOR?O=Math.floor(this.world.map[_+(k-g)*this.world.width]/10)+this.world.table.MAP_DOOR_FRAME:0===x&&this.world.map[_-M+k*this.world.width]===this.world.table.MAP_DOOR&&(O=Math.floor(this.world.map[_-M+k*this.world.width]/10)+this.world.table.MAP_DOOR_FRAME),D=1}}if(0===D);else{0===x?c=(_-this.pos.x+R.x+(1-M)/2)/b.x:1===x&&(c=(k-this.pos.y+R.y+(1-g)/2)/b.y);let o=Math.round(i.height/c),h=(.5+s)*i.height-o/2,r=h+o;0===x?l=this.pos.y+c*b.y:1!==x&&2!==x||(l=this.pos.x+c*b.x),l-=Math.floor(l),O%10===this.world.table.MAP_DOOR&&(l+=this.world.doorOffsets[_+k*this.world.width]);let a=this.world.textureMap.get(O);if("string"==typeof a)e.stroke(a),e.line(t,h,t,h+o);else{let i=Math.floor(l*a.width);(0===x&&b.x>0||1===x&&b.y<0)&&(i=a.width-i-1),e.image(a,t,h,1,o,i,0,1,a.height)}if(1===x&&O%10!==this.world.MAP_DOOR){let i=this.world.textureMap.get(10*Math.floor(O/10)+this.world.table.MAP_WALL_SHADOW);if(i)if("string"==typeof i)e.stroke(i),e.line(t,h,t,r);else{let s=Math.floor(l*i.width);b.y<0&&(s=i.width-s-1),e.image(i,t,h,1,o,s,0,1,i.height)}else e.stroke("rgba(0,0,0,0.5)"),e.line(t,h,t,r)}else if(2===x){let i=this.world.textureMap.get(10*Math.floor(O/10)+this.world.table.MAP_WALL_SHADOW);if(i){if(e.push(),w=0===A?.6*l:.6*(1-l),e.drawingContext.globalAlpha=w,"string"==typeof i)e.stroke(i),e.line(t,h,t,r);else{let s=Math.floor(l*i.width);e.image(i,t,h,1,o,s,0,1,i.height)}e.pop()}else{if(0===A)var w=.6*l;else w=.6*(1-l);e.stroke(`rgba(0,0,0,${w})`),e.line(t,h,t,r)}}this.zBuffer[t]=c}}let u=-1;if(a.length>0&&(u=a.length-1),!t){1!==e.frameCount&&e.frameCount%this.spritesUpdateGap!=0||this.updateSpritesBuffers();for(let t=0;t<this.world.sprites.length;t++){const o=this.world.sprites[this.spritesOrderBuffer[t]];let h=o.pos.x-this.pos.x,r=o.pos.y-this.pos.y,l=1/(this.plane.x*this.dir.y-this.dir.x*this.plane.y),n=l*(this.dir.y*h-this.dir.x*r),d=l*(this.plane.x*r-this.plane.y*h);if(d>0){for(;u>=0;u--){let e=(this.pos.x-a[u].mapX)*(this.pos.x-a[u].mapX)+(this.pos.y-a[u].mapY)*(this.pos.y-a[u].mapY);if(!(this.spritesDistanceBuffer[t]<e))break;a[u].display(i,s)}let l=Math.abs(Math.floor(i.height/d))*o.scaleP.y,p=(.5+s-o.yAdjustment)*i.height-l/2,f=Math.floor(i.width/2)*(1+n/d),m=Math.abs(Math.floor(i.height/d))*o.scaleP.x,w=Math.floor(f-m/2),y=w+m,c=w,M=y;w<-m&&(w=-m),y>i.width+m&&(y=i.width+m);for(let t=w;t<y;t++)if(d>this.zBuffer[t]){if(!(t-c<=1)){M=t;break}c=t}if(c!==M&&c<i.width&&M>0){let t=o.width/m,i=Math.floor((c-w)*t);i<0&&(i=0);let s=Math.floor((M-c)*t)+1;s>o.width&&(s=o.width);let a=M-c;a<0&&(a=0);let n=Math.atan2(r,h);o.updateRotationFrame(n),e.push(),e.drawingContext.imageSmoothingEnabled=!1,e.image(o.buffer,c,p,a,l,i,0,s,o.height),e.pop()}}}}for(;u>=0;u--)a[u].display(i,s);a.length=0,e.pop()}renderFrame(t=this.canvas){this.world.ceiling||this.world.floor?this.world.ceiling&&this.world.floor?this.renderFloorAndCeiling(t):this.world.ceiling?(this.renderFloorAndCeiling(!1,!0,t),this.renderSkyBox(!1,!0,t)):(this.renderFloorAndCeiling(!0,!1,t),this.renderSkyBox(!0,!1,t)):this.renderSkyBox(t),this.renderRayCasting(!1,t)}}const l=a;class n{static defaultKeyMap={forward:{keys:["w"]},backward:{keys:["s"]},goLeft:{keys:["a"]},goRight:{keys:["d"]},turnLeft:{keys:["q"]},turnRight:{keys:["e"]},tiltUp:{keys:["z"]},tiltDown:{keys:["x"]},moveDoor:{keys:[" "]}};constructor(t=n.defaultKeyMap){this.keyMap=t;for(const i in this.keyMap)Object.hasOwnProperty.call(this.keyMap,i)&&(t[i].initValue?this[i]=t[i].initValue:this[i]=!1);this.regControl()}regControl(){document.addEventListener("keydown",this.keyDown.bind(this)),document.addEventListener("keyup",this.keyUp.bind(this))}removeControl(){document.removeEventListener("keydown",this.keyDown.bind(this)),document.removeEventListener("keyup",this.keyUp.bind(this))}keyDown(t){t.preventDefault();for(const i in this.keyMap)if(Object.hasOwnProperty.call(this.keyMap,i)&&this.keyMap[i].keys.includes(t.key)){const t=this.keyMap[i].toggle,e=this.keyMap[i].initValue;t&&"down"===t?this[i]=!this[i]:t||(this[i]=void 0===e||!e)}}keyUp(t){for(const i in this.keyMap)if(Object.hasOwnProperty.call(this.keyMap,i)&&this.keyMap[i].keys.includes(t.key)){const t=this.keyMap[i].toggle,e=this.keyMap[i].initValue;t&&"up"===t?this[i]=!this[i]:t||(this[i]=void 0!==e&&e)}}loadKeyMap(t){this.keyMap=t}addItem(t,i,e=void 0,s=void 0){this.keyMap[t]={keys:i,toggle:e,initValue:s},this[t]=!1}removeItem(t){this.keyMap.hasOwnProperty(t)&&(delete this.keyMap[t],delete this.name)}}const d=n,p=class{constructor(t=null){this.mouseIsDown=!1,this.mouseX=0,this.mouseY=0,this.pmouseX=0,this.pmouseY=0,this.mouseButton=-1,this.mouseCX=0,this.mouseCY=0,this.pmouseCX=0,this.pmouseCY=0,this.regControl(t)}regControl(t){let i=t||document;this.targetElement=i,i.ownerDocument.addEventListener("mousedown",this.mouseDown.bind(this)),i.ownerDocument.addEventListener("mouseup",this.mouseUp.bind(this)),i.ownerDocument.addEventListener("mousemove",this.mouseMove.bind(this))}removeControl(){this.targetElement.ownerDocument.removeEventListener("mousedown",this.mouseDown.bind(this)),this.targetElement.ownerDocument.removeEventListener("mouseup",this.mouseUp.bind(this)),this.targetElement.ownerDocument.removeEventListener("mousemove",this.mouseMove.bind(this))}mouseDown(t){t.preventDefault(),this.mouseIsDown=!0,this.mouseButton=t.button}mouseMove(t){this.pmouseX=this.mouseX,this.pmouseY=this.mouseY,this.pmouseCX=this.mouseCX,this.pmouseCY=this.mouseCY,this.mouseX=t.offsetX,this.mouseY=t.offsetY,this.mouseCX=t.clientX,this.mouseCY=t.clientY}mouseUp(t){this.mouseIsDown=!1,this.mouseButton=-1}},f=class{constructor(t,i){this.camera=t,this.targetElement=i,this.pointerSpeed=.002,this.pointerLocked=!1,this.mouseIsDown=!1,this.mouseButton=-1,this.invertedX=!1,this.invertedY=!1,this.switchXY=!1,this.regControl()}regControl(){this.targetElement.ownerDocument.addEventListener("mousemove",this.mouseMove.bind(this)),this.targetElement.ownerDocument.addEventListener("pointerlockchange",this.pointerLockChange.bind(this)),this.targetElement.ownerDocument.addEventListener("pointerlockerror",this.pointerLockError.bind(this)),this.targetElement.ownerDocument.addEventListener("mouseup",this.mouseUp.bind(this)),this.targetElement.ownerDocument.addEventListener("mousedown",this.mouseDown.bind(this))}removeControl(){this.targetElement.ownerDocument.removeEventListener("mousemove",this.mouseMove.bind(this)),this.targetElement.ownerDocument.removeEventListener("pointerlockchange",this.pointerLockChange.bind(this)),this.targetElement.ownerDocument.removeEventListener("pointerlockerror",this.pointerLockError.bind(this)),this.targetElement.ownerDocument.removeEventListener("mouseup",this.mouseUp.bind(this)),this.targetElement.ownerDocument.removeEventListener("mousedown",this.mouseDown.bind(this))}lock(){this.targetElement.requestPointerLock()}unlock(){this.targetElement.ownerDocument.exitPointerLock()}setPointerSpeed(t){this.pointerSpeed=t}pointerLockChange(){this.targetElement.ownerDocument.pointerLockElement===this.targetElement?this.pointerLocked=!0:this.pointerLocked=!1}pointerLockError(){console.error("pointerLock unavailable")}mouseMove(t){if(!this.pointerLocked)return;const i=this.camera,e=t.movementX*(this.invertedX?1:-1),s=t.movementY*(this.invertedY?1:-1);i.rotate((this.switchXY?s:e)*this.pointerSpeed),i.tilt((this.switchXY?e:s)*this.pointerSpeed)}mouseDown(t){this.mouseIsDown=!0,this.mouseButton=t.button}mouseUp(t){this.mouseIsDown=!1}};function m(){let t=new Map;for(let i=0;i<arguments.length;i+=2){const e=arguments[i],s=arguments[i+1];t.set(e,s)}return t}function w(t,i,e=null,s=null,o=null){return{sky:t,ground:i,front:e,middle:s,back:o}}function u(t,i,e,s,h,r,a){return new o(t,i,e,s,h,r,a)}function y(t,i,s,o,h,r,a,l){return new e(t,i,s,o,h,r,a,l)}function c(t,i,e,s,o){return new l(t,i,e,s,o)}function M(t){return new d(t)}function g(t){return new p(t)}function x(t,i){return new f(t,i)}return i})()));