After that previous Mazer post about breadth-first graph traversal, or as I put it: wavefront propagation, I got couple of people asking “how do you make a game out of that?”. So, I’d like to talk about how that works and the ideas I tried before I got there.
I wanted to make an action puzzle game. One that has short gameplay loops where the player achieves something every few seconds. I also wanted to make it as procedural as possible so I can avoid having to hand-craft levels and play-test them to verify they are achievable. In a way the game would need to generate a “level” and setup it up in a way that:
- it’s playable – it doesn’t result in an impossible scenario where there is no winning move
- challenging – challenges the player in-line with where they are on the difficulty curve
- fair – not having a win-win strategy that the user can apply without solving the puzzle
- it has a short game loop – user is presented a new puzzle every few seconds
Take 1: The One Tap Mechanic
My first idea was to make a game where the player would asses the playing field – the maze – then apply a single tap/click to make their move. They would watch the game unfold and get a win/lose result.
After thinking this through for a while I settled on a reverse “estimated time of arrival” mechanic. This involves:
- Game generates a maze
- Game selects 3 locations in the maze as exits. Each exit is numbered – 1 to 3.
- Player has to tap on location in the maze that would be the start point.
- A wave propagates through the maze from the start point and the exits need to be reached in order – that’s success.
- If the wave reaches an exit before it’s order has come that’s a fail.
I liked that idea. It required player to “solve the maze” with regards to the 3 exits and estimate the starting location. It required them to think before they acted. To make this a challenge I decided to add time pressure. Given infinite time anyone would be able to trace the mazes and the make the perfect move… if time is ticking down there is incentive to act quickly.
To satisfy my “it’s playable” condition I decided to get the game to select an start point and solve the maze using Dijkstra’s algorithm then record in what order were the random exits reached. That would guarantee that there is always a valid solution. In a way the game would play the maze behind the scenes and do a few calculations before presenting it as puzzle the user. This carried on to be a recurring theme in the final game.
At this point I had written zero lines of code for this game. It was all in my head and my paper notebook. It was still a Zombie Bus.
I set out to prototype. I wrote a maze generator. It was a simple maze generator that didn’t create any loops in the maze. Between any two points in the maze there was exactly one direct route and there were no isolated parts – no unreachable parts of the maze.
It was at this stage I realised this mechanic would have a win-win strategy. All the user had to do was tap/click very close to the first exit and given the “no-loops” generated maze the exits would usually be reached in the right order. I could still make this work by guaranteeing there would be loops in the maze and that exits are generated in a such a way that maze loop presented alternative routes between the exits and the start point… but that seemed like desperately holding onto idea that wouldn’t be able to provide generic game puzzles players can enjoy without considerable post-processing of those mazes.
Take 2: Tap The Exits In Order Mechanic
I decided to move on to and come up with different approach. I knew liked the idea of mazes, estimated time of arrival and self verifying maze puzzles. It wasn’t a big departure to switch the roles of the game and the player. The game would be generating the start point and the exits but now the user would be assigning the order. User would have to tap on the exits in the oder they would be reached from the the start point.
This also made the mechanic more presentable to the user. They now had to solve the maze 3 times (incrementally if they can) judging which exit would be reached first, second and so on. It was a lot more straightforward than the reverse-engineer of start point the first mechanic above.
This did mean that I would lose some of the speed in terms of game loop repetition. Players would have to tap multiple times now. It also opens the can of worms of user input. When is the player solution final? I didn’t want to a “confirm”/”GO” button in there so I decided to have the last exit seals the solution mechanic. However, if player had made a mistake prior to that last input they’d have a chance to change their mind so I had to implement a toggle on/off for exits to accommodate that – adding the fact that the player is assigning order it’s not the most clean of input mechanic.
An interesting scenario started cropping up. Often exits would be at the same distance from the start point – presenting player with a hard to judge but always correct puzzle for those two exits. I did have to tweak the generation and setup algorithms to run the solution in the background and record the distances at all proposed exits and chose ones which different in travel distance.
Another area of experimentation was (and still is) time reward per solved maze. Do I:
- give the player 1 second for every maze solved? (+1 seconds for every maze)
- give them 1 second for every exit they successfully reach? (+3 seconds for 3 exits)
- give them 1,2,3 seconds for respective exits? (+6 seconds for 3 exits)
The last one turned out to be very generous and was quickly dismissed. I’m currently running the middle one but I am finding that game can go on to last for a bit too long for my liking. Plus the user gets more time through the bonus levels…
Yes, there is more to this game. Even though what I just described is the core game loop – really it’s that simple. There are bonus levels where other maze algorithms are involved and pickups are collected, there is the scoring mechanic… and much more.
Stay tuned and I’ll see you next time.