My entry for the js1k competition. 1012 bytes of JavaScript. Arrow keys move, space fires.
As per the competition rules, this won't work in IE, except perhaps version 9 (untested). The game gradually speeds up, so there's a degree of difficulty in getting a high score.
Feedback: joeri (at) sebrechts.net
Version: 2.0 (link to v1.0 / changes: retro look, larger field, better bullet timing)
View source for minified source code. Documented source code:
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);
}
}