Making simple AI states in Unity3d
My implementation of AI state machine. It relies on nested inherited classes.
/*===============================================================
Product: Utilities
Developer: Dimitry Pixeye - pixeye@hbrew.store
Company: Homebrew - http://hbrew.store
Date: 26/04/2017 10:55
================================================================*/
using UnityEngine;
using System.Collections.Generic;
namespace Homebrew{
public abstract class BasicAI<T> : MonoBehaviour {
[System.Serializable]
public abstract class AIState
{
protected T AI;
public string ID;
public AIState(T AI)
{
this.AI = AI;
}
/// <summary>
/// Logic loop. The action itself goes here
/// </summary>
public abstract void Update();
/// <summary>
/// Checks if we need to kill the current state
/// </summary>
/// <returns></returns>
public abstract bool EndStateCondition();
/// <summary>
/// Use to reset some variables / set next state or set state to null
/// </summary>
public abstract void End();
/// <summary>
/// Some initial setups or actions that happen ONCE when the state becomes active.
/// </summary>
public virtual void Start() { }
}
public List<AIState> states = new List<AIState>();
public AIState currentState;
public void SwitchToState(string ID)
{
var state = states.Find(s => s.ID == ID);
currentState = state;
if (currentState != null)
currentState.Start();
}
protected virtual void Update()
{
if (currentState != null)
{
if (currentState.EndStateCondition())
{
currentState.End();
return;
}
currentState.Update();
}
}
}
}
It’s a initial AI script you inherit from. It contains nested class AIState that we will use to create our custom states.
AIState
Members:
- ID - a string name of the state. Is used to get other states from list.
Methods:
- Update - Logic loop. The action of the state itself goes here.
- EndStateCondition - The way to know if we don’t need state anymore.
- End - The end method of state. Triggers after positive EndStateCondition
- It’s important to note that you have to define ether you want to switch to the next state or set it to null.
- Start - Triggers once after new state set.
**BasicAI
Members:
- states - A list of all states to look. Add new states to the list.
- currentState - a current state in action.
Methods:
- SwitchToState(string ID) - will try to switch to a state with provided ID. If not null triggers state start method.
An example from Battlecruiser:
/*===============================================================
Product: Battlecruiser
Developer: Dimitry Pixeye - pixeye@hbrew.store
Company: Homebrew - http://hbrew.store
Date: 26/04/2017 11:02
================================================================*/
/*===============================================================
Example realisation
Create special netested classes of your states and inherit them from AIState
================================================================*/
using System;
using UnityEngine;
using DG.Tweening;
namespace Homebrew{
public class SalvageDroneAI : BasicAI<SalvageDroneAI> {
public Transform model;
public Transform targetRef;
#region STATES
public class LeaveBase : AIState
{
bool leftTheBase = false;
public LeaveBase(SalvageDroneAI ai): base(ai)
{
ID = "LeaveBase";
}
/// <summary>
/// Reseting values
/// </summary>
public override void End()
{
leftTheBase = false;
AI.SwitchToState("FlyToTarget");
}
public override bool EndStateCondition()
{
return leftTheBase;
}
public override void Update()
{
}
public override void Start()
{
Debug.Log("Leaving my parent ship. Goodbye!");
leftTheBase=true;
}
}
public class FlyToTarget : AIState
{
public FlyToTarget(SalvageDroneAI ai): base(ai)
{
ID = "FlyToTarget";
}
public override void End()
{
throw new NotImplementedException();
}
public override bool EndStateCondition()
{
return false;
}
public override void Update()
{
}
public override void Start()
{
//AI.TargetRef
if (AI.targetRef==null)
Debug.Log("I'm on my way! To...err where am I going?!");
else
Debug.Log("I'm on my way to the " + AI.targetRef.name);
}
}
#endregion
protected override void Create()
{
base.Create();
states.Add(new LeaveBase(this));
states.Add(new FlyToTarget(this));
}
private void OnEnable()
{
SwitchToState("LeaveBase");
}
private void OnDisable()
{
}
}
}
You can take the script from Github
Follow me at my Twitch channel where I’m showing creation process of the Battlecruiser.
Comments