Making simple AI states in Unity3d

2 minute read

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