 
          
        
        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);
  }
}