It’s time for me to move on to another part of my game. The world map definitely needs more work, but it’s just one part of the overall game. The other big part of an XCOM-inspired game – probably the main part – is the tactical combat, for which I intend to use the Pathfinder 2E rules. I think this part of the game, with its many moving parts and interactions between available actions, feats, different tokens, and the map itself is going to be the biggest challenge. Not to mention that there will need to be some kind of AI for the enemies the player fights against, and I also want to use procedural generation for non-story quests. The main saving grace is that it’s turn-based, so I don’t have to worry too much about optimisation.
There’s lots of opportunities to get myself confused and end up with a mess of spaghetti code, so I’ve settled on a couple of first steps – sketching out what I want to achieve, and considering the game’s architecture.
Initial UI Thoughts
I’ve played a lot of RPGs with tactical combat, so I’d like to think I have a reasonable idea of what should go on the UI. I’ve taken a lot of inspiration from games like Baldur’s Gate 3 and Dawnsbury Days.

To summarise this image and help you decipher my handwriting:
- Combat takes place on a grid of square tiles
- The grid has terrain on it – presumably this will be used in combat in some way, but I’ve not actually written anything about it on the image (spoiler alert: it definitely will)
- At the top of the screen is an initiative tracker, which displays the combatants in turn order
- The combatant whose turn it is (the active combatant) is indicated on the initiative tracker – my initial thought on how to do this is by making the box bigger and putting an arrow underneath it
- Each combatant on the initiative tracker has a health bar. Player health bars have a numeric value, but enemy ones do not
- The middle of the screen is mostly free of UI components so that the player can see the combat grid
- Players and enemies are represented on the map by circular images (tokens – a common thing in TTRPGs)
- Above each token is a health bar
- Clicking on player character tokens will give detailed character information, probably in some kind of popup
- The bottom of the screen displays a summary of the active character in a box on the left, including HP and action points remaining
- In the middle at the bottom is an action bar. This can be filtered, although what the filters are is uncertain
- On the right side is a combat log. The player will be able to hover over each line for more detailed information
As with the world map, that’s a lot of components! Unfortunately, that’s barely scratching the surface – there’s a lot of UI components without any details whatsoever, and it doesn’t even touch on implementing any of the rules of the game.
Designing the Code
Pathfinder 2E is a very crunchy system – it has lots of character options and rules about how those character options work in combat. Some actions can be triggers for other actions, or other characters getting to act outside their turn. Some actions are enhanced by feats and so work differently across different characters. In short, there is a lot going on, and there is a lot of potential to write very confusing code that cannot be easily extended or maintained.
I’ve reviewed my world map code and it is, quite honestly, a mess that needs refactoring. Part of making this combat scene is going to be trying out a different way of organising my game code. Once I have something I’m happy with, I’ll start refactoring the world map code whenever I feel a bit burned out on the combat scene.
Foundations
Let’s start with some basics. I want:
- Data for the combat scene to be stored in one location
- Each visual component (or view) is solely responsible for visual elements
- Game logic is separate from the visual and data layers
- The game logic is testable
- Files are arranged in logical manner
And let’s go into a bit more depth about these and why I think they’re important.
Data is stored in one location. This means there is a single source of truth for combat and we’ll know where to find our data when writing new components without having to do any searching. This doesn’t necessarily mean we won’t need to access data from other repos, however – adventurer stats and abilities will need to be available elsewhere in the game, so we might import those when we start a combat.
Each view/component is solely responsible for visual elements. The scripts that deal with rendering and animations should not contain any game logic or manipulate data. These scripts should pass inputs on to a different part of the code. Although I’m not really doing animation yet, I’ll put in that the visual components might also raise events when animations reach a specific frame.
Game logic is separate from the visual and data layers. This is an extension of the previous principle. The data layer, like the visual layer, should not be applying game logic. The data layer should set the data and broadcast changes
The game logic is testable. As I’ve already mentioned a few times, there are lots of different interactions going on. Where there are lots of interactions, there are many edge cases and a whole host of places where things could go wrong. As such, I want to be able to write automated tests so I can check that everything still works without having to try and engineer each situation in-game. I’m not hugely concerned about whether the visual elements are testable, or about getting 100% code coverage, however.
Files are arranged in a logical manner. It should be relatively easy to see what files belong with which component. I should not have to look far to find the script associated with a visual component or its state, or to find assets that are used in the scene.
From my experience as a software engineer, this looks like it would fit quite well into the MVVM design pattern.

