let my={} function init(){let version='0.52' my.wd=Math.max(600,window.innerWidth-30) my.ht=Math.max(500,window.innerHeight-50) console.log('my.wd,my.ht',my.wd,my.ht) my.theme=localStorage.getItem('theme') my.fadeClr=my.theme=='dark'?'rgba(0,0,0,0.02)':'rgba(225,235,255,0.02)' my.playQ=true my.frame=0 my.car=new Car() my.imgs=[{file:'BMW-Z4.svg',lt:25,tp:38,wd:160},{file:'glibersat.svg',lt:28,tp:36,wd:160},] my.img=my.imgs[0] my.zone={wd:200,ht:100} let s='' s+=`
` s+='' my.imgHome=document.domain=='localhost'?'/mathsisfun/games/images/':'/games/images/' s+='' s+='' s+=wrap({cls:'copyrt',pos:'abs',style:'left:5px; bottom:3px'},`© 2022 Rod Pierce v${version}`) s+='
' s=wrap({id:'',tag:'div',pos:'abs',style:'left:0px; height:'+my.ht+'px;'},s) s+=wrap({id:'',tag:'div',style:'height:'+my.ht+'px;'}) docInsert(s) my.canTrack=new Can('canTrack',my.wd,my.ht,2) my.canBd=new Can('canBd',my.wd,my.ht,2) my.rotLtQ=false my.rotRtQ=false my.speedUpQ=false my.speedDnQ=false my.brakeQ=false document.onkeydown=function(e){e.preventDefault() switch(e.keyCode){case 37:my.rotLtQ=true break case 39:my.rotRtQ=true break case 38:my.speedUpQ=true break case 40:my.speedDnQ=true break case 32:my.brakeQ=true break case 78:polyNext() break default:console.log('',e.keyCode)}} document.onkeyup=function(e){switch(e.keyCode){case 37:my.rotLtQ=false break case 39:my.rotRtQ=false break case 38:my.speedUpQ=false break case 40:my.speedDnQ=false break case 32:my.brakeQ=false}} window.addEventListener('mousedown',function(ev){console.log('['+ev.clientX+','+ev.clientY+']')},false) my.polys=[[[287,60],[451,60],[451,147],[287,147],],[[36,140],[217,139],[220,252],[107,224],[38,239],],[[472,10],[580,10],[580,273],[472,273],],[[127,292],[278,327],[181,472],[115,453],],[[441,32],[299,177],[529,202],],[[100,200],[100,340],[200,340],[200,200],],[[12,11],[160,11],[160,105],[12,105],],[[430,200],[340,323],[195,276],[195,124],[340,76],],[[213,251],[288,187],[405,311],[333,374],],[[346,397],[455,290],[526,349],[522,458],],] my.poly=new Poly() my.polyN=-1 polyNext() go() anim()} function go(){my.car.move() my.car.draw() my.frameN=0} function anim(){this.frame++ my.car.update() my.car.move() my.car.draw() my.car.wheelsDraw() if(my.playQ&&my.frameN++<500000)requestAnimationFrame(anim)} class Car{constructor(){this.len=100 this.wd=30 this.vel={ang:0,mag:0,x:0,y:0,dAng:0,dMag:0} this.rear={x:100,y:100} this.head={x:this.rear.x+this.len,y:100,ang:0.2} this.carAng=0 this.wheels=[{dy:-this.wd,rearQ:true},{dy:this.wd,rearQ:true},{dy:-this.wd,rearQ:false},{dy:this.wd,rearQ:false},] this.prev={lt:0,tp:0,ang:0}} update(){if(my.rotLtQ)this.vel.ang-=0.018 if(my.rotRtQ)this.vel.ang+=0.018 this.vel.ang=Math.max(-0.8,Math.min(this.vel.ang,0.8)) if(my.speedUpQ)this.vel.mag+=0.05 if(my.speedDnQ)this.vel.mag-=0.05 this.vel.mag=Math.max(-1,Math.min(this.vel.mag,3)) if(my.brakeQ){this.vel.mag*=0.95 if(Math.abs(this.vel.mag)<0.3)this.vel.mag=0}} move(){let totAng=this.vel.ang+this.carAng this.vel.x=this.vel.mag*Math.cos(totAng) this.vel.y=this.vel.mag*Math.sin(totAng) this.head.x+=this.vel.x this.head.y+=this.vel.y this.carAng=Math.atan2(this.head.y-this.rear.y,this.head.x-this.rear.x) let xy=polarToCart(this.len,this.carAng) this.rear.x=this.head.x-xy.x this.rear.y=this.head.y-xy.y let div=document.getElementById('car') let lt=fmt(this.rear.x-my.img.lt,5) let tp=fmt(this.rear.y-my.img.tp,5) let rot=fmt(this.carAng,5) if(this.prev.lt!=lt||this.prev.tp!=tp||this.prev.rot!=rot){if(my.frame++>20){my.frame=0 let g=my.canTrack.g g.fillStyle=my.fadeClr g.fillRect(0,0,g.canvas.width,g.canvas.height) g.strokeStyle='black' g.fillStyle='#ffe' g.beginPath() my.poly.drawLines(g) g.fill() g.stroke()} div.style.left=lt+'px' this.prev.lt=lt div.style.top=tp+'px' this.prev.tp=tp div.style.transform='rotate('+rot+'rad)' this.prev.rot=rot let inQ=true for(let i=0;imy.wd)inCanQ=false if(mid.y>my.ht)inCanQ=false if(!inCanQ){this.vel.mag=0} let g=my.canTrack.g if(inQ){polyDone()}else{g.strokeStyle='black' g.beginPath() my.poly.drawLines(g) g.stroke()}}} draw(){let g=my.canBd.g g.clearRect(0,0,g.canvas.width,g.canvas.height)} wheelsDraw(){this.carAng=Math.atan2(this.head.y-this.rear.y,this.head.x-this.rear.x) this.wheels.map((wheel)=>{let x=wheel.rearQ?this.rear.x:this.head.x let y=wheel.rearQ?this.rear.y:this.head.y let ang=wheel.rearQ?this.carAng:this.carAng let xy=polarToCart(wheel.dy,ang+Math.PI/2) wheel.x=x+xy.x wheel.y=y+xy.y let wheelWd=22 let wheelHt=10 let pts=[new Pt(-wheelWd/2,-wheelHt/2),new Pt(+wheelWd/2,-wheelHt/2),new Pt(+wheelWd/2,+wheelHt/2),new Pt(-wheelWd/2,+wheelHt/2)] let rot=wheel.rearQ?this.carAng:this.carAng+this.vel.ang let rotPts=ptsRotate(pts,x+xy.x,y+xy.y,-rot) let g=my.canBd.g g.strokeStyle='black' g.fillStyle='white' g.beginPath() ptsDraw(g,rotPts,true) g.fill() g.stroke() g=my.canTrack.g g.strokeStyle='green' g.fillStyle='yellow' g.beginPath() ptsDraw(g,rotPts,true) g.fill() g.stroke()})}} function polyDone(){console.log('polyDone') let g=my.canTrack.g g.strokeStyle='black' g.fillStyle='blue' g.beginPath() my.poly.drawLines(g) g.fill() g.stroke() polyNext()} function polyNext(){my.polyN++ if(my.polyN>=my.polys.length)my.polyN=0 my.poly.ptsSet(my.polys[my.polyN]) console.log('polyNew: ',my.poly.toString()) console.log('my.poly',my.poly) if(my.polyN>0){let extents=my.poly.extents() console.log('extents',extents) let wiggleWd=Math.random()*(my.wd-extents.xSpan)-extents.xStt console.log('wiggleWd',wiggleWd) let wiggleHt=Math.random()*(my.ht-extents.ySpan)-extents.yStt console.log('wiggleHt',wiggleHt) my.poly.trans(wiggleWd,wiggleHt) console.log('my.poly',my.poly)} my.poly.pts2pxs() let g=my.canTrack.g g.strokeStyle='black' g.fillStyle='#ffe' g.beginPath() my.poly.drawLines(g) g.fill() g.stroke()} function ptsRotate(pts,midX,midY,rot){var newPts=[] for(var i=0;iy!=yj>y&&x<((xj-xi)*(y-yi))/(yj-yi)+xi if(intersect)inside=!inside} return inside} trans(dx,dy){for(let i=0;i180)return true} return false} drawAngles(g){let angSum=0 let angDescr='' let angs=[] for(let i=0;i90){g.strokeStyle='#ff0000' d=Math.max(20,30-(angDeg-90)/6)}else{g.strokeStyle='#4444FF'} g.fillStyle='rgba(0, 0, 255, 0.3)' g.beginPath() g.moveTo(pt.x,pt.y) g.arc(pt.x,pt.y,d,pt.angleIn,pt.angleOut,false) g.closePath() g.fill()} let ang=this.userAngle(pt.getAngle()) if(i0?' onclick="'+fn+'" ':''),cls:'btn',fin:'>'+txt+''},can:{stt:''},div:{stt:'
0?' onclick="'+fn+'" ':''),cls:'',fin:' >'+txt+'
'},edit:{stt:''},inp:{stt:'0?' oninput="'+fn+'" onchange="'+fn+'"':''),cls:'input',fin:'>'+(lbl.length>0?'':'')},out:{stt:''+txt+''+(lbl.length>0?'':'')},radio:{stt:'
\n'},sel:{stt:'0?'':'0')},} let type=tags[tag] if(lbl.length>0)s+='
'} s+=''} if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'} s+='' if(lbl.length>0)s+=''} s+='\n' return s.trim()} init()