Skip to main content
blogsigler

Developing a turn-based RPG in Godot

Every now and then, I take a swing at working on a 'game'. I never finish even a short 'proof of concept', but the exercise is still fun. This time around, I felt like working on a turn-based RPG, reminiscent of classic Final Fantasy or Dragon Quest.

Developing a turn-based RPG, reminscent of old NES games, is attractive for a lot of reasons: it's practically a convention that the enemy is represented as a static sprite, and that the background can be sparse or even just a black screen. It's no coincidence that my gamedev itch was inspired by Undertale. When playing it, I was struck by how clever the game was, and also how achievable it was (compared to other games, at least).

That being said, making a turn-based RPG is also a unique challenge. I think it's no coincidence that most gamedev tutorials focus on real-time games. It won't be a very interesting game, but you can achieve quite a bit with simple code which checks for inputs every tick and manipulates the player character accordingly.

A turn-based battle in an RPG is a different beast. The way we think of a turn-based battle is a sequence of steps (you choose 'Attack', you hit the enemy for some damage, the enemy hits you back, and repeat), but because the player expects to see this sequence happen before their eyes, we can't implement it as an imperative set of instructions inside a single function call. In order to show the player the steps, we need to show them one thing at a time, then either wait a few seconds or wait for the user to hit the 'next' button, then show them the next thing, and so on.

So, if we can't represent these steps via a set of imperative instructions, what can we do? One solution is to represent them with a data structure. We could represent the battle as a list, where each item in the list contains a callable function, or perhaps just a string, and then store the 'index' that we're currently at in a variable, and every time we progress through the battle (which shouldn't happen every tick, just every time the user selects something or an animation completes), we increment the index and then do whatever the next step in the list tells us to do.

This worked well for the first iteration. I had a simple loop where the player was prompted to attack or defend, then the player's action would happen, and finally the enemy's action would happen. In this case, there were no animations, so what it means for an action to 'happen' is a text box describes it, and the player or enemy's HP decreases by a certain amount. Each 'action' could be exactly one line of text, and hitting the "OK" key/button would cause us to advance to the next step.

Eventually, I wanted more from the system. What if a combatant's action requires multiple steps? For example, what if a certain attack should result in multiple lines of text for the player to advance through? At first, I thought that I could dynamically add steps into the step list, but that gets really ugly because you need to know where to insert the steps in the list, and that index is hard to determine when the list can change size and we don't necessarily know how many steps the previous combatant added. These are solvable problems, but things are getting complicated and the game barely even does anything yet.

I toyed with the idea of letting each step be its own object, which has an internal implementation that has its own set of steps, and tracks its own index in its 'sub-list', and so on. I started to implement this and wasn't really happy with it (the classes for these 'step' objects were going to be HIGHLY coupled with the class that contained the outermost battle step list). I know that I'm unhappy with what I have, but I don't know how to do it differently--I'm wondering if maybe I need to go all in on signals and let the battle step list be a 'linked list' of procedures that point to the next one instead of an array of steps.