First take on squeezing IMPOSSIBLE ROAD into a JS1k entry
This project was kindly approved by Kevin NG
| // Use the textContent of the shim as noise function | |
| s=document.querySelector('script').textContent.replace(/[\s\n\t\r]/g,''); | |
| // Stretch the noise | |
| R=[]; | |
| for(i=0;i<519*16;i++)R[i]=(i/16>4?s.charCodeAt(i/16)%19-9:0)*16*2; | |
| // Smooth the noise | |
| a0=.9;a1=1-a0; | |
| for(j=16;j--;) | |
| for(i=0;i<519*16+16*3;i++) | |
| R[i] = a0*(R[i-1]||0)+a1*(R[i]||0); | |
| // Get deltas | |
| for(i=0;i<R.length;b[i&127]=0) | |
| R[i++] -= R[i%R.length]; | |
| onkeydown=onkeyup=function(e){b[e.keyCode]=!!e.type[5];} | |
| vvx=vvy=pos=x=y=px=py=vx=vy=dx=dy=0; | |
| function F(){ | |
| //a.style.width = Math.max(360*1.5,innerWidth>>1)+'px';a.style.height = Math.max(180*1.5,innerHeight>>1)+'px';a.style.backgroundColor="#fff";b.style.backgroundColor="#ccc"; | |
| a.width|=0; | |
| c.scale(a.width/720,a.height/360); | |
| vx=Math.min(2,Math.max(-2,vx-(b[39]-b[37])/16)) | |
| c.globalCompositeOperation='destination-over'; | |
| c.fillText(pos>>7,360,20); | |
| // c.fillText(Math.round(dx)+','+Math.round(dy),0,-60); | |
| // c.font='32px arial'; | |
| // lastFrame=16*9 | |
| // // The road | |
| // //X=x;Y=y; | |
| c.fillStyle='hsla(0,0%,0%,.5)' | |
| c.fillText([px,py].map(function(x){return (" "+Math.round(x)).slice(-4);})+" player",30,80); | |
| c.fillText([ x, y].map(function(x){return (" "+Math.round(x)).slice(-4);})+" road",30,100); | |
| c.fillText([dx,dy].map(function(x){return (" "+Math.round(x)).slice(-4);})+" delta / 2",30,120); | |
| c.fillText([vx,vy].map(function(x){return (" "+Math.round(x*100)).slice(-4);})+" velocity * 100",30,140); | |
| c.translate(360,380); | |
| vvx=vvx*a0+a1*(vx/2); | |
| vvy=vvy*a0+a1*(1+vy/2); | |
| for(i=0;i<999;i++){ | |
| posi=pos+i; | |
| u=R[posi%R.length]/2; | |
| posi+=16*3; | |
| v=R[posi%R.length]; | |
| posi-=16*3+8 | |
| l=96/(i+8); | |
| c.scale(l,l); | |
| c.rotate(Math.atan(v,u)/64); | |
| ll=100; | |
| c.fillStyle= 'hsl(210,90%,'+ll+'%)'; | |
| // The vessel | |
| if(i==8) { | |
| // if(pos<lastFrame){ | |
| x+=u; | |
| y+=v; | |
| // } | |
| //vx=0; | |
| vx*=.9; | |
| // title = v.toFixed(3)+' // '+vy.toFixed(3); | |
| vy = Math.max(vy-.1, -2);//Math.cos(pos*3.1415/32); | |
| // title += ' --> '+vy.toFixed(3); | |
| px+=vx; | |
| py+=vy; | |
| dx = (x-px)/2; | |
| var inside_x = dx*dx<26*26; | |
| dy = (y-py)/2; | |
| //var below_ish = /*dy<32 && */dy<0; | |
| if(/*inside_x && */dy>0){ | |
| // console.log([vy,py,y].map(function(x){ return x.toFixed(3); }).join('\n') +' Forcing the vessel back on track'); | |
| py=y; | |
| vy=-v; | |
| } | |
| dy = (y-py)/2; | |
| //ll=inside_x?100:70; | |
| c.arc(dx,dy-16,11,0,7);c.fill(); | |
| ll*=.9; | |
| c.fillStyle= 'hsl(210,90%,'+ll+'%)'; | |
| c.arc(dx-vx/2,dy-16+vy/2,12,0,7);c.fill(); | |
| } | |
| h=Math.min(9,Math.max(3,5+v)); | |
| if(i==0){ | |
| u-=dx; | |
| v-=dy; | |
| } | |
| c.translate(u+vvx,v-vvy); | |
| k = posi&4?3:7; | |
| k*=4; | |
| c.fillRect(k/2,-h/2,-k,h); | |
| k = 16; | |
| k*=4; | |
| h*=.9; | |
| //ll = i/13+(posi&127?24:48); | |
| u=posi&127; | |
| ll *= (u?.1:.2)+i/999; | |
| c.fillStyle= 'hsl(210,90%,'+ll+'%)'; | |
| if(u==0) | |
| c.fillText(posi>>7||'',k/2,-h/2); | |
| c.fillRect(k/2,-h/2,-k,h); | |
| c.scale(1/l,1/l); | |
| } | |
| // next frame | |
| // if(pos<lastFrame) | |
| pos++; | |
| requestAnimationFrame(F); | |
| } | |
| F(); |
| <!doctype html> | |
| <html> | |
| <head> | |
| <title>First prototype of IMPOSSIBLE ROAD for JS1k 2015 by Mathieu 'p01' Henri</title> | |
| <meta charset="utf-8" /> | |
| <meta name="author" content="Mathieu 'p01' Henri, @p01"/> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"/> | |
| <style> | |
| html, body { margin: 0; padding: 0; border: 0; } | |
| #c { display: block; } /* kill scrollbars from hell */ | |
| </style> | |
| </head> | |
| <body> | |
| <canvas id="c"></canvas> | |
| <script> | |
| var a = document.getElementsByTagName('canvas')[0]; | |
| var b = document.body; | |
| var d = function(e){ return function(){ e.parentNode.removeChild(e); }; }(a); | |
| // unprefix some popular vendor prefixed things (but stick to their original name) | |
| var AudioContext = | |
| window.AudioContext || | |
| window.webkitAudioContext; | |
| window.requestAnimationFrame || (window.requestAnimationFrame = | |
| window.requestAnimationFrame || | |
| window.mozRequestAnimationFrame || | |
| window.webkitRequestAnimationFrame || | |
| window.msRequestAnimationFrame || | |
| function(f){ setTimeout(f, 1000/30); }); | |
| (function() { | |
| var originalRAF = window.requestAnimationFrame; | |
| var time = performance.now(); | |
| var framesVBLs = new Array(64); | |
| var frameIndex = 0; | |
| var vblsSum = 0; | |
| window.requestAnimationFrame = function(f) { | |
| var now = performance.now(); | |
| var vbls = Math.max(1, Math.round((now - time) * 60 / 1000 - .5)); | |
| vblsSum += vbls - (framesVBLs[frameIndex]||0); | |
| framesVBLs[frameIndex] = vbls; | |
| frameIndex = ++frameIndex % framesVBLs.length; | |
| var averageFps = Math.round(60/vblsSum*framesVBLs.length); | |
| c.fillText(averageFps+'fps',16,16); | |
| time = now; | |
| originalRAF(f); | |
| }; | |
| })(); | |
| // fix bug in safari: http://qfox.nl/weblog/218 | |
| document.body.clientWidth; | |
| // auto resize (original) canvas. call `onresize(w,h) to limit the size of the canvas | |
| (window.onorientationchange = window.onresize = function(a){ | |
| var mw = Infinity; | |
| var mh = Infinity; | |
| var min = Math.min; | |
| return function(w,h){ | |
| if (arguments.length === 2) { | |
| mw = w; | |
| mh = h; | |
| } | |
| a.style.width = (a.width = min(mw, innerWidth)) + 'px'; | |
| a.style.height = (a.height = min(mh, innerHeight)) + 'px'; | |
| }; | |
| }(a))(); | |
| var c = a.getContext('2d'); | |
| </script> | |
| <script> | |
| // p01: "emulation" of having the source code in window._ as expected after compression | |
| _ = document.querySelector('script').textContent.replace(/\s/g, ''); | |
| while(_.length<1024)_+=_; | |
| </script> | |
| <script src="impossible_road.js"></script> | |
| </body> | |
| </html> |