Pac-Man

I've published my Pac-Man clone! It's not 100% complete, but this was just a learning exercise, and I think I've gotten enough out of it.

The bits that I didn't do:

  • Music: I wanted to record some simple background music in a particular key, and record the sound effects in the same key. They would combine produce a randomly generated soundtrack. I recently attended a talk at Freeplay by a guy called Stephan Schütze, who had lots of interesting things to say about procedural music generation. I may revisit this idea in a future project.
  • Artwork: There are some elements that I didn't bother doing (mainly the bonus symbols, which are represented as plain white squares). The ghost artwork is pretty inconsistent, too - ghosts look totally different when frightened. I would probably have fixed this, but my trial Photoshop license expired. (Do you know how much that thing costs nowadays?)
  • I skipped some behavioural details, like the way ghosts jostle around in the house when they're waiting to be released.

Other than those, it's a pretty faithful implementation of the game.

There are some technical decisions that I would make differently in retrospect. The following (non-exhaustive!) list outlines some choices that might have overcomplicated things:

  • Code structure: Programmers have a tendency to look for patterns and generalisations in code that can be re-used. In my case, I wanted to keep the engine code as simple as possible, and pushed all the behavioural bits and pieces (particularly the ghost releasing and mode switching behaviour) down into objects (i.e. DotCounter, ElroyCounter, ModeSwitcher and ReleaseTimer). I don't think I hit a particularly sweet spot of abstraction by doing that – it would probably have been nicer to keep it all nearer the surface.
  • Movement: I got overly concerned about actors moving in sub-pixel increments. That is, the ghosts and Pac-Man can have speeds of e.g. 1.2 pixels/frame, but you can't draw inbetween pixels on the screen. I came up with some rather complicated code to accumulate fractional pixel amounts between frames, but it would've been much easier to store the raw values and round to the nearest pixel when drawing. Check out Actor to see what I mean.

There are plenty of other warts in the code, but it works OK.

The playable version is at http://www.harto.org/wheel/pacman. It works in recent versions of Firefox, Chrome and Safari (without sound). The source is at https://github.com/harto/pacman.

Let me know what you think!

Simple JavaScript dependency analysis

One of the most glorious forms of procrastination for a programmer is developing tools that automate menial and repetitive tasks. I've wasted lots of time on little Python scripts that generate Java classes, remove unused rules from CSS stylesheets, and all kinds of other unnecessary stuff.

My latest invention is a program that does a simple analysis of JavaScript files to determines the order in which they should be concatenated.

Concatenating multiple JS files is a simple optimisation that reduces the number of HTTP requests between a browser and a server. However, they need to be concatenated in the right order so that objects and functions are defined before they are referenced.

The program works by scanning JSLint /*global ...*/ declarations to determine the JavaScript variables referenced by each script. It then looks in all other scripts to figure out which one defines each variable. This results in a dependency graph that maps each file to each of its dependencies.

Once the dependencies are known, the program determines the concatenation order by inserting files into a list, one at a time. Each file is inserted after all its dependencies. If any of the previously inserted files references the newly inserted file, they are removed and reinserted in the same way.

The insertion algorithm seems very inefficient, and possibly isn't even correct! (I don't remember anything about graph theory.) But it seems to work for my Pac-Man project, which is split into 32 interdependent files.

Here's the program, and a Makefile that shows how it's used:

State of play

So much for my regular blogging habit.

Since my last post, I've been continuing my self-education in games development. I'm going to write about the state of my current project, which is a Pac-Man clone.

But first, briefly, some exciting personal news!

In March, 7 years after we starting going out, I proposed to my partner Lucy. And she said yes! We're getting married in October here in Melbourne.

We also went to Europe for a short holiday - one week in the UK catching up with relatives, then two weeks in a Parisian apartment. It was an amazing time - what an incredible city!

So, as is often the way with Life, I haven't been able to spend as much time as I expected on Pac-Man. Aside from the aforementioned events, it's still taken longer than expected.

There are a few reasons for this:

  • As my understanding of the game evolved, I would think of different ways of doing things. This resulted in me reworking large chunks of code. This is really the whole point of the exercise: an opportunity to learn how a program like this hangs together.
  • While fleshing out "secondary" parts of the game, I would realise that some earlier assumption I had made was no longer valid, and would have to do some rework. For example, when Pac-Man eats a ghost, everything pauses for about half a second. This meant implementing a global wait function. I could've glossed over these kinds of details, but I learned more by just spending the time and doing it.
  • I decided to implement some rudimentary graphics and sound effects. This has been a lot of fun so far, and is a big part of why I'm excited by games development - lots of different creative techniques involved.
  • The game logic is more complicated than I realised. Luckily, I could refer to The Pac-Man Dossier whenever I needed help - an excellent resource.

I'm not going to implement every last feature of the game, but I do still want to implement a couple more things. I think it's only the following:

  • Background music. (In the original Pac-Man, this is a weird wobbling sound that speeds up towards the end of each level.)
  • Artwork for the bonus symbols (cherry, key, etc).
  • "Cruise Elroy" mode (see Pac-Man Dossier)
  • Maze flashing on level-up

The code will be available on my GitHub account shortly. Once I publish it, I'll write a follow-up post detailing some of the interesting technicalities of my implementation.

Blinky

Reinventing the wheel

To get really skilful at something, you got to do it a lot. An obvious way to learn games development is by building clones of existing games.

My brother showed me an article that prescribes a list of arcade classics to be developed by the aspiring programmer. Once you remake each of these games, you'll theoretically know all the fundamentals of game development. (This would also be a really good way to learn a new programming language.)

I started on a Tetris clone a long time back then forgot about it. But I recently remembered that I kind of, you know, need to learn how to make games. It's implemented in JavaScript and basically works, although the rotation algorithm is a bit smelly (i.e. wrong). I've pushed it to Github and you can find the source here.

Feel free to use the code in whatever way you like. It's obviously not perfect. I publish it to shame myself into improving it. Hopefully I'll find the time to do so.

Other people's software seems simple until you discover all the little details that accumulate over the life of the program. I won't aim for 100% of the functionality, since it's only a learning exercise. But I will endeavour to add a bit more here and there, possibly in parallel with the next game in the list - Breakout.