Friday, 18 January 2013

One hour game initiative


It's Friday again and I'm like a plastic chicken. What can you do with a dead brain? Well actually quite some things. Back in high school when we drank our first beer with my best-friend we tried to measure how drank we were. Do you know how? We went through the basic calculus theories. And when you're dancing in a public fountain almost naked chanting math equations you realize there not too much correlation.

Anyways. Today I propose the:

"One hour game" initiative


One hour game when you create a game in one hour. It's like the time limited version of 64k game. Back at the university I loved to create small games. They are perfect to learn structuring code and taking care of the right implementation design. Well, and then you just pile the code up to a huge mess so it works before you go to bed.

A one hour game can be written in any language and any environment. Genre and complexity doesn't matter. My silly one hour game a simple shooter game: AsciiShooter


The game is simple - never overestimate a one hour game. Left and right keys navigating the ship. Space shoots the enemy. (No intergalactic prelude this time.) Let me explain quickly how it works:

The base is html, we just create some containers:

<!doctype html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="AsciiShooter.css" />
<script>
</script>
</head>
<body>

  <div>
    <pre id="title">Ascii Shooter</pre>
  </div>

  <div>
    <pre id="map"></pre>
    <pre id="ship"></pre>
  </div>

  <div>
    <pre id="score"></pre>
  </div>

  <div>
    <small>Controls: navigation = left/right, shoot = space.</small>
  </div>

</body>
</html>


Nothing extraordinary. Let's define some key mapping constants:

const KEY_LEFT = 37;
const KEY_RIGHT = 39;
const KEY_SPACE = 32;


We will have a screen and we need to know the boundaries and some coordinates:

var screen_w = 12;
var screen_h = 10;
var screen_mx = new Array(screen_w * screen_h);
var ship_x = Math.floor(screen_w >> 1);


Here screen_mx will contain the enemies on the map. We need some vars to define the rendering engine behavior:

var step_delay = 600;
var render_frequency = 100;


Not the easiest if we define what happens with the enemy. That's basically the main step of the game. We have a matrix where enemies are appearing on the top and flowing down towards our ship.

function step() {
  for (var i = screen_h * screen_w - 1; i >= 0; i--) {
    screen_mx[i] = screen_mx[i - screen_w];
  }

  for (var i = 0; i < screen_w; i++) {
    screen_mx[i] = Math.random() > 0.95 ? true : false;
  }

  setTimeout(step, step_delay);
}


There we copied each line to the next line. Then we add enemies to the very first row randomly. At the end we call it again - that makes the game continuous. It would be great to count how many enemies got through our defense. Let's store it in:

var stat_survive = 0;


And count them in the stop function:

  for (var i = 0; i < screen_w; i++) {
    if (screen_mx[screen_w * (screen_h - 1) + i]) {
      stat_survive++;
    }
  }


Each enemy that would go over the last line is a surviver. Now we can add the ship navigation and action handlers:

  jQuery('body').keydown(function(event){
    switch (event.keyCode) {
      case KEY_LEFT:
        ship_x > 0 ? ship_x-- : null;
        break;
      case KEY_RIGHT:
        ship_x < screen_w - 1 ? ship_x++ : null;
        break;
      case KEY_SPACE:
        shoot();
        break;
    }
  });


With the key events we set the coord of the ship or do a shooting action. Shooting is very lame, just removes the enemy if it's in the way:

var stat_kill = 0;

function shoot() {
  var row = screen_h - 1;
  var kill_flag = false;
  while (!kill_flag && row >= 0) {
    if (screen_mx[row * screen_w + ship_x]) {
      kill_flag = true;
      screen_mx[row * screen_w + ship_x] = false;
      stat_kill++;
    }
    row--;
  }
}


And we need a last thing to care about - rendering the whole game out:

function render() {
  var output = '';
  for (var i = 0; i < (screen_w * screen_h); i++) {
    output = output + (i && i % screen_w == 0 ? "\n" : '');
    output = output + (screen_mx[i] ? 'O' : ' ');
  }

  var output_ship = '';
  for (var i = 0; i < screen_w; i++) {
    output_ship = output_ship + (i == ship_x ? 'A' : ' ');
  }

  jQuery('#map').text(output);
  jQuery('#ship').text(output_ship);
  jQuery('#score').text('Killed: ' + stat_kill + ' Missed: ' + stat_survive);
}


And to start the game I've put the ignition into the DOM-ready callback:

jQuery(function(){
  step();
  setInterval(render, render_frequency);
});


Dead simple. And now I'm sleeping. Before my laptop falls down you can click on the GitHub repo of the game: AsciiShooter. Or try the demo.



---

What do you think about the "one hour game" initiative?

Peter

No comments:

Post a Comment