Unity C#简易的敌人状态机,学习日记

在网上查阅了很多资料,然后根据一些自己的需求进行了一些修改。

需要的是:状态父类,状态机系统(增删状态等管理状态类),一个敌人单位的控制类(继承MonoBehaviour)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//敌人状态类型
public enum Enemy_StateID
{
    NullStateID=0,
    Idle,
    Patrol,
    Attack,
    Skill,
    Execute,
    Trace,
}
//敌人状态转化
public enum Enemy_Transition
{
    NullTransition=0,
    Idle,
    Patrol,
    Attack,
    Skill,
    Execute,
    Trace,
}
//状态机系统
public class EnemyFSMSystem 
{

    private List<EnemyFSMState> states;

    public EnemyManager manager;
    private Enemy_StateID currentStateID;
    public Enemy_StateID CurrentStateID { get { return currentStateID; } }
    private EnemyFSMState currentState;
    public EnemyFSMState CurrentState { get { return currentState; } }

    public EnemyFSMSystem()
    {
        states = new List<EnemyFSMState>();

    }



    /// <summary>
    /// 添加状态
    /// </summary>
    public void AddState(EnemyFSMState s)
    {
        // Check for Null reference before deleting
        if (s == null)
        {
            Debug.LogError("FSM ERROR: Null reference is not allowed");
        }

        // 第一个状态默认为初始状态
        if (states.Count == 0)
        {
            states.Add(s);
            currentState = s;
            currentStateID = s.ID;
            return;
        }

        // 如果有重复状态则报错
        foreach (EnemyFSMState state in states)
        {
            if (state.ID == s.ID)
            {
                Debug.LogError("FSM ERROR: Impossible to add state " + s.ID.ToString() +
                               " because state has already been added");
                return;
            }
        }
        s.system = this;
        Debug.Log(s.system);
        states.Add(s);
    }

    /// <summary>
    /// 删除状态
    /// </summary>
    public void DeleteState(Enemy_StateID id)
    {
        // 检测为空,报错
        if (id == Enemy_StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
            return;
        }

        // 搜索到就删除
        foreach (EnemyFSMState state in states)
        {
            if (state.ID == id)
            {
                states.Remove(state);
                return;
            }
        }
        Debug.LogError("FSM ERROR: Impossible to delete state " + id.ToString() +
                       ". It was not on the list of states");
    }

    /// <summary>
    /// 执行转换,必须通过转换改变状态
    /// </summary>
    public void PerformTransition(Enemy_Transition trans)
    {
        if (trans == Enemy_Transition.NullTransition)
        {
            Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
            return;
        }

        // Check if the currentState has the transition passed as argument
        Enemy_StateID id = currentState.GetOutputState(trans);
        if (id == Enemy_StateID.NullStateID)
        {
            Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
                           " for transition " + trans.ToString());
            return;
        }

        // Update the currentStateID and currentState		
        currentStateID = id;
        foreach (EnemyFSMState state in states)
        {
            if (state.ID == currentStateID)
            {
                // Do the post processing of the state before setting the new one
                currentState.DoBeforeLeaving();

                currentState = state;

                // Reset the state to its desired condition before it can reason or act
                currentState.DoBeforeEntering();
                break;
            }
        }

    }

状态父类,用于其他状态类继承

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

public class EnemyFSMState 
{
    protected Dictionary<Enemy_Transition, Enemy_StateID> map = new Dictionary<Enemy_Transition, Enemy_StateID>();
    protected Enemy_StateID stateID;
    public EnemyFSMSystem system;
    public Enemy_StateID ID { get { return stateID; } }

    public void AddTransition(Enemy_Transition trans, Enemy_StateID id)
    {
        // Check if anyone of the args is invalid
        if (trans == Enemy_Transition.NullTransition)
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
            return;
        }

        if (id == Enemy_StateID.NullStateID)
        {
            Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
            return;
        }

        // Since this is a Deterministic FSM,
        //   check if the current transition was already inside the map
        if (map.ContainsKey(trans))
        {
            Debug.LogError("FSMState ERROR: State " + stateID.ToString() + " already has transition " + trans.ToString() +
                           "Impossible to assign to another state");
            return;
        }

