Skip to content

Khemitron Industries

Amateur Game Dev, Gaming, and TTRPGs

Menu
  • Home
  • Game Dev
  • About
Menu

Taking Turns in Combat

Posted on 2025-03-10

An important part of a turn-based tactics game is the ability to take turns. A shocking revelation, I know, but stay with me. For my game I obviously need to let the player take their turn and then have the computer control the enemies before handing back control to the player for their next turn, and so on. I’ve been quite busy with other things this week, so I’ve not made as much progress as I’d like, but I have implemented the concept of taking turns into my game and the idea that the player doesn’t control everything.

Differentiating friend and foe

In my last post, I’d set up an initiative tracker with all the combatants and their initiatives displayed on it. This was a good start, but it was difficult to tell which units belong to the player and which units are the cunning foes that the player needs to fight against. Fortunately, that’s a relatively simple fix. I created two different types of combatant and gave them different allegiances, and then changed the UI to display player-controlled creatures in green, and enemy creatures in red.

The code for this is relatively straightforward.

public enum Allegiance
{
  Player,
  Enemy
}

// combatant takes allegiance as a parameter when it is created
public class Combatant(Allegiance allegiance)
{
  // other properties

  public Allegiance Allegiance {get; set;} = allegiance
}

public partial class UnitSummary : Control
{
  // background colour is set using the ColorRect Godot component
  private ColorRect BackgroundColour;

  // function called by the UnitSummaryViewModel
  public void SetAllegiance(Allegiance allegiance)
  {
    switch (allegiance)
    {
      case Allegiance.Player:
      {
        BackgroundColour.Color = COMBAT_CONSTANTS.PLAYER_COLOUR;
        break;
      }
      case Allegiance.Enemy:
      {
        BackgroundColour.Color = COMBAT_CONSTANTS.ENEMY_COLOUR;
        break;
      }

    }
  }
}

This is also easily extendable if I want to introduce other factions, such as computer-controlled player allies, or neutral creatures, or a separate faction of enemies. I would probably use a dictionary to map the allegiances to different colours at that point instead of a switch statement.

It’s my turn now!

So what about taking turns?

Well, you may have noticed in the image above that Monster 1’s summary box is larger than the others and has a triangle underneath it.

That size difference and the triangle is the turn indicator. I wanted it to be obvious whose turn it is just by looking at this one part of the UI, and this was a quick and simple way to do so. In the same vein, I’ve added an animation when the turn changes so that the size doesn’t change in a jarring fashion, and the indicator arrow pulses to bring attention to the change.

The initiative tracker indicates whose turn it is

The code for changing turns is, once again, fairly simple.

// turn order is initially combatants orded by initiative descending
private List<ICombatant> TurnOrder;
private ICombatant ActiveCombatant;

public void EndTurn()
{
  // remove active combatant from turn order 
  //(they are at the top of the list)
  TurnOrder.Remove(ActiveCombatant);
  // add active combatant to turn order again 
  //(this places them at the bottom of the list)
  TurnOrder.Add(ActiveCombatant);

  // next combatant is now at the top of the list, so grab them
  ActiveCombatant = TurnOrder[0];
  // and start their turn
  ActiveCombatant.StartTurn();
}

I briefly considered using a Queue instead of a List, but:

  1. I might want to add in new combatants as reinforcements arrive
  2. The Pathfinder 2E ruleset lets combatants delay their turns and reinsert elsewhere

Both of these requirements mean I need the ability to insert combatants at specific positions, which a queue, to my knowledge, does not allow.

AI vs Player

Next, I needed to get the computer to take its turns without player input. The requirement here is that if a combatant is not one of the player’s characters, the computer needs to control it. Otherwise, the player needs to be able to choose actions from the UI. To facilitate this, I set up the concept of a Turn Controller, which will be responsible for orchestrating the turn.

This flowchart shows how the game should behave at the start of a turn

At the moment, I have no actions beyond end turn, so the AI just waits for a second so that I can see the initiative tracker animation and then ends its turn automatically. When it’s a player’s turn, the End Turn button is enabled and I have to manually end the turn. It’s not sophisticated, but it is a good start.

Combat logs

Another thing I managed to sneak in is the combat log. I think this will be a very useful tool, both for myself debugging the game, and for the players who want to thoroughly analyse their tactics. Since almost every action will need to go in the log, I think that implementing it early and expanding on it will be a much better development choice than trying to shoehorn it in at the end.

The combat log sits in the bottom right of the screen and displays actions taken during the fight

Currently it just shows that turns start and end, which isn’t very exciting. I plan to expand on it by adding tooltips when the player hovers over certain parts of a log – e.g. hovering over the creature name might show a summary or highlight it on the map, while hovering over the result of a roll would show the raw number from the dice and the bonuses and penalties applied to the roll.

With these building blocks in place, I think it’s time to put the combatants on some kind of map and start moving them around. Since I’ve already had quite a bit of experience building maps with my world map, I should be able to make a good start.

Share on Social Media
facebook tumblr reddit emailwhatsapp

Like this:

Like Loading...

Recent Posts

  • Refactoring the World Map 2025-06-09
  • Using Themes to Enhance my Game 2025-05-19
  • Quality of Life Improvements – Nested Tooltips 2025-05-12
  • Improving Quality of Life 2025-05-05
  • Godot4.4 – Powerful Localisation with gettext 2025-04-27
©2025 Khemitron Industries | Design: Newspaperly WordPress Theme
%d