How to Make a Turn-Based Combat System with Multiple Opponents & Players?

Godot Version

4.5.1

Question

Hello! So I followed Ayrton Alexis’s video, Simple Turn-Based Game Tutorial, on how to make a simple turn-based combat system. Their tutorial is awesome, but they only show how to make a turn-based system with one player and one enemy.

I’m currently working with three players and two enemies at the moment. When it comes to the video around the 34 minute mark- it shows the Change Turn function- I was wondering if anyone had any idea on how to adjust the function for multiple turns.

This is what my script looks like.

What I am talking about is probably super vague, so if more information is need just lmk!

There is a variety of ways you can do this and it also depends on your game rules. It will also depend on if you have different numbers of enemies compared to players etc.

Lets suppose you can have 3 players, and five enemies in one particular set up, and turns always go a players turn, then an enemies turn. (Again you may have weighted ordering where a players turn can be followed by another players turn).

Then I would have two arrays, one for players, and one for enemies.

var enemies_play_order: Array = [enemy1, enemy2, enemy3, enemy4, enemy5]
var players_play_order: Array = [player1, player2, player2]

Where enemy1 etc and player1 etc are node references to that entities controller. When an enemy or player is killed you would delete them from the turn order. If either turn order list is empty, then the battle is over.

Now you can keep an index for both lists:

var enemy_turn_index: int = 0
var player_turn_index: int = 0

Now in your turn_manager (or wherever you are doing your turns) do something like:

var is_players_turn: bool = true

func get_next_player() -> Node:
   if is_players_turn:
      is_players_turn = false
      enemy_turn_index = (enemy_turn_index + 1) % enemies_play_order.size()
      return enemies_play_order[enemy_turn_index ]
   else:
      is_players_turn = true
      player_turn_index= (player_turn_index+ 1) % players_play_order.size()
      return players_play_order[player_turn_index]

Now you can get the next player and get them taking their turn like this:

   var next_player: Node = get_next_player()
   next_player.take_turn()

This is just me typing, so you will have to add some more checks in there like ‘are there any players left’ or ‘are there any enemies left’ etc. You will also have to have a game_manager to make decisions about how many enemies you will have, and how many ‘players’ are playing etc.

You should also make your turn_manager ONLY deal with turns. In your code you have things like hide_options_menu in the players turn, and state controls in the enemies turn. This is very messy and you should refactor it now, since you are going beyond this simple example code.

Anyway, as I said before it depends on your game rules how complex you make this. If you want a turn queue where players can affect other enemy turn priorities, this would involve creating a turn_queue which is a single array, or if you want a dazed enemy to miss a turn etc you may want a weighted dictionary that is sorted on each turn after weights are adjusted. It all depends on your game rules, but I hope this approach has helped in some way.

4 Likes

Hello! Thank you for taking some time to respond! This helps out a lot and points me in a direction I hadn’t known existed beforehand. Thanks again!

1 Like