制作角色AI必用?!速通有限状态机

欢迎加入光光的奇妙冒险,我是你们的煎饼光子老师。

这期我们来速通一套有限状态机框架

我认为一个有限状态机必须要满足这三个条件

如果结合代码说就是

1.枚举表示的状态类型

2.当前处于的状态

3.通过Switch等逻辑去切换状态

首先我们创建一个FSM,也就是我们的有限状态框架

在代码中我已经给出了详细的注释

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//状态类型用枚举表示
public enum E_StateType
{
    Idle,Walk
}

//状态接口
public interface IState
{
    void OnEnter();
    void OnUpdate();
    void OnExit();
    // void OnFixedUpdate();
    // void OnCheck(); 
}

[System.Serializable]
public class Blackboard
{
    //此处存储共享数据,或向外展示的数据,可配置的数据
}
public class FSM
{
    public IState currentState;//当前状态
    public Dictionary<E_StateType, IState> stateDic;//状态字典
    public Blackboard blackboard;//共享信息的黑板
    public FSM(Blackboard blackboard)
    {
        stateDic = new ();
        this.blackboard = blackboard;
    }

    /// <summary>
    /// 切换状态
    /// </summary>
    /// <param name="stateType"></param>
    public void SwitchState(E_StateType stateType)
    {
        if(!stateDic.ContainsKey(stateType))
        {
            return;
        }
        else
        {
            //如果当前状态不为空,则调用OnExit
            if(currentState!=null)
                currentState.OnExit();
            currentState=stateDic[stateType];
            currentState.OnEnter();
        }
    }

    /// <summary>
    /// 添加状态
    /// </summary>
    /// <param name="stateType"></param>
    /// <param name="state"></param>
    public void AddState(E_StateType stateType, IState state)
    {
        if(!stateDic.ContainsKey(stateType))
        {
            stateDic.Add(stateType, state);
        }
    }

    public void OnUpdate()
    {
        currentState.OnUpdate();
    }

    // public void OnFixedUpdate()
    // {
    //     currentState.OnFixedUpdate();
    // }

    // public void OnCheck()
    // {
    //     currentState.OnCheck();
    // }
}

接着我们来实际使用一下这个有限状态机框架 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//为某个对象专门创建一个黑板
[System.Serializable]
public class MyBlackboard:Blackboard
{
    public Animator anim;
    public Transform transform;//在外面关联某个对象的Transform
    public Vector2 targetPos;
    public float idleTime;
    public float moveSpeed;
}
public class IdleState : IState
{
    private float idleTimer;
    private FSM fsm;
    private MyBlackboard blackboard;

    //构造函数
    public IdleState(FSM fSM)
    {
        this.fsm = fSM;
        this.blackboard = fSM.blackboard as MyBlackboard;
    }
    
    public void OnEnter()
    {
        idleTimer = 0;
        blackboard.anim.Play("Idle");
    }

    public void OnExit()
    {
        
    }

    public void OnUpdate()
    {
        idleTimer += Time.deltaTime;
        if(idleTimer > blackboard.idleTime)
        {
            fsm.SwitchState(E_StateType.Walk);
        }
    }
}
public class WalkState : IState
{    
    private FSM fsm;
    private MyBlackboard blackboard;    

    //构造函数
    public WalkState(FSM fSM)
    {
        this.fsm = fSM;
        this.blackboard = fSM.blackboard as MyBlackboard;
    }
    public void OnEnter()
    {
        float randomX=Random.Range(-5,5);        
        blackboard.targetPos = new Vector2(blackboard.transform.position.x+randomX,blackboard.transform.position.y);
        blackboard.anim.Play("Walk");
    }

    public void OnExit()
    {
        
    }

    public void OnUpdate()
    {
        if(Vector2.Distance(blackboard.transform.position,blackboard.targetPos)<0.1f)
        {
            fsm.SwitchState(E_StateType.Idle);
        }
        else
        {
            blackboard.transform.position=Vector2.MoveTowards(blackboard.transform.position,blackboard.targetPos,Time.deltaTime*blackboard.moveSpeed);
        }
    }
}

public class MyAI : MonoBehaviour
{
    private FSM fsm;
    public MyBlackboard blackboard;
    void Start()
    {        
        fsm = new FSM(blackboard);
        fsm.AddState(E_StateType.Idle, new IdleState(fsm));
        fsm.AddState(E_StateType.Walk, new WalkState(fsm));
        fsm.SwitchState(E_StateType.Idle);               
    }
    private void Update() 
    {
        fsm.OnUpdate();
        Flip();
    }
    void Flip()
    {
        if(blackboard.targetPos!=Vector2.zero)
        {
            if(blackboard.targetPos.x>blackboard.transform.position.x)
            {
                transform.localScale=new Vector2(1,1);
            }
            else
            {
                transform.localScale=new Vector2(-1,1);
            }
        }
    }    
}

猜你喜欢

转载自blog.csdn.net/Blueberry124/article/details/142423891