Meteors game in less than 1K of Javascript

Since the JS1K contest started in 2010 (where I got second place with my 1K Javascript chess game) I've seen various entries trying to be similar to a meteors game. I was pretty curious about the subject, really was it so complicated to do something looking nice and complete? a nice challenge to try in my free time :)
Click the game to start playing (use arrows and space bar)
I started writing it in February 23, 2012 thinking in JS1K 2012 Love contest, most of the game was coded in one week, including all basic features: player ship, meteors, sparks, enemy ships with AI and multiple levels
It wasn't so easy as I thought, in fact I needed more bytes to crunch in everything as I improved it, so I resorted to using @aivopass JS-Crunch, this gave me more space for the design, ironically for a game in space :).
I missed the JS1K 2012 Love contest because I was not happy with the result, I redesigned various things for the JS1K 2012 Autumn contest and I forgot to send it!
So one week after the start of JS1K 2013 Spring contest I managed to fit in a score indicator and I sent the entry. It was published as number 1312. Check the original version.
As the contest developed I noted that the player's ship didn't have inertia while rotating, so I managed to fit a few bytes more for it and I resent it: improved with inertia.
Still I wasn't happy, because I wanted to add a radioactive halo feature around graphics that was present before I added score indicator. Fortunately I found ClaudioCC's Javascript compression tips.
With all the bytes saved I was able to put back in the shadow and also some small enhancements, all this found in the final version.
Unfortunately my game didn't made it to the final top 10 published in May 5, 2013.

Features and usage

Pilot your ship through space and remove meteors from field. Rotate with left and right arrows, advance with up arrow, shoot with spacebar.
Caveat with aliens lurking.
If you want to change the initial configuration then just refresh the page.

Source code

Note that the JS1K "provides" some variables loaded with important data, similar to this:
<canvas id="c">
</canvas><script>
var c=document.getElementById("c");
var a=c.getContext("2d");
</script>
<script src="meteors.js">
</script>
Here is my original commented source code.
p=[],
//
// Javascript 1K meteors (after compression)
// (c) 2012-2013 by Oscar Toledo G. (@nanochess)
// http://www.nanochess.org/
//
// Creation date: Feb/23/2012.
// Last revision: Mar/29/2013.
//
// In this source code some expressions are repeated to get more compression
// from @aivopaas JS compressor. http://js1k.com/demo/1127
// and later http://www.iteral.com/jscrush/
//
// Visual objects array (in first line to evade original compressor bug)
// Keyboard array
q=[],
// <canvas> width/height, save also for further use
c.width=d=444,
c.height=h=252,
// window.onkeydown/onkeyup, annotate key pressed/depressed
onkeydown=function(w){
  q[w.which]=.1};
// Don't remove semicolon at end of both functions or fails after compression
onkeyup=function(w){
  q[w.which]=0};
