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:'
'}
s+=''}
if(tag=='sel'){for(let i=0;i'+opt.descr+'\n'}
s+=''
if(lbl.length>0)s+=''}
s+='\n'
return s.trim()}
init()