Now that player movement exists in the game it’s time to extend that courtesy to enemies. This might seem simple since we already have the ability to move tokens around the map, and it’s true that if we give an enemy token a new position, it will move there without a problem. This, however, does not take into account that the enemy needs to pick a place to move to. In a game with tactical turn-based combat, this is going to be one of the biggest problems to solve as the enemies will need to move (and eventually use other actions) in a way that will provide an interesting challenge to the player.
Enemy behaviours
Before I dived into actually making the enemies move, I decided to consider enemy AI and how to make their behaviour interesting. I’ve not done in-depth research here, just a couple of hours reading some summaries and thinking about how I might apply them. When I start building enemy AI properly, I will need to do some further research. For now, there are two statements that I think are interesting and that crop up regularly in discussions:
- Enemy AI doesn’t have to be extremely complex to be interesting
- Different enemies with different simple behaviour patterns can be used together to create an illusion of complexity
Based on this, I’ve written down some prototype enemy behaviours that I’ll try to implement:
- Berserker – this enemy wants to get up close and personal. They don’t care for their own safety too much, and also have little regard for tactics beyond hitting things hard. They might occasionally do something like trying to grapple their opponent or trip them up
- Frontline Soldier – this guy wants to get close too, but is going to be more tactical about it. They’re going to try to get into flanking positions, try to disarm their opponent or hold them still so others can get the big hits in. If they have protective abilities, they’re going to use them to keep their allies safe
- Melee Assassin – the assassin archetype wants to get to the squishiest target, preferably without being engaged by anything that can hit them hard. They’re going to try to take advantage of openings provided by their allies
- Ranged Assassin – this assassin archetype wants to stay as far away as possible while still being able to shoot the squishiest target. They’re going to try and hide, just to pop out and take a devastating shot later
- Support – these guys are going to be the ones hanging out at the back buffing and healing their allies, or debuffing the player’s units
These behaviours should create some interesting dynamics for the player. Do you try to take out the berserker first? They’re probably a bit squishier than the frontline soldier, but might be easier to manipulate or control. But while you focus on taking them down, the soldier is locking down your ability to move and setting up flanking for a melee assassin. And how do your tactics change if the enemies are bolstered by the support at the back constantly healing and providing buffs to the berserker?
But I’m getting ahead of myself. We’re a long way from implementing proper behaviours when the enemy just stands there doing nothing, waiting for the player to just waltz over at their leisure. It’s time to implement enemy AI.
Make them move
Previously, I created this flowchart to demonstrate how the game might work with regards to the player choosing their action vs an enemy AI choosing an action.

I’ve revised that flowchart to expand a bit on how the AI turn differs from the player turn.

We can see that there are several differences with how the AI turn flows in comparison to the player’s turn. In the player turn, we don’t need to do any battlefield analysis – the player does all that themselves. We need to provide the player with information only when they request it – e.g. there’s no point calculating all their movement options if they’re not going to choose to move. On the AI turn, however, we need to check what actions can be taken and then weight them according to that enemy’s behaviour, so we need to do a lot of the calculation and analysis up front as soon as the turn starts. With the hardware available today, this might not be a problem, but it’s something that I should keep an eye on.
For my first attempts at getting an enemy moving, I’m going to keep things very simple. I’m going to make the enemy move towards the nearest player combatant. The algorithm for this is very simple:
- Check which player combatant is closest
- Check which tiles this enemy can move to
- Calculate the distance to the nearest player combatant for each tile
- Order the list of tiles by the distance to the player
- Choose the one with the smallest distance
In the event that the enemy is next to a player, or has no action points remaining, they will choose to just end their turn.
With this algorithm implemented, the enemies start to move!

Saving and loading the game
Now that the enemies can move, it’s time to add the option to save the game and subsequently load it while there’s only a small amount of data. The main reason I wanted to tackle this now is so that I can incrementally add to the saved data whenever something that needs to be persisted comes along (e.g. health points, or limited use abilities), but it has had the added bonus of showing me that my new combat logic was too tightly coupled to my logic for rendering the game and so I’ve been able to address that.
I started with saving the following data to a statically named json file:
- Name of the current map (even though I only have one right now, I want to have specific maps for story quests, each with their own unique name)
- Combatant data (for each combatant):
- Name
- Initiative
- Allegiance
- Position
- Whether it is their turn
- How many action points are remaining
Some of this data may eventually be acquired elsewhere (e.g. player combatants will have name pulled from their character record), and I do want the player to be able to name their saves manually. This is done through a new menu.

Saving the data was relatively straightforward.
Loading the game, however, came with the need to make some bigger changes.

In order to make this work, I could have taken a bit of a shortcut and just implemented loading in the combat scene itself. However, I know that I will eventually need to load games that are on either the combat scene or the world map scene, so it makes sense to implement loading so that it can handle both scenarios rather than trying to shoehorn it in later.
To accommodate this, I’ve expanded my base Game scene so that it has an ActiveScreen control and a loading screen.

Whichever scene is currently being used for gameplace (combat or world map) will go into ActiveScreen when it’s running, and the Game node will handle swapping between the two. While data is being loaded in, the loading screen is set visible. Once the data has been loaded in and the scene rendered, the loading screen is hidden again and the player is free to interact with the active screen.
This approach also meant that I needed to change how the combat scene works. When I originally created it, I hard coded in some test data and the scene is built up from that. Now that data can be loaded in, when the combat scene is created, rather than just using the test data, it first checks to see if there is any loaded data. If so, it uses that data to build the scene. If not, it reverts back to the test data.

This took up quite a bit of my game dev time this week, but I believe it was the right approach and it’ll save me time in the long run. In addition to letting me load a combat from saved data, I should be able to load in quest data easily to build a new combat scene when I integrate combat with quests. I also won’t need to rip the logic out into a more central location when I start loading saves on the world map.
Actions speak louder than words
While looking after my daughter this weekend, I had an idea for how to architect actions, so that’s what I intend to try and build this week. Hopefully my idea is sound and I’ll be able to the Strike action with ease so that players and enemies can start attacking each other rather than just running around after each other like they’re playing a game of tag.