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.

16:9 scale colorful vectorial.

Score counting :)

Many sparks on blasts.

Always different games.

30 frames per second in most machines.

Objects make smooth transition between borders.

Cleaning the field gets more meteors and aliens.

A lot of realism as there are no sounds in space.

Aliens can shoot down meteors and other aliens by accident.

It can serve also as an screensaver, just leave it running.

Inertia while rotating :)

Radioactive green halo :D

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