Solvable Chunks: One Week Video Game

How I built a Massive Multiplayer Online HTML5 Canavs Game in One Week

July 29, 2016 •

Screen capture of Global Defense

‘Twas late Sunday night and I got an idea for a multiplayer HTML5 game using canvas, web sockets, and gyroscopes. I tossed and turned mulling it over. On Friday night Chris Coyier and I were scheduled to do a live Shop Talk Show at Web Design Day in Pittsburgh. As I lay awake staring at the ceiling, I realized I might be able to pull it off. I would call it Global Defense!

Play Global Defense

Solvable Chunks

To build the game I broke the project up in to something I call “Solvable Chunks”. Breaking a design or idea into smaller pieces, while maintaining a big picture, allows you to prototype each piece of necessary functionality with the aim to inform your design and timeline.

To me, a solvable chunk is a problem I think I can solve in about 4 hours. The 4 hours is relevant because -as a parent- it’s roughly the amount of time I have after my kids go to bed. It’s also the length of a morning or afternoon where you can prototype while pretending to check your email. Solvable chunks is maybe something we do naturally, but applying a light framework around it has really helped me quickly create and maintain momentum.

When working on a chunk, I’m always aware that a problem can give birth to a myriad of baby problems. Knowing that, over thinking or scoping anything beyond that first or third chunk is futile because what I discover in those early stages will dramatically affect what happens in later stages. I have the big idea in mind, but I let those later stages be intentionally vague.

Solvable is important too. At all costs you want to keep momentum on a prototype. Keeping problems small and solvable helps you do this. Losing momentum means it will be more difficult to jump back into solving complex tasks. If by the end of 4 or 8 hours you’re still not finished, that’s okay. You should now have a better idea of what it would take to finish and if the current design is endangering the timeline.

At the end of your chunk, share and document your learnings with your team. If you’re working solo, keep a development journal you can reference later.

Using prototypes you’ll be able to make better timeline estimates if you do a little bit of the work up front. You can choose to keep iterating, redesign to be something more minimal and timeline efficient, or adjust the timeline.

The following is a night-by-night, chunk-by-chunk, breakdown of how I built Global Defense.

Monday: Asteroids

See the Pen Global Defense v1: Make asteroids fall by Dave Rupert (@davatron5000) on CodePen.

I didn’t know much about drawing in canvas, so my first chunk was learning to draw falling-circle shaped asteroids. Circles have x, y, and radius attributes. Making them fall from the top was simply a matter of increasing the y value every frame and splicing the asteroid object from the asteroids array when it hit the bottom of the screen.

// Move the Asteroids
for(var i = 0; i< asteroids.length; i++ ) {
  var asteroid = asteroids[i];
  asteroid.y += 1;

  if( asteroid.y > h ) {
    asteroids.splice(i, 1);
  }
}
// Draw the Asteroids
for(var i = 0; i< asteroids.length; i++ ) {
  var asteroid = asteroids[i];

  ctx.beginPath();
  ctx.strokeStyle = '#0CF';
  ctx.arc( asteroid.x, asteroid.y, asteroid.radius,  0, 2 * Math.PI );
  ctx.stroke();
}

Tuesday: Shooting

See the Pen Global Defense v2: Make bullets shoot by Dave Rupert (@davatron5000) on CodePen.

I originally wanted lasers to shoot the asteroids like Missile Command or Asteroids, but as I thought about it some I realized a “bullet” is really just a tiny asteroid that goes up instead of down! I already had the code for this, so I inverted my asteroid code to make bullets.

// Move the Bullets
for(var i = 0; i< bullets.length; i++ ) {
  var bullet = bullets[i];
  bullet.y -= 2;

  if( bullet.y < 0 ) {
    bullets.splice(i, 1);
  }
}

Allowing the code from the prototype to inform the design saved me lots of time and I attribute this to being the reason the project was successful.

Wednesday: Collision, Damage, and the Planet

See the Pen Global Defense v3: Aim, Collision, and Damage by Dave Rupert (@davatron5000) on CodePen.

Now I needed the bullets to destroy the asteroids. Searching the web for “canvas circle collision detection” took me to an MDN article about 2D game development. There was my answer in JavaScript. I had to modify it a bit, but it worked and bullets could now splice() asteroids.

