Should AI logic have its own scene / node?

Godot Version

4.4

Question

I work on my first project, turn based tactical game on grid.
I have following scene structure so far:

  1. Main Scene called BattleBoard.
    It can instantiate unit scene
    It has child node TileMap with a grid
    It has child node for UI
    In general, player actions related to selecting, moving, attack orders

  2. Unit scene
    It has many inherited scenes for specific actual units, like tanks and soldiers (they will hold actual sprites, sounds, animations, unit stats and specific attack logic, like instantiating projectiles)
    By itself, it acts like an interface that inherited scenes are implementing.

It works generally quite well so far, but I do not know what would be best practice to organize AI logic , that would control how enemy soldiers are moving and attacking.

So far I have this:

  1. Player moves their units and clicks End Turn in BattleBoard.
  2. BattleBoard has a method that will trigger (one by one) AI_Activate that sits in Unit scene. By default it is empty, but each enemy like Melee Brawler will override this method with a sequence action that says for example “move to closest player unit”, “attack” and “retreat”. Since I do not want to keep complicated logic in actual units like Brawler, they just store a pattern of this sequence and actual implementation of them sits in Unit scene, so every enemy can invoke them.

This is not ideal because for once, Unit scene needs to have access to state of the game that sits in BattleBoard and its children Tiles. And such structure causes me to use signal to go both up and down. Example:
Logic for AI turn sits in Brawler → Brawler attacks → uses Unit attack method → signals up to BattleBoard that it should move Brawler to position X and perform attack, BattleBoard checks if actions are valid, then performs attack (going back to Unit->Brawler to see if it needs to instantiate projectiles etc and then making actual attack there, waiting for signal up that this is finished), then signal down back to Brawler that action was fully done.

I think I have a wrong place to organize AI logic. It feels instead of signaling up and down like crazy, I should be calling the moves from some other place. But if I have all AI logic in BattleBoard, then it becomes a very big , very complicated scene with massive script . Should I add some node in between ?

You probably already have a Player class that holds all input logic etc. I would make this class an abstract class that is extended by 2 classes: HumanPlayer and ComputerPlayer (or AiPlayer, whatever). The HumanPlayer would be your old Player class with all the input logic like you have today. And the ComputerPlayer would be a new class that holds all AI logic. The logic should be written in a way as if the player does all of the actions, just automated. Any Unit-specific action logic can still be on the Unit class, but whatever related to actually performing these actions should be on the ComputerPlayer class.
Hope that makes sense. That’s how I implemented it in my turn based game at least.

1 Like

Thank you, I will try it

Right now I have a class BattleCursor that handles user input like clicks and sends singals to BattleBoard (for example it handles left click on the tile, recognizes which hex this is , based on position ,and then BattleBoard will know that user wants to select a unit etc).

So I will make an abstact class Player (which will be mostly empty) , make the BatteCursor the extention of it. At the same time , I will do another extension of Player, call it ComputerPlayer. And it will be emitting the same signals as it human player was clicking. But instead of reading from the mouse input, those will be predefined actions.

This sounds like a good plan , I will try it out today evening and if I have no followup questions, will mark as solved :slight_smile:

1 Like