Fredrb's Blog

Rediscovering Roguelike Games

I’m not a hobbyist Game Designers. Perhaps I was on that path ten years ago when my friend and I had an idea for the next World of Warcraft and we would put it to practice. We hadn’t, and we didn’t. The passion for building something of my own is still there though. Maybe different, less grandiose and more reasonable. What keeps pulling me back to Game Development is the technicality of it rather than design. Can’t lie, I occasionally get myself thinking in games I could build. But my attention constantly shifts from game design to its technical aspects.

Earlier this month I came across a community of Roguelike game developers. I would have remained unaware of this community if it wasn’t a struck of Internet serendipity. The term Roguelike was not new to me, but the specifics of what defines it as a genre and amount of people involved was astonishing.

One place where people get involved is the Seven Day Roguelike Challenge (7DRL) (official page). A yearly event where game developers build and submit Roguelike games in a week’s time frame. 526 people took part in the event in 2019 according to roguebasin challenge page.

On May 14th I accidentally started a self-7DRL-challenge. After doing the first few parts of this tutorial just for fun, I was hooked. That settled the tutorial result as a base for my 7DRL. I could definitely finish the game in seven days at this pace (I didn’t) and the tutorial would only last two or three days (took seven). Even though it took twice as long as I planned, the journey was fun. Using nothing but a font image to develop the game set the right amount of technical limitations that allowed me to be creative [1].

The stack used to develop the game:

  1. Python3
  2. tcod library for Python
  3. dejavu16x16_gs_tc.png font file
  4. PyInstaller for releasing the game to Mac and Windows

This post is a compilation of some things I learned, surprising discoveries and challenges faced in the last two weeks. The experience of writing this game was pleasant. I have constantly flirted with game development but done nothing about it. I can’t express enough what finishing this project meant to me, despite the simplicity of it.

Dragons and Dungeons

itch.io game page

As cliche as it gets, the game I developed has:

  1. Infinite dungeon
  2. Magic Missiles
  3. Fireballs
  4. Goblins
  5. Trolls
  6. Dragons

This is my comfort zone. Determining what the game would be about as in winning, losing, battling and surviving wasn’t relevant for me at that point. As I mentioned before, I am more interested in the technicalities. I spent most of the time incrementing the tutorial result to add an architecture that made more sense to my game, hotkey support, a city screen, spell targets, a monster scan log and some other shiny features. I’ll break down some significant changes I made to the tutorial result:

Filling the screen with colorful ASCII

I have moved things around a bit. Health bar and player stats are up, message log is on the same place, there is a hotkey bar and two scan logs.

Ground scan: Shows whatever things are in “field of view” or always shown (like stairs)[2]

Monster scan: Shows all (alive) monsters in “field of view”.

play_test_4

On its first form, the monster scan was supposed to support targeting. Similar to what Tibia offers. Not being familiar with Roguelike games, walking towards the enemy to attack them was odd at the beginning. I wanted either an “auto-attack” mode or a button to “attack the target if in range”. Targets could be cycled using “Tab” key. Since I was determined to finish the game in a reasonable time frame, I opted out on this feature, keeping the classical “walk towards to attack” mechanics of Roguelikes.

Burning Multiple Goblins with Fireballs

After the mouse target tutorial part, I was craving for a visual aid on the spell target. I can’t recall how quickly I implemented this after I finished the tutorial, but it was surely high on my priority list. Both for single target and area spells. The result was great.

play_test_area

One caveat that the gif above doesn’t show, is that the area color is very similar to the color of some monsters in higher levels. When these monsters are in the targeted area, they become almost invisible on the map. This could be solved if targets switch to a “targeted” color when found in the target area.

Facing the Dragon

The major “game design” addition was to have a boss every 7 dungeon levels, with Dragons and minions stronger than the regular level. I wanted two major things:

  1. Add levels in between that were not procedurally generated.
  2. Have a challenge that the player had to prepare for.

boss_1

The initial Dragon battle (at level 7) is hard. Incredibly hard. Unless you get a good amount of spells and buy a lot of passive stat tomes, you will likely die. This is part of the balancing issue (described below), where the first boss is harder than the second and third.

Resting in peace

One interesting addition to the game was adding a statistics screen of the player’s run after their death. Most of my friends that played the game perceived the feature very well, albeit it was simple to develop. Given the simplicity of the game, it is hard for a player to keep track their progress. This screen existed to fulfill that purpose.