// Detect Bullet/Asteroid Collisions
for(var i = 0; i< bullets.length; i++ ) {
  var bull = bullets[i];

  for ( var j = 0; j < asteroids.length; j++) {
    var ast = asteroids[j];
    var dx = bull.x - ast.x;
    var dy = bull.y - ast.y;
    var distance = Math.sqrt(dx * dx + dy * dy);

    if (distance < bull.radius + ast.radius) {
      // Collision detected!
  }
}

Yay free code! The code-informed design decision to switch to circles already started paying off in speed.

Damage was an easy patch. Each asteroid would get a randomized hp (hitpoint) attribute. And the radius on each draw() cycle would now be based on the hp * asteroidSizeModifier. After every collision, damage would be applied, affecting the radius.

if (distance < bull.radius + ast.radius) {
  // Collision detected! Remove bullet.
  bullets.splice( i, 1 );

  // Make asteroid take damage
  if(ast.hp - 1 === 0) {
    asteroids.splice( j, 1 );
  } else {
    ast.hp = ast.hp - 1;
    ast.radius = ast.hp * asteroidSizeModifier;
  }
}

The last chunk was the planet. After some thinking, I realized planets are just very large asteroids! I already had this code and the collision detection. It came together quickly. Again, that code-informed design decision was paying off in dividends.

Thursday: Math and Socket.io

On Thursday I was traveling all day on a plane to Web Design Day. This worked out well for the project because I had to pull it off of CodePen to my localhost begin web socket work using Node and Socket.io.

Screenshot of hand written math equations

I started by doing a lot of High School level math. I’m surprised I didn’t get escorted off the plane. Eventually I understood Math.tan() and y=mx+b enough to give the bullet a slope as it travelled upwards based on my Surface’s gyroscope.

Socket.io, a very complex web socket thing, turned out to be easier than imagined.

On one page there’s a game board, on another a button that says “Fire”. When the fire button is clicked, it emits a custom event called fire. Attached to that event you can send data. After some tinkering I realized I could just send the calculated slope of the device. Emitting a small packet of data is good.

function handleClick( event ) {
  socket.emit( 'fire', { slope: slope } );
}

The server hears that event and responds by emitting that fire event and its data out to all the other connected clients (i.e, the game board).

socket.on('fire', function(msg) {
  io.emit('fire', msg);
});

When the game board screen hears a “fire” event, it will push() a bullet object into the bullets array with the slope from the packet of data. The draw() function in the next requestAnimationFrame will give it a starting x,y coordinates and start animating the bullet.

socket.on('fire', function(msg) {
  bullets.push(msg);
});

I also learned that VS Code is a really great text editor for building and debugging Node applications. You can (re)launch your server by hitting F5 and even setup a debugger to step into objects and functions just like a web inspector. That feature alone may have secured Code as my editor of choice going forward.

Friday: UI, Polish, and Demo!

Photo of Global Defense playtest Photo by Brian Muenzenmeyer

On Friday I used my new found canvas skills to rough out a UI. This has a “Draw the rest of the owl” feel but everything below was optional. I could have played the game without this stuff, but it was a little more exciting with it.

I did some refactoring:

  • Improved the single player mode and game joining system.
  • I added a simple polygon for a ship, but its position affected the initial y-coordinates of the bullets.
  • Adding a bit of responsiveness for a multidevice strategy means minor refactoring of the ship and planet to be scalable.

And added some nice to haves:

  • I made a defcon variable to increase the chance of randomization.
  • I added a score to give the game a bit more of a point.
  • I downloaded a font from DaFonts for the UI text; score, planet hitpoints, and defcon level.
  • Made the earth change color for 12 frames when hit.
  • I bought a domain name and forwarded the DNS.

And that was it. I had a working game. The demo during the live Shop Talk Show went okay. Live demos are always tough, and it’s impossible for me to test 200 simultaneous clients, but it held up and I think people had fun. Bullets never stopped flying.

The next week

Notebook with about 10 to-dos all completed: Mnaifest, Offline, Service Worker, Base32 Game ID, Rotate to Aim, Tap to Fire, Click to Fire, Instructions, Show Game ID on UI, Icons, Homepage, Reset(), apple-web-app-capable?

Over the next week I built out a punchlist of all the things I learned I needed. I took the same Solvable Chunks approach to finish it out. Most of these chunks went a lot faster. By the next Friday, a week after the demo, I was ready to share it.

Launch went well, except I had a bug where the game would never start. So I uh… fixed that.

There are still have some things I’d like to do, but I’ve learned through this process that each feature adds about another day of work. Making the asteroids more geometric instead of circles? 1 day. Making the bullets lasers instead? 1 day. Progressive web app? 1 day. The list goes on, the day job is back in full effect, and I’ll have to take it one chunk at a time since there is zero momentum. Or I’ll start another project ;)

Summary

Global Defense is a game I built in my spare time. I had a playable prototype in a week and launched it in two weeks.

Along the way, I worked in solvable chunks and let the code from the prototype inform some of my design decisions. This saved uncounted hours and allowed the product to be delivered quickly and on time. Working on a tight timeline forced me to be practical and reduce scope as much as possible. Getting to a minimum viable product meant understanding that every feature would result in another day of work.

I had fun building it and learned a lot about canvas, gyroscopes, and websites with high-concurrency, realtime, cross-device communication. Those are all things I can apply to my work immediately. I’ve also had the chance to have conversations with people from Microsoft Edge and Google Chrome about it, not too shabby.

I think the greatest takeaway, even though it’s low-budget and still has a prototype feel, I built and released my first game other people can play. That is very exciting and I hope there’s more in the future.