Advertisement
TyrannicGoat

Enemy AI State Machine Example

Mar 22nd, 2023 (edited)
957
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 3.53 KB | Source Code | 0 0
  1. //define method signatures for types of moves that can be assigned to AI
  2. //NOTE these could be impelemented as coroutines if you wanted them to be async
  3. public delegate void BasicMove(Actor user);
  4. public delegate void TargetMove(Actor user, Actor target);
  5.  
  6. //one concrete inheritor per enemy type (i.e. OrcActor, GoblinActor, TrollActor, ect)
  7. public abstract class AIActor : MonoBehaviour
  8. {
  9.     private Controller _controller;
  10.    
  11.     //this is where you would call the builder class to create your enemy (could also just implement it here)
  12.     protected abstract Controller BuildController();
  13.  
  14.     private void Awake()
  15.     {
  16.         _controller = BuildController();
  17.     }
  18.    
  19.     private void Start()
  20.     {
  21.         _controller.Init();
  22.     }
  23.    
  24.     private void Update()
  25.     {
  26.         _controller.Update();
  27.     }
  28. }
  29.  
  30. //one concrete implementor per enemy behavior type (i.e. ScoutBrain, GruntBrain, HeavyBrain, CustodianBrain, ect.)
  31. public abstract class EnemyController
  32. {
  33.     private FSM _fsm;
  34.    
  35.     private Actor _target; //this value would be resolved dynamically, probably through some sort of perception system
  36.     private Actor _owner; //this needs to be injected in the constructor
  37.    
  38.     private Dictionary<string, BasicMove> _basicMoves = new Dictionary<string, BasicMove>();
  39.     private Dictionary<string, TargetMove> _targetMoves = new Dictionary<string, TargetMove>();
  40.    
  41.     //this method would be where you define the states and transitions
  42.     public abstract FSM CreateStateMachine();
  43.    
  44.     public void Init()
  45.     {
  46.         //exact syntax for your state machine varies based on your choosen implementation
  47.         //I am assuming that you can assign states as coroutines though
  48.         _fsm = CreateStateMachine();
  49.         _fsm.Start();
  50.     }
  51.  
  52.     public void Update()
  53.     {
  54.         _fsm.Update();
  55.     }
  56.    
  57.     public void AssignMove(string move, BasicMove moveDelegate)
  58.     {
  59.         //don't assing same name to more than one move
  60.         if (_basicMoves.ContainsKey(move) || _targetMoves.ContainsKey(move))
  61.             return;
  62.        
  63.         _basicMoves.Add(move, moveDelegate);
  64.     }
  65.    
  66.     public void AssignMove(string move, TargetMove moveDelegate)
  67.     {
  68.         //don't assing same name to more than one move
  69.         if (_targetMoves.ContainsKey(move) || _basicMoves.ContainsKey(move))
  70.             return;
  71.        
  72.         _targetMoves.Add(move, moveDelegate);
  73.     }
  74.  
  75.     //this method would be used to convert the sync delegate into an async state so it can be added to the state machine
  76.     IEnumerator ExecuteMoveAsState(string move, float cooldown, Action<bool> successCallback)
  77.     {
  78.         if(!ExecuteMove(move))
  79.             successCallback?.Invoke(false);
  80.         yield return new WaitForSeconds(cooldown);
  81.         successCallback?.Invoke(true);
  82.     }
  83.      
  84.     bool ExecuteMove(string move)
  85.     {
  86.          if (_basicMoves.ContainsKey(move))
  87.         {
  88.             _basicMoves[move](_owner);
  89.         }
  90.         else if (_targetMoves.ContainsKey(move))
  91.         {
  92.             if (_target == null)
  93.             {
  94.                 successCallback?.Invoke(false);
  95.             }
  96.             else
  97.             {
  98.                 _targetMoves[move](_owner, _target);
  99.             }
  100.         }
  101.         else
  102.         {
  103.             //throw exception because AI is trying to execute a move that it doesn't have
  104.             throw new KeyNotFoundException();
  105.         }
  106.     }  
  107.    
  108.     //could also implement any common enemy functionality here like target selection, perception, movement, pathfinding, ect.
  109. }
  110.  
Tags: Unity
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement