【Unity】Finite State Machine 有限状态机代码注释解析

发表于2018-01-06
评论0 554浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏程序行业精英群

711501594
本篇文章是翻译了Unity官方Wiki有限状态机的代码注释部分。出于学习目的,修改了有限状态机中部分注释和调试输出等内容,希望可以有助于大家去理解有限状态机。
版权归原文所有,仅供大家学习使用。

FSMSystem.cs
using System;  
using System.Collections;  
using System.Collections.Generic;  
using UnityEngine;  
/// <summary>  
/// 脚本功能:状态机系统,用于控制战斗系统中角色和敌人的状态转换  
/// 添加对象:无  
/// 创建时间:2015年6月12日16:39:02  
/// 知识要点:  
/// 1. 状态机框架  
/// 2. 虚方法  
/// 3. 抽象类、抽象方法  
/// 4. 枚举  
/// 补充说明:  
///    在回合制战斗系统中,状态的转换比较规整,状态机体现的优势不大。  
///    对于多人不同时的半回合制战斗系统,状态机将发挥一点作用。  
///    对于行为复杂的实时战斗系统,状态机将发挥重要作用。  
/// </summary>  
// 状态转换  
public enum Transition  
{  
    NullTransition = 0, // 系统中不存在转换  
    // 需要根据实际应用继续扩展  
}  
// 状态ID  
public enum StateID  
{  
    NullStateID = 0,    // 系统中不存在状态  
    PlayerMove = 2,     // 玩家战斗移动状态  
    PlayerAttack = 4,   // 玩家战斗攻击状态  
    EnemyMove = 6,      // 敌人战斗移动状态  
    EnemyAttack = 8,    // 敌人战斗攻击状态  
}  
// 转换信息类:  
public class TransInfo  
{  
    public string comment;  
}  
/// <summary>  
/// 状态机中的状态类:以字典的形式保存状态的转换  
/// 1. Reason() 决定触发哪个转换  
/// 2. Act() 决定NPC在当前状态下的行为  
/// </summary>  
public abstract class FSMState  
{  
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();  // 状态转换映射  
    protected StateID stateID;                     // 状态ID  
    public StateID ID { get { return stateID; } }  // 获取当前状态ID  
    /// 添加转换  
    public void AddTransition(Transition trans, StateID id)  
    {  
        // 空值检验  
        if (trans == Transition.NullTransition)  
        {  
            Debug.LogError("FSMState ERROR: 不能添加空转换");  
            return;  
        }  
        if (id == StateID.NullStateID)  
        {  
            Debug.LogError("FSMState ERROR: 不能添加空状态");  
            return;  
        }  
        // 检查是否已经有该转换  
        if (map.ContainsKey(trans))  
        {  
            Debug.LogError("FSMState ERROR: 状态 " + stateID.ToString() + " 已经包含转换 " + trans.ToString() + "不可添加另一个状态");  
            return;  
        }  
        map.Add(trans, id);  
    }  
    /// 删除状态转换  
    public void DeleteTransition(Transition trans)  
    {  
        // 空值检验  
        if (trans == Transition.NullTransition)  
        {  
            Debug.LogError("FSMState ERROR: 不能删除空转换");  
            return;  
        }  
        // 检验是否有配对的转换  
        if (map.ContainsKey(trans))  
        {  
            map.Remove(trans);  
            return;  
        }  
        Debug.LogError("FSMState ERROR: 转换 " + trans.ToString() + " - 状态 " + stateID.ToString() +  " 不存在");  
    }  
    /// 获取下一个状态  
    public StateID GetOutputState(Transition trans)  
    {  
        // 如果存在转换,返回对应状态  
        if (map.ContainsKey(trans))  
        {  
            return map[trans];  
        }  
        return StateID.NullStateID;  
    }  
    /// 进入状态之前执行  
    public virtual void DoBeforeEntering() { }  
    /// 离开状态之前执行  
    public virtual void DoBeforeLeaving() { }  
    /// 状态转换条件  
    public abstract void Reason(GameObject player, GameObject npc);  
    /// 控制行为  
    public abstract void Act(GameObject player, GameObject npc);  
}   
/// <summary>  
/// 状态机类:包含状态列表  
/// 1. 删除状态  
/// 2. 改变当前状态  
/// </summary>  
public class FSMSystem  
{  
    private List<FSMState> states;  // 状态列表  
    // 在状态机中改变当前状态的唯一途径是通过转换,当前状态不可直接改变  
    private StateID currentStateID;  
    public StateID CurrentStateID { get { return currentStateID; } }  
    private FSMState currentState;  
    public FSMState CurrentState { get { return currentState; } }  
    public FSMSystem()  
    {  
        states = new List<FSMState>();  
    }  
    /// 添加状态  
    public void AddState(FSMState s)  
    {  
        // 空值检验  
        if (s == null)  
        {  
            Debug.LogError("FSM ERROR: 不可添加空状态");  
        }  
        // 当所添加状态为初始状态  
        if (states.Count == 0)  
        {  
            states.Add(s);  
            currentState = s;  
            currentStateID = s.ID;  
            return;  
        }  
        // 遍历状态列表,若不存在该状态,则添加  
        foreach (FSMState state in states)  
        {  
            if (state.ID == s.ID)  
            {  
                Debug.LogError("FSM ERROR: 无法添加状态 " + s.ID.ToString() + " 因为该状态已存在");  
                return;  
            }  
        }  
        states.Add(s);  
    }  
    /// 删除状态  
    public void DeleteState(StateID id)  
    {  
        // 空值检验  
        if (id == StateID.NullStateID)  
        {  
            Debug.LogError("FSM ERROR: 状态ID 不可为空ID");  
            return;  
        }  
        // 遍历并删除状态  
        foreach (FSMState state in states)  
        {  
            if (state.ID == id)  
            {  
                states.Remove(state);  
                return;  
            }  
        }  
        Debug.LogError("FSM ERROR: 无法删除状态 " + id.ToString() + ". 状态列表中不存在");  
    }  
    /// 执行转换  
    public void PerformTransition(Transition trans)  
    {  
        // 空值检验  
        if (trans == Transition.NullTransition)  
        {  
            Debug.LogError("FSM ERROR: 转换不可为空");  
            return;  
        }  
        // 获取当前状态ID  
        StateID id = currentState.GetOutputState(trans);  
        if (id == StateID.NullStateID)  
        {  
            Debug.LogError("FSM ERROR: 状态 " + currentStateID.ToString() + " 不存在目标状态 " +  
                           " - 转换: " + trans.ToString());  
            return;  
        }  
        // 更新当前状态ID 与 当前状态        
        currentStateID = id;  
        foreach (FSMState state in states)  
        {  
            if (state.ID == currentStateID)  
            {  
                // 执行当前状态后处理  
                currentState.DoBeforeLeaving();  
                currentState = state;  
                // 执行当前状态前处理  
                currentState.DoBeforeEntering();  
                break;  
            }  
        }  
    }   
}   

原文链接

著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

游戏学院公众号二维码
腾讯游戏学院
微信公众号

提供更专业的游戏知识学习平台