preface

This article is referenced from:

  • Unity3d College – Unity3D AI with State Machine (FSM), Drones, and Lasers! (Video tutorial)
  • Game Design Patterns — State Patterns
  • Game Programming Patterns – State

After reading this article, check out the links above.

Sample project used in this article: FINCTIVE/ lost-in-the-wilders-Nightmare Welcome Star!

Due to the limited level, the content of the article may be wrong, welcome to discuss, exchange, or direct criticism. ┗ | ` O ‘| ┛

Author of this article: FINCTIVE Email: [email protected]

Please mark the original link and author’s name for reprinting, thank you.

Issued in original language finch: www.yuque.com/finctive/ga…

Application scenarios

In The Wild: Nightmare, enemies behave like this (run the demo online) :


It looks like a big if{… }else if{… }else{… } statement implementation, but after the actual hands-on development I found……

Cut to the chase: A state refers to a series of behaviors of AI, such as the static, chase, and self-explosion states in this project, which can be described by a class. For a state, you should put the handling code in a class. For example, code related to the “chase the player” state should not be written to classes in other states.

The solution

Screenshot of enemy AI gameobject



The base class

public abstract class BaseState : MonoBehaviour
{
	// Perform the related operation of this state, return the state of the next game loop
    public abstract BaseState Tick();
    // Initialization code associated with this state
    public virtual void OnStateStart(){}
    // Exit code associated with this state
    public virtual void OnStateExit(){}}Copy the code

The state machine

public class StateMachine : MonoBehaviour
{
    public BaseState defaultState;
    [HideInInspector]public BaseState currentState;

    private void Awake()
    {
        currentState = defaultState;
    }

    void FixedUpdate()
    {
        BaseState nextStateType = currentState.Tick();
        if (nextStateType != currentState)
        {
            nextStateType.OnStateStart();
            currentState.OnStateExit();
        }
        currentState = nextStateType;
    }
}
Copy the code

I wrote the control scripts associated with all states in the EnemyController component, exposing public methods to be invoked by the state machine script. This allows code to be reused and allows the logic code of the state machine to take care of only one higher level of control, regardless of the details.

Here’s the code for chasing state, as well as other states.

public class EnemyChasingState : BaseState
{
    public EnemyAttackingState enemyAttackingState;
    public EnemyIdlingState enemyIdlingState;
    
    private EnemyController _enemyController;

    private void Awake()
    {
        _enemyController = GetComponent<EnemyController>();
    }
    private static readonly int AnimMove = Animator.StringToHash("move");
    public override BaseState Tick()
    {
        Vector3 targetPos = PlayerController.playerTransform.position;
        _enemyController.MoveToTarget(targetPos);
        
        float distanceSqrMag = (targetPos - transform.position).sqrMagnitude;
        // Close enough to attack (self-destruct)
        if(distanceSqrMag < _enemyController.enemyInfo.startAttackingDistance*_enemyController.enemyInfo.startAttackingDistance)
        {
            return enemyAttackingState;
        }
        
        // The distance is too far, give up the chase
        if(distanceSqrMag > _enemyController.enemyInfo.stopChasingDistance*_enemyController.enemyInfo.stopChasingDistance)
        {
            return enemyIdlingState;
        }
        return this;
    }

    public override void OnStateExit()
    {
        _enemyController.modelAnimator.SetFloat(AnimMove, 0f); }}Copy the code

Author: FINCTIVE([email protected]) Welcome to reprint, please attach the original link and the author’s name, thank you!