Side-scrolling fighter game. Arrow keys move, space fires. Second version now has more of a retro look (and fixes some bugs).
m=Math;k=m.abs;g=s=q=0;r=53;this.onkeydown=this.onkeyup=function(e){k[e.which]=(e.type=='keydown');if(k[32]&!q){f.push({x:p.x,y:p.y,s:4,d:-3,b:1})}};with(document.getElementById('c')){style.border='inset #999';width=w=350;height=h=150;c=getContext('2d');p={x:10,y:h/2,s:8};f=[];with(f){function d(p){c.beginPath();c.moveTo(p.x,p.y);x=p.x-p.s;v=p.b?1:5;c.lineTo(x,p.y+v);c.lineTo(x,p.y-v);c.fill()}setInterval(function(){l=length;p.x+=k[39]?2:0;p.x-=k[37]?2:0;p.y-=k[38]?2:0;p.y+=k[40]?2:0;g%=m.max(10,r-=0.02)|0;if(!g++)push({x:w,y:h*m.random(),s:-8,d:1});t=c.fillStyle=c.createLinearGradient(0,0,w,h);t.addColorStop(0,'#170');t.addColorStop(1,'#010');c.fillRect(0,0,w,h);c.fillStyle='#3F1';i=l;while(i--){x=(o=f[i]).x-=o.d;if(o.b&o.d<0){j=l;while(j--){z=f[j];if(z&&!z.b&&k(x-z.x-4)<4&&k(z.y-o.y)<4){if(i>j)i--;splice(j,1);splice(i,1);s++}}};if(!q&&o.d>0&&k(p.x-x-6)<4&&k(o.y-p.y)<5){q=1;splice(i,1)};if(!(o.b|x%h))push({x:x,y:o.y,s:-4,d:2,b:1});if(k(x)>w+9)splice(i,1);d(o)};if(!q)d(p);c.fillText(s,2,h-2)},40)}}
bT1NYXRoO2s9bS5hYnM7Zz1zPXE9MDtyPTUzO3RoaXMub25rZXlkb3duPXRoaXMub25rZXl1cD1mdW5jdGlvbihlKXtrW2Uud2hpY2hdPShlLnR5cGU9PSdrZXlkb3duJyk7aWYoa1szMl0mIXEpe2YucHVzaCh7eDpwLngseTpwLnksczo0LGQ6LTMsYjoxfSl9fTt3aXRoKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjJykpe3N0eWxlLmJvcmRlcj0naW5zZXQgIzk5OSc7d2lkdGg9dz0zNTA7aGVpZ2h0PWg9MTUwO2M9Z2V0Q29udGV4dCgnMmQnKTtwPXt4OjEwLHk6aC8yLHM6OH07Zj1bXTt3aXRoKGYpe2Z1bmN0aW9uIGQocCl7Yy5iZWdpblBhdGgoKTtjLm1vdmVUbyhwLngscC55KTt4PXAueC1wLnM7dj1wLmI/MTo1O2MubGluZVRvKHgscC55K3YpO2MubGluZVRvKHgscC55LXYpO2MuZmlsbCgpfXNldEludGVydmFsKGZ1bmN0aW9uKCl7bD1sZW5ndGg7cC54Kz1rWzM5XT8yOjA7cC54LT1rWzM3XT8yOjA7cC55LT1rWzM4XT8yOjA7cC55Kz1rWzQwXT8yOjA7ZyU9bS5tYXgoMTAsci09MC4wMil8MDtpZighZysrKXB1c2goe3g6dyx5OmgqbS5yYW5kb20oKSxzOi04LGQ6MX0pO3Q9Yy5maWxsU3R5bGU9Yy5jcmVhdGVMaW5lYXJHcmFkaWVudCgwLDAsdyxoKTt0LmFkZENvbG9yU3RvcCgwLCcjMTcwJyk7dC5hZGRDb2xvclN0b3AoMSwnIzAxMCcpO2MuZmlsbFJlY3QoMCwwLHcsaCk7Yy5maWxsU3R5bGU9JyMzRjEnO2k9bDt3aGlsZShpLS0pe3g9KG89ZltpXSkueC09by5kO2lmKG8uYiZvLmQ8MCl7aj1sO3doaWxlKGotLSl7ej1mW2pdO2lmKHomJiF6LmImJmsoeC16LngtNCk8NCYmayh6Lnktby55KTw0KXtpZihpPmopaS0tO3NwbGljZShqLDEpO3NwbGljZShpLDEpO3MrK319fTtpZighcSYmby5kPjAmJmsocC54LXgtNik8NCYmayhvLnktcC55KTw1KXtxPTE7c3BsaWNlKGksMSl9O2lmKCEoby5ifHglaCkpcHVzaCh7eDp4LHk6by55LHM6LTQsZDoyLGI6MX0pO2lmKGsoeCk+dys5KXNwbGljZShpLDEpO2Qobyl9O2lmKCFxKWQocCk7Yy5maWxsVGV4dChzLDIsaC0yKX0sNDApfX0=
m = Math;
// k = keyboard state object, reuse Math.abs to avoid an initializer
// so k() = Math.abs(), but k[keycode] = down state
k=m.abs;
// s = score
// q = quit, if 1 then game over
// g = rate counter to generate enemy fighters
g = s = q = 0;
r = 53; // generate a fighter every this many frames, 1 frame per 40 ms
// key state tracking
this.onkeydown = this.onkeyup = function(e) {
// which is shorter than keyCode
k[e.which] = (e.type == 'keydown');
if (k[32] & !q) {
// d: inverted x direction travelling speed
f.push({x: p.x, y: p.y, s: 4, d: -3, b: 1});
};
};
with(document.getElementById('c')) {
style.border = 'inset #999';
width = w = 350; height = h = 150;
c = getContext('2d');
// fighters
// s: delta x for drawing
p = {x: 10, y: h/2, s: 8}; // player 1
f = []; // enemy fighters and bullets, bullets have b: 1
with (f) {
// d = draw item
// p.s = scale factor for flipping rendering across the x axis
function d(p) {
c.beginPath();
c.moveTo(p.x, p.y);
x=p.x-p.s; v = p.b?1:5;
c.lineTo(x, p.y+v);
c.lineTo(x, p.y-v);
c.fill();
}
setInterval(function() {
l=length;
// update the position of the main fighter
p.x += k[39]?2:0; // right
p.x -= k[37]?2:0; // left
p.y -= k[38]?2:0; // up
p.y += k[40]?2:0; // down
// should we generate an enemy fighter and enemy bullets?
// value is inverted: g=0 -> generate fighter
g %= m.max(10, r-=0.02)|0; // slowly increase the rate of fighters
// generate enemy fighter
if (!g++) push({x: w, y: h*m.random(), s: -8, d: 1});
// draw everything
t = c.fillStyle = c.createLinearGradient(0,0,w,h);
t.addColorStop(0,'#170');
t.addColorStop(1,'#010');
c.fillRect(0,0,w,h);
c.fillStyle = '#3F1';
i=l;
while (i--) {
// animate enemy fighters and bullets
x = (o=f[i]).x -= o.d;
// if this is a player 1 bullet,
// do collision detection against enemy fighters
// o.d < 0: player 1 object
if (o.b & o.d<0) {
// for every enemy fighter
j=l;
while (j--) {
z=f[j];
// if collision, remove bullet and fighter and increase score
// !z.b = not a bullet
if (z && !z.b && k(x-z.x-4)<4 && k(z.y-o.y)<4) {
if (i>j) i--;
splice(j, 1);
splice(i, 1);
s++;
};
}; // end while (j--)
};
// do collision detection between player 1 and enemy objects
// o.d>0 : enemy object
if (!q && o.d>0 && k(p.x-x-6)<4 && k(o.y-p.y)<5) {
q=1;
splice(i, 1);
};
// if this is a fighter, and not a bullet,
// and it's time to fire bullets, then fire a bullet
// x%h -> fire bullets every h pixels
if (!(o.b | x%h)) push({x: x, y: o.y, s: -4, d: 2, b: 1});
// remove them if they go out of the screen
if (k(x) > w+9) splice(i, 1);
// draw all items
d(o);
}; // end while (i--)
if (!q) d(p);
c.fillText(s, 2, h-2);
}, 40);
}
}