Building Walls with Digital Logic

 

A few months back, a friend and I set out to build a simple computer game in 1 month. My friend, Greg, is an artist. He created the art assets and I did the coding.
We built the game in Unity. We decided to build a 2D over-head game where the player navigates a maze and collects items from different stages of life. When all items are collected — from pacifier to coffin — the game is over. It’s all very deep and philosophical. I want to highlight one cool experience in the development of this game: building the walls.

It’s always fun to see knowledge that, at first, seems superfluous come into practical use. I took a course in digital logic last fall (as part of my ongoing education plan for a BS in computer science). I didn’t immediately see the use in knowing about binary conversion. I mean, doesn’t the computer just do that for me? In the end, this small bit of knowledge, practiced over and again for class, came in very handy.

A 2D overhead maze game showing walls, floor, player, and pacifier collectible

 

The Blueprint

I researched maze creation algorithms before beginning any other development. The one that seemed like the best option was Depth-First Search (DFS). Miguel Kano’s article on DFS is a big help. From his article:

“Depth-first search is an algorithm that can be used to generate a maze. The idea is really simple and easy to implement using recursive method or stack.

Basically, you start from a random point and keep digging paths in one of 4 directions(up, right, down, left) until you can’t go any further. Once you are stuck, you take a step back until you find an open path. You would continue digging from there. It’s just the repetition of these.”

I used DFS to build a 2D array which stores a 0 to represent a floor position and a 1 for a wall position. Since there was only one floor tile, it was easy to place the floor with some simple game logic like:

if (thisPos === 0) { drawFloor(thisPos); }

So far so good. Then comes the tricky part — wall placement.

Bad Framing

My first pass at this was pretty horrible. I was taking into account all sorts of separate issues for each wall position like 1. is it a corner? 2. is it on the edge of the maze? 3. what are it’s connecting walls?? This led me to write some awful code (which works) like this:


Ugly code

Ignoring the parts of Unity code that you may not understand (GameObject, Quaternion.identity, transforms), what is mazeSprites[6]? I guess it’s the wall which has a connection to the up, right, and left from the code. But what about mazeSprites[5]? I have no idea. Even if I had left a comment about what it represents, this code is still atrocious. And this is just some of the logic for the corners and wall edges! Let me continue:

Ugly code
The inner wall logic alone continue in this horrendous fashion for about 90 lines.  My code is bad. It’s repetitive. The organization is bad. My wall tile assets stored in the mazeSprites[] array have no logical flow. Everything is bad. I frown.

The saving grace of this code is in the comments: // 1111 (Up, Right, Down, Left)

Common Sense Structuring

If, just after building the 2D array full of 0’s and 1’s (floors and walls), I iterate through the walls and check the wall’s neighbors, I can use that information for good. If a wall has a connection on each of its 4 sides (in order from Up, Right, Down, Left), that wall position will change from a ‘1’ to a ‘1111’ which is binary for 15. If the wall has a connection on only its Down side, it is now a ‘0010’, binary for 2. This provides the structure I need. Now I can convert these binary numbers into decimal: a ‘1111’ becomes 15, and then I can set up mazeSprites[15] to hold the wall sprite with connections on all 4 sides. This leads to the following improved code which is called in a loop: *Note: the 2d gameMaze[] array holds the 0 (floor) or 1 (wall)


Good code

This bit of binary knowledge helped me organize my art assets and simplify my code. The logic was there, quietly waiting to be discovered. What was literally over 90 lines of nearly incomprehensible if-else spaghetti was reduced to the 15 lines (including comments) of easy-to-follow logic you see above.