// Compression of <canvas> function names
for(Z in a)a[Z[0]+(Z[6]||Z[2])]=a[Z];
// Add new object to visual list
function o(x,y,r,a,c,s,o,t){
p[p.length]={
// X,Y coordinates
  x:x,y:y,
// Rotation (in radians) for displaying
  r:r,
// Rotation (in radians) for displacement
  w:r,
// Scale
  u:c,
// Score (ship) or who shot this bullet (3=ship, 0=enemy)
  s:t,
// Type of object
// 0 - Player's ship
// 1 - Enemy's ship
// 2 - Meteor
// 3 - Spark
// 4 - Bullet
  t:s,
// Speed
  v:a,
// Duration
  z:o}
}
// Call continously main loop
setInterval(
// Function containing main loop
function(){
// Keep canvas context in scope
with(a)
  with(
// Wide lines for all objects
    lineWidth=2,
// Cleans canvas
    fc(0,0,d,h),
// If list is empty or player's ship was removed then restart screen
    p.length&&!p[0].t||
// Center player's ship, put it pointing upwards
      o(d/2,h/2,p.length=0,0,1,0,1,0),
// Add Math object to scope
    Math)
// Cycles through visual list in reverse to not have problems with deletion
    for(e=p.length;e--;)
// Include visual object in scope (now three objects in scope!)
      with(p[e]){
// Save context before drawing object
        sv();
// Wide shadow
        shadowBlur=9,
// Color for score, note it reuses string
        fillStyle=
// Shadow properties, radioactive green :P makes it to look better
        shadowColor="#5f0",
// Select color for object, third color character shared between objects :)
        strokeStyle="#"+"fcfdafd62f8".substr(t+t,3);
// Is this an enemy?
  2-t||
// ...yes, inertia, and now standing still?
    (v*=.97)<.1&&
// ...yes, shoot player
      o(x,y,
// ...direct bullet to player...
         atan2(p[0].x-x,y-p[0].y,
// ...rotate enemy to left or right randomly...
               w=r+=random()-.5,
// ...choose random speed for enemy, updates displacement...
               v=4*random())
// ...bullet angle randomly between -0.2 and 0.2 radians of exact direction
//    to not make it too hard...
           +.4*random()-.2,
// ...note it doesn't include last argument, this signals bullet shot by enemy
         7,1,4,35);
// Is it the player?
  t||(
// ...inertia...
    v*=.97,
// Pressing space fires bullets, reuses time for slower shooting
    q[32]&&!z&&o(x,y,r,
// Note last argument signals bullet shot by ship.
      7,1,4,35,z=3),
// Visualize score, note it reuses numbers
    fx(s,4,20),
// Pressing left/right arrows rotates player ship
    r+=-q[37]||q[39]||0,
// Choose meteor or enemy ship
    i=random()<.2,
// Add objects in random positions when there are less than six objects
// Note the objects are added far enough around player's ship.
    p.length<6&&
      o(x+d/4+.4*random()*d,
        y+h/4+.4*random()*h,7*random(),1,i?1:4,i+1),
// Pressing up arrow accelerates player ship and updates displacement
    q[38]&&(w=r,v=3)
  );
// Translate for drawing and calculate new position,
// keep inside canvas with margin so objects enter softly.
        ta(x=(x+d+sin(w)*v+15*u)%(u*10+d)-u*5,
           y=(y+h-cos(w)*v+15*u)%(u*10+h)-u*5);
// Apply rotation
        rt(r);
// Apply scale
        sa(u+.1,u+.1);
// Begin draw
        ba();
// Each shape contained in a single number
// 2602934 = 8,8-4,6-0,8-4,0 (ship pointing upwards)
// 26573945564232 = 0,5-2,8-4,7-7,8-8,2-7,0-4,1-1,0 (meteor)
// 39023120720 = 2,4-0,7-8,7-6,4-6,1-2,1 (kind of Apollo capsule :P)
// 207489 = 3,5-5,5-4,3 (triangle pointing upwards)
// 207489 = 3,5-5,5-4,3 (same)
        for(i=[2602934,26573945564232,39023120720,207489,207489][t];
// number becomes zero when drawing finishes
          i;
// Extract a pair of coordinates. Modulus 9 gets unit 0-8 (drawing space.)
          i-=f=i%9,i/=9,
// ...substract unit before division by 9 to keep as integer
          i-=g=i%9,i/=9,
// draw line
          ln(f-4,g-4));
// Close shape
        ca();
// Paint shape
        sr();
// Restore context
        re();
// If handling alive player ship or bullet fired at least one frame ago
// Check collision against other objects
          for(f=!t*u|3<t&z<35?p.length:0;f--;)
// Be sure it's not same object and it's a ship or meteor...
            if(f-e&&p[f].t<3
// ...inside bounding square
               &abs(p[f].x-x)<4*p[f].u&abs(p[f].y-y)<4*p[f].u)
// Ok, there is a collision
// If it's player then mark as dead and prepare to disappear
// in a few seconds, other objects score if player's bullet and
// disappear in next frame
// Put collided object in scope
// (now four objects in scope!, don't do this at home)
              with(z=e?(s&&++p[0].s,1):(u=0,99),p[f])
// Add spark 1
                   o(x,y,7*random(),9,1,3,9),
// Add spark 2
                   o(x,y,7*random(),9,1,3,9),
// Add spark 3
                   o(x,y,7*random(),9,1,3,9),
// Add spark 4
                   o(x,y,7*random(),9,1,3,9),
// Add spark 5
                   o(x,y,7*random(),9,1,3,9),
// Add spark 6
                   o(x,y,7*random(),9,1,3,9),
// First meteor gets a random kick
                  r+=random(),
// Needs to cut meteor in two?
                   --u?
// Create a second meteor with more random kick
                  o(x,y,r+random(),
// Both meteors accelerate and get same smaller size
                    ++v,u,1)
// Prepare to remove object, already u=0 if 'f' points to player ship
                  :z=f?1:99;
// Time to delete object? Remove object from visual list
        z&&!--z&&e|!u&&p.splice(e,1)
      }
// End of function
}
// Refresh 30 times per second (1000/30 = 33 milliseconds)
,33);

Related links

Last modified: May/12/2013