Screen Shot 2020-05-28 at 09.04.28

The game is filled with well known D&D resources. Magic Missile, Fireball, Goblins and Dragons aren’t anything new even to casual players. That plays an enormous advantage for me because my friends can experience it fully with little effort to learn new terminology. They don’t need to learn that Goblins are weaker than Trolls, which are weaker than Dragons. They are well aware of Fireballs and Magic Missiles.

tcod Library

I have never heard of tcod before I started this challenge. It is interesting to see such a specific library being used widely (or at least widely in this community). Developing with it feels like something in-between SDL and curse-like libraries. With a bunch of ready-made features specific for Roguelikes. Here are some of my takeaways from tcod:

Map Structure and Field of View

The tcod.Map abstraction and light algorithms are collectively the best features provided by tcod. Map provides necessary properties to define transparent and blocked path in a 2d array that integrate with the light algorithms creating the Field of View light effects. I probably wouldn’t bother to develop myself if I were building the game from scratch. Having these effects gave the game a significantly better aesthetic.

light

Monospaced Cells

Every sprite in this game is a character in a font and every piece in the scenery is a colored text background. Therefore, you place all game content in a grid, removing a lot of the heavy-lifting of 2D graphical programming. No need to deal with pixel or float screen coordinates. Placing an entity at (1,1) and another at (1,2) objectively means placing them next to each other with no overlap. The biggest advantage of this is that the coordinates used for rendering are the same on the virtual game map. This way the renderer doesn’t have to convert map coordinates to screen coordinates.

Colors

Every object in your game is a monocolored character. One must vary a lot of colors to make the game feel more alive. Colors can identify friends, foes, items or danger. The tcod library offers a bunch of convenient colors ready of usage; e.g. tcod.red, tcod.light_red, tcod.darker_red.

Challenges

There were quite a few challenges I had to overcome to see this project through. They are all product of a lack of game development skills. The tutorial gave me a solid foundation for every design decision I took. There are things that I would have struggled if it wasn’t for the tutorial structured the code. Especially in the Entity-Component relationship, a widely used pattern in Game Development. On one hand, having that design in place, made it easier to plug-and-play additional features for both the hero and the monsters. On the other hand, some tutorial parts are messy, like the “function files” and the amount of responsibility of one giant block of code inside the game loop. Mostly, the modularisation presented is just hiding the complexity and not breaking into a new abstraction.

In this part I’ll show how I tried (and failed) to break the rendering logic into a more Object Oriented design. Also, how I attempted to make the game more balanced, teach the players how to play and ship the game in a reasonable format.

Game Design vs Code Design

Having developed enterprise software for the last few years, I couldn’t help but trying to design and find an abstraction I would feel comfortable with. We should design software for constant change, it is important to have a piece of code that can be easily maintained. Naturally, not every part of your program will be effortlessly changeable. It’s always a matter of trade-off. What changes constantly must be easily changeable and it’s ok to have a complex mess if that never changes.

After finishing the tutorial, the first task in my mind was to break down the tutorial’s game loop logic into smaller pieces and find the common interface among them. It was an easy decision for me. I broke the single class that was handling all plumbing code into four different ones:

All these 4 objects are part of a game Stage. And my game loop is always interacting with the current stage.

That was a grim decision.

Applying this massive refactor to that part of the code was time-consuming and gave me little benefits in the long run. The design is not bad, I’m still convinced that this separation of concerns makes sense. But the problem is that what I thought would be different stages (playing game, in-game menus, player dead, city shops, inventory) were all part of the same stage/scene combination. Which is the playing one. So I ended up with two stages: Game and Main Menu. This refactor would make much more sense if driven by a game design decision. Like having unique places, scenes and mechanics in the game. But for a single scene procedural generated infinite dungeon, there was no point in putting all this effort.

It’s fine to have a complex mess if it doesn’t change. First, assessing what part of the game code is frequently changed, and then focusing on a de-coupled design makes a lot more sense.

An excellent post by Michael Feathers (2011) about this topic: Getting empirical about software refactor; and a follow-up by Sandi Metz (2017): Breaking up the behemoth

Balancing

