var w,h,el,g,my={};var CIRCLE=Math.PI*2;var MOBILE=/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent) function maze3dMain(mode){my.version='0.61';my.typ=typeof mode!=='undefined'?mode:'bla';w=Math.min(700,window.innerWidth-15) h=w*0.8 var s='';s+='
';s+='
';s+='';s+='';s+='
';s+='';s+=popHTML() s+='
© 2019 MathsIsFun.com v'+my.version+'
';s+='
';document.write(s);el=document.getElementById('canvas1');var ratio=3;el.width=w*ratio;el.height=h*ratio;el.style.width=w+"px";el.style.height=h+"px";g=el.getContext("2d");g.setTransform(ratio,0,0,ratio,0,0);my.clrs=[["Blue",'#0000FF'],["Red",'#FF0000'],["Black",'#000000'],["Green",'#00cc00'],["Orange",'#FFA500'],["Slate Blue",'#6A5ACD'],["Lime",'#00FF00'],["Spring Green",'#00FF7F'],["Teal",'#008080'],["Gold",'#ffd700'],["Med Purple",'#aa00aa'],["Light Blue",'#ADD8E6'],["Navy",'#000080'],["Purple",'#800080'],["Dark SeaGreen",'#8FBC8F'],["White",'#ffffff'],["Yellow",'#ffff00'],["Light Yellow",'#ffffdd']];console.log("my.typ",my.typ);my.cellMax=25 my.mapsz=(w-20)/my.cellMax my.sttTime=performance.now() my.game={nx:6,ny:4,cellWd:10,moreHoles:15,wallType:'multi'} start() my.playQ=true anim()} function start(){my.game.nx=document.getElementById('nx').value<<0 my.game.nx=Math.max(2,Math.min(my.game.nx,my.cellMax)) my.game.ny=document.getElementById('ny').value<<0 my.game.ny=Math.max(2,Math.min(my.game.ny,my.cellMax)) my.game.moreHoles=Math.round(my.game.nx*my.game.ny/10) console.log('my.game',my.game) my.player=new Player(0.5,0.5,Math.PI*0.1);my.map=new Map() my.controls=new Controls();my.camera=new Camera(el,MOBILE?160:320,0.8);my.successq=false my.walkq=false my.map.generate();my.mapq=true my.camera.render(my.player,my.map);} function success(){var s='' var elapsed=Math.round(performance.now()-my.sttTime)/1000 s+='Freedom!
It took you '+elapsed+' seconds to navigate this '+my.game.nx+' by '+my.game.ny+' maze.' var speed=my.game.nx*my.game.ny/elapsed if(speed>3)s+=' Well Done!' document.getElementById('info').innerHTML=s my.mapq=true popShow()} function anim(){if(my.playQ){var mapElapsed=performance.now()-my.mapLast if(mapElapsed>2500&&!my.mapq){my.mapq=true my.camera.drawMap(my.map,my.player)} var seconds=0.02 var chgq=my.player.update(my.controls.states,my.map,seconds);if(chgq){my.camera.render(my.player,my.map);} requestAnimationFrame(anim);}} function update(){my.camera.render(my.player,my.map);} function Controls(){this.codes={37:'left',39:'right',38:'forward',40:'backward'};this.states={'left':false,'right':false,'forward':false,'backward':false};document.addEventListener('keydown',this.onKey.bind(this,true),false);document.addEventListener('keyup',this.onKey.bind(this,false),false);document.addEventListener('touchstart',this.onTouch.bind(this),false);document.addEventListener('touchmove',this.onTouch.bind(this),false);document.addEventListener('touchend',this.onTouchEnd.bind(this),false);} Controls.prototype.onTouch=function(e){var t=e.touches[0];this.onTouchEnd(e);if(t.pageYw*0.5)this.onKey(true,{keyCode:39});};Controls.prototype.onTouchEnd=function(e){this.states={'left':false,'right':false,'forward':false,'backward':false};e.preventDefault();e.stopPropagation();};Controls.prototype.onKey=function(val,e){var state=this.codes[e.keyCode];if(typeof state==='undefined')return;this.states[state]=val;e.preventDefault&&e.preventDefault();e.stopPropagation&&e.stopPropagation();};function Img(src,width,height){this.image=new Image();this.image.src=src;this.width=width;this.height=height;this.image.addEventListener('load',function(){console.log('Img') update()},false);} function Player(x,y,direction){this.x=x;this.y=y;this.direction=direction;this.weapon=new Img('../images/arrow.gif',32,32);this.paces=0;} Player.prototype.rotate=function(angle){this.direction=(this.direction+angle+CIRCLE)%(CIRCLE);};Player.prototype.walk=function(distance,map){my.mapLast=performance.now() if(!my.walkq){my.walkq=true my.sttTime=performance.now() console.log('started walking')} var dx=Math.cos(this.direction)*distance;var dy=Math.sin(this.direction)*distance;var xf=Math.floor(this.x);var yf=Math.floor(this.y);if(xf<0||xf>my.game.nx-1||yf<0||yf>my.game.ny-1){this.x+=dx this.y+=dy this.paces+=distance;}else{var cell=map.wallGrid[yf*my.game.nx+xf] var xfnew=Math.floor(this.x+dx);if(xfnew>xf&&!cell[4])this.x+=dx if(xfnew==xf)this.x+=dx if(xfnewyf&&!cell[2])this.y+=dy if(yfnew==yf)this.y+=dy if(yfnewmy.game.nx-1||yf<0||yf>my.game.ny-1)return false var dx=x-wasx var dy=y-wasy var horizq=Math.abs(dx)>Math.abs(dy) var walln if(horizq){if(dx>0){walln=3}else{walln=4}}else{if(dy>0){walln=1}else{walln=2}} var n=this.wallGrid[yf*my.game.nx+xf][walln] return(n>0);};Map.prototype.generate=function(){this.genWalls()};Map.prototype.genWalls=function(){var maze=[];var moves=[];var pts=getRandomPts(my.game.nx,my.game.ny,4);var numberOfCells=my.game.nx*my.game.ny console.log('numberOfCells',numberOfCells) for(var i=0;i=0)&&(maze[pos-my.game.nx][0]==0)){possible+="N";} if(possible){visited++;moves.push(pos);var way=possible.charAt(Math.round(Math.random()*(possible.length-1)));switch(way){case "N":maze[pos][1]=0;maze[pos-my.game.nx][2]=0;pos-=my.game.nx;break;case "S":maze[pos][2]=0;maze[pos+my.game.nx][1]=0;pos+=my.game.nx;break;case "E":maze[pos][4]=0;maze[pos+1][3]=0;pos++;break;case "W":maze[pos][3]=0;maze[pos-1][4]=0;pos--;break;} maze[pos][0]=1;}else{pos=moves.pop();}} var moreHoles=0;while(moreHoles=0) maze[pos-my.game.nx][2]=0;break;case 2:maze[pos][2]=0;if(pos+my.game.nx=0) maze[pos-1][4]=0;break;case 4:maze[pos][4]=0;if(pos+1range)return[origin];if(nextStep.x<0||nextStep.x>my.game.nx||nextStep.y<0||nextStep.y>my.game.ny)inq=false if(!inq&&wasInq)return[origin] wasInq=inq return[origin].concat(ray(nextStep));} function step(rise,run,x,y,inverted){if(run===0)return noWall;var dx=run>0?Math.floor(x+1)-x:Math.ceil(x-1)-x;var dy=dx*(rise/run);return{x:inverted?y+dy:x+dx,y:inverted?x+dx:y+dy,length2:dx*dx+dy*dy,};} function inspect(step,shiftX,shiftY,distance,offset){step.distance=distance+Math.sqrt(step.length2);if(shiftX)step.shading=cos<0?2:0;else step.shading=sin<0?2:1;step.offset=offset-Math.floor(offset);step.xf=Math.floor(step.x) step.yf=Math.floor(step.y) if(step.xf<0||step.xf>my.game.nx||step.yf<0||step.yf>my.game.ny){step.wallq=false}else{var wallNS=1 var wallWE=3 var n=step.yf*my.game.nx+step.xf var outsideq=false if(step.xf==my.game.nx){n-=1 wallWE=4 outsideq=true} if(step.yf==my.game.ny){n-=my.game.nx wallNS=2 outsideq=true} if(outsideq){var cell=self.wallGrid[n] if(step.xf==my.game.nx&&step.yf0){this.ctx.fillStyle='#ffffff';this.ctx.globalAlpha=ambient*0.1;this.ctx.fillRect(0,this.height*0.5,this.width,this.height*0.5);} this.ctx.restore();};Camera.prototype.drawColumns=function(player,map){this.ctx.save();for(var column=0;column=0;s--){var step=ray[s];if(s===hit){var textureX=Math.floor(texture.width*step.offset);var wall=this.project(step.height,angle,step.distance);ctx.globalAlpha=1;switch(my.game.wallType){case 'texture':ctx.drawImage(texture.image,textureX,0,1,texture.height,left,wall.top,width,wall.height);ctx.fillStyle='#888888';ctx.globalAlpha=Math.max((step.distance+step.shading)/this.lightRange-map.light,0);ctx.fillRect(left,wall.top,width,wall.height);break case 'multi':ctx.beginPath() var xf=Math.floor(step.x);var yf=Math.floor(step.y);var cell=map.wallGrid[yf*my.game.nx+xf] if(cell==undefined){ctx.fillStyle='hsla(240,100%,60%,1)';}else{ctx.fillStyle=cell[6];} ctx.fillRect(left,wall.top,width,wall.height);ctx.fillStyle='hsla(60,10%,100%,0.6)';ctx.globalAlpha=Math.max((step.distance+step.shading)/this.lightRange-map.light,0);ctx.fillRect(left,wall.top,width,wall.height);break default:}}}};Camera.prototype.project=function(height,angle,distance){var z=distance*Math.cos(angle);var wallHeight=this.height*height/z;var bottom=this.height/2*(1+1/z);return{top:bottom-wallHeight,height:wallHeight};};function GameLoop(){this.frame=this.frame.bind(this);this.lastTime=0;this.callback=function(){};} GameLoop.prototype.start=function(callback){this.callback=callback;requestAnimationFrame(this.frame);};GameLoop.prototype.frame=function(time){var seconds=(time-this.lastTime)/1000;this.lastTime=time;if(seconds<0.2)this.callback(seconds);requestAnimationFrame(this.frame);};function randomInt(min,max){return Math.floor(Math.random()*(max-min+1))+min;} function drawEdge(x0,y0,x1,y1,clr){g.strokeStyle=clr g.lineWidth=2 g.beginPath() g.moveTo(x0,y0);g.lineTo(x1,y1);g.stroke()} function getRandomPts(width,height,ptCount){var pts=[];for(var i=0;i'+fld.title+':';s+='';} s+='';s+='
';s+='';s+='
';s+='';return s;} function chg(n){var div=document.getElementById(my.flds[n].id) var val=Number(div.value)<<0 val=my.base=Math.max(0,Math.min(val,my.cellMax)) if(val!=div.value){console.log('chg chg') div.value=val} console.log('chg',my.flds[n].id,div.value)} function radioHTML(prompt,id,lbls,func,n){var s='';s+='
';s+=prompt;for(var i=0;i';s+='';s+='
'} s+='
';return s;}