In this pattern we have:
- View – responsible for visual elements, e.g. displaying data, playing animations, accepting user input. We might also have some basic validation checks here
- ViewModel – passes inputs from the view to the model and tells the view what to display based on data in the model
- Model – Uses inputs to manipulate the data and surfaces data
This seems like a good start. Each Godot scene with its attached script can act as a View with an attached ViewModel to maintain local state, and any logic, state, or data that needs to affect multiple Views can live in the Model, to be picked up by ViewModels.
I’m not necessarily going to rigidly stick to this – I see it as a stepping off point. Something to help me organise my code. If it ends up being a hindrance, I’ll revisit this decision and try something else.
File Structure
To make things easy to find, I’ve decided to layout my files in this manner.
| Game
|-- Config
|-- Helpers
|-- Screens
|-- {Screen}
|-- Domain
|-- {IRepo}.cs
|-- {Repo}.cs
|-- Components
|-- {Component1}
|-- Assets
|-- {Component1Image}.png
|-- {Component1}.cs
|-- {Component1}.tscn
|-- {Component2}
|-- {Component2}.cs
|-- {Component2}.tscn
|-- {Component2ViewModel}.cs
|-- {SubComponent1}
|-- {SubComponent1}.cs
|-- {SubComponent1}.tscn
|-- {SubComponent1ViewModel}.cs
| tests
- Game – this folder contains all the game code
- Config – game configuration files, e.g. base map data, quest data. Things that I might want to change without making a code change
- Helpers – extension methods, or other tools that might be useful across the entire game
- Screens – the different screens that will be in the game (e.g. the World Map is a screen, this Combat Scene is a screen). Within each screen is:
- Domain – the model layer. Things that persist across multiple views within a screen
- e.g. a Repo and an Interface
- Components – the visual components that make up the screen (e.g. this Combat screen will need an Initiative Tracker, a Map, etc.)
- The component scene (.tscn), script (.cs), and ViewModel live here
- Assets – any images, textures, etc. that the component needs
- SubComponents – Components that the parent needs
- Domain – the model layer. Things that persist across multiple views within a screen
This should keep everything that I need when working on a specific part of the game grouped close together so that I don’t have to go hunting through lots of folders to find it all.
Testing Concerns
I mentioned that I want to make sure my code is fairly easy to test, especially the game logic. To aid with this, I intend to use interfaces and dependency injection as much as possible. This will allow me to substitute mock testing objects in so that I can test specific circumstances easily.
To facilitate this, I am going to use two modules (and their dependencies) from ChickenSoft:
- AutoInject for dependency injection (interestingly, from a web dev perspective, this has parallels to a React context)
- GoDotTest for testing, which should be pretty obvious from the name
I may end up using more of their modules in the future since the authors have clearly put a lot of thought into them and they are all very well documented.
Progress?
As you might expect from the above, I’ve spent a lot more time researching and thinking about how to do things than actually building anything. But I have made a start on what I think will be the easiest component of the Combat screen – the Initiative Tracker.
I’ve started off by making my base screen node – the Combat node – and added a child, CombatUI, which, hopefully to no one’s surprise, will be responsible for all the UI elements.

And within CombatUI, I’ve added an InitiativeTracker, which is its own component. The InitiativeTracker instantiates a UnitSummary for each combatant.

To share data across the whole Combat screen, I’ve set up a CombatRepo with its own interface. I’ve also made a Combatant object with an interface, which will be responsible for storing data about each player adventurer and enemy monster in the combat and will also broadcast changes to those values.
So, with my new file structure, these fit in like so:

The CombatRepo is created in the top level component with some hard-coded player characters and a random number of monsters. Initiative is rolled and saved against each combatant. The InitiativeTracker gets the CombatRepo as part of its creation and passes it into the InitiativeTrackerViewModel, which grabs the combatants from the repo, sorts them from highest initiative to lowest, and then tells the view to display the result.

It’s definitely a bit basic. But it’s a start, and it works. So I’ll take it.