Figuring out how to make the game easy, slightly difficult or very difficult in distinct places was hard. I wanted the game to be a little difficult in the beginning so the player struggles in the first few rounds. The following rounds should ease things so the player gets more confidence and rewards. Then, in the higher levels, raise the difficulty so they also don’t lose interest.

Balancing turned out to not only mean making monster stronger, but making player progression more reasonable.

The initial version of Magic Missiles would fire a number of missiles equal to Magic Power/10. Since magic power scaled exponentially, at higher levels magic missile was firing ~100 missiles and single handily killing any boss.

At some point I called the quits on this. If I wanted to structure the difficulty level as I wanted it would mean rethinking all the monster progression and damage formulas. And since my friends wouldn’t care if they die from goblins at level 1 and one-shot elder dragons 20 levels done the line, I was fine with it.

Teaching players how to play

When you develop a niche game for a community there is plenty of intrinsic knowledge. You don’t have to explain most of the mechanics in the game if you follow the same conventions as your peers. It can, however, be often difficult to draw this line on what does the player knows and what does the game has to teach them. Things like the @ being a player, attacking by moving towards an enemy or use the mouse after clicking on a spell. Were a few that popped in my mind when finishing the game.

Providing a manual can be useful, but also tricky. Providing too little information leaves the players in the dark, while too much information is easily ignored.

Screen Shot 2020-05-28 at 09.42.24

Even with that screen, after sending the game to some of my friends; one of them said: “I didn’t know if I could use melee attacks on monsters or if only spells would work”.

Packaging and Releasing

Releasing the game was on the bottom of my priority list and it burned me so hard that I almost gave up on the project all together. Since I developed the game in Mac and most of my friends have Windows, I used pyinstaller to generate the executable binaries for both Windows and Mac. Even though pyinstaller is a great tool that takes a lot of the complexity away, it took me more than a day to figure out why I was not able to generate the package in my environment. After a lot of debugging and a Pull Request sent to the project, the binaries were properly generated. Some of the major problems I faced:

  1. Python Lib not found (Mac): This was the reason I had to debug pyinstaller in the first place. I eventually figured out that my environment virtualenv + Python3 installed via brew had a small misconfiguration compared to what pyinstaller expected. Here’s the issue and the pull request related to the problem.
  2. Binary not opening screen and no error message shown (Windows): The kind of issues that make you pull your hair out. Windows .exe binary was simply unresponsive regardless of the build being successful. Took me a while to figure out that the --debug=all flag would “propagate” to the generated binary and you can get more meaningful logging.
  3. Images not being copied to the binary (Windows): For some reason the image was being properly copied in Mac but not in Windows. Even though the image name had no special characters and only lower case letters. This resulted in me having to manually add the images passing the --add-data parameter to pyinstaller.

PyInstaller makes sense most of the time. But sometimes it made no sense at all. It was pleasant and frustrating. Nevertheless, all problems were, after pulling some of my hair out, resolved.

Conclusion

There are tons of other features I wanted to put on the game. For the sake of time I decided against it. Finishing this project was one of the key takeaways for me. It was totally worth it. I had a good time developing it. However when things got hard or boring I had the urge to just drop it and start something else. Since the endeavor lasted for a little more than 2 weeks, it was ok to put other wishes aside and focus on finishing the task at hand.

I’m not sure I could do game development for living, but it was definitely an interesting experience. I might probably attempt some form of game development again in the future. Maybe at something higher level like Unity or lower level like building my own things from scratch. Or even join next year’s 7DRL challenge.

Check out the communities and resources:

Footnotes

[1]: There was an interesting article in HN a couple of months ago talking about Gunpei Yokoi. How he used “withered technology” to design the Game Boy. The hardware limitations were essential to push his creativity: “Withered constraints will push you creatively, yet allow you to scale to success”.

[2]: Originally I left the stairs (>) character always showing, regardless if the map was not explored and it was not in the Field of View. That turned out to be an interesting mechanic for the game, since I have to make the call if I want to go quickly through this level or explore it more.

[3]: Attribute tomes were inspired by old Warcraft 3 hero defense custom maps. Quite a few had STR, AGI and INT consumable tomes, which were the basis for “levelling up” your hero.

#roguelike #gamedev #challenge

⇦ Back Home | ⇧ Top |

If you hated this post, and can't keep it to yourself, consider sending me an e-mail at fred.rbittencourt@gmail.com or complain with me at Twitter X @derfrb. I'm also occasionally responsive to positive comments.