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> |