        map.Add(trans, id);
    }

    /// <summary>
    /// This method deletes a pair transition-state from this state's map.
    /// If the transition was not inside the state's map, an ERROR message is printed.
    /// </summary>
    public void DeleteTransition(Enemy_Transition trans)
    {
        // Check for NullTransition
        if (trans == Enemy_Transition.NullTransition)
        {
            Debug.LogError("FSMState ERROR: NullTransition is not allowed");
            return;
        }

        // Check if the pair is inside the map before deleting
        if (map.ContainsKey(trans))
        {
            map.Remove(trans);
            return;
        }
        Debug.LogError("FSMState ERROR: Transition " + trans.ToString() + " passed to " + stateID.ToString() +
                       " was not on the state's transition list");
    }

    /// <summary>
    /// This method returns the new state the FSM should be if
    ///    this state receives a transition and 
    /// </summary>
    public Enemy_StateID GetOutputState(Enemy_Transition trans)
    {
        // Check if the map has this transition
        if (map.ContainsKey(trans))
        {
            return map[trans];
        }
        return Enemy_StateID.NullStateID;
    }

    /// <summary>
    /// 进入状态时执行
    /// </summary>
    public virtual void DoBeforeEntering()
    {
    }

    /// <summary>
    ///离开状态时执行
    /// </summary>
    public virtual void DoBeforeLeaving() { }

    /// <summary>
    /// 在此状态执行
    /// </summary>
    public virtual void StateUpdate()
    {

    }
}

状态类,就拿待机状态举个例子

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyIdleState : EnemyFSMState
{

    public EnemyIdleState()
    {
    	//赋予此状态对应的枚举ID
        stateID = Enemy_StateID.Idle;
        //添加转化,给予一个可以进入Trace状态的一个转化。
        AddTransition(Enemy_Transition.Trace, Enemy_StateID.Trace);
    }
    public override void DoBeforeEntering()
    {

    }
    public override void DoBeforeLeaving()
    {
    }
    
    public override void StateUpdate()
    {
    	//通过状态及系统获取敌人控制类里的方法来判断条件是否达成
        if (system.manager.IsTracePlayer())
        {
        	//进入转化
            system.PerformTransition(Enemy_Transition.Trace);
        }
    }
}

敌人控制类

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

public enum EnemyType
{
    Test
}
public class EnemyManager : MonoBehaviour
{
    private EnemyMessage message;
    /// <summary>
    /// 敌人信息
    /// </summary>
    public EnemyMessage Message { get { return message; } }

    private EnemyFSMSystem fsmSystem;

    private float speedUPTimer = 0;
    private Animator enemy_Animator;
    private bool isGround;
    public bool IsGround { get { return isGround; } }
    private GameObject player;
    [SerializeField] private float traceDistance = 5f;

    public void Awake()
    {
        player = GameObject.FindGameObjectWithTag("Player");
        message = GetComponent<EnemyMessage>();
        //新建一个状态机系统
        fsmSystem = new EnemyFSMSystem();
        //将此脚本引入进去,这样状态类执行时就可以通过状态机系统调用EnemyManager的方法
        fsmSystem.manager = this;
        //新建一个待机状态
        EnemyFSMState idleState = new EnemyIdleState();
        //将待机状态导入进状态机系统
        fsmSystem.AddState(idleState);
        //将状态里面添加进入状态机系统
        idleState.system = fsmSystem;
      
        EnemyFSMState traceState = new EnemyTraceState();
        fsmSystem.AddState(traceState);
        traceState.system = fsmSystem;
        
    }
    private void FixedUpdate()
    {
    	//通过状态机系统去调用当前状态的StateUpdate
        if (fsmSystem != null)
            fsmSystem.CurrentState.StateUpdate();
      
    }
    public void SelectInit(EnemyType type)
    {
        switch (type)
        {
            case EnemyType.Test:

                break;
            default:
                break;
        }
    }
   //玩家是否靠近追踪范围
    public bool IsTracePlayer()
    {
        if ((transform.position - player.transform.position).magnitude < traceDistance)
        {
            return true;
        }
        return false;
    }

    public void TracePlayer()
    {
        transform.position = Vector3.MoveTowards(transform.position, player.transform.position, Time.deltaTime * message.Walkspeed);
    }
}

当然我这个写的很菜,很多方法不应该写到Enemymanager里面,应该是通过manager去获取其他对应的功能类的方法,还有很多地方需要改进

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值