using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/**
基於Eric Dybsand的遊戲編程Gems 1第3.1章的有限狀態機系統Roberto Cezar Bianchini著,2010年7月
How to use:
1. 爲有限狀態系統的轉換和狀態放置標籤在相應的枚舉中。
2. 編寫從FSMState繼承的新類,並用對(轉換狀態)填充每個類。這些對錶示當處於狀態S1, a時,FSMSystem應該處於的狀態S2轉換T被觸發,狀態S1從它轉換到S2。記住這是一個確定性的FSM。你不可能有一個轉變導致兩個不同的狀態。
方法原因用於確定應該觸發哪個轉換。您可以在另一個地方編寫觸發轉換的代碼,如果需要,則保留此方法爲空覺得它更適合你的項目。
Method Act有代碼來執行NPC在這個狀態下應該執行的操作。您可以在另一個地方爲操作編寫代碼,如果需要,可以將此方法保留爲空覺得它更適合你的項目。
3. 創建一個FSMSystem類的實例,並向其添加狀態。
4. 調用Reason和Act(或者你擁有的用於觸發轉換和製作npc的任何方法)行爲在你的遊戲)從你的更新或FixedUpdate方法。
從Unity引擎的異步轉換,如OnTriggerEnter, SendMessage,也可以使用,只需從FSMSystem實例調用PerformTransition方法,並使用正確的轉換事件發生時。
本軟件是“按原樣”提供的,沒有任何明示或暗示的保證,包括但不限於適銷性、適合某一特定用途的保證和不侵權。在任何情況下,作者或版權持有人均不對任何索賠承擔責任,損害賠償或其他責任,無論是在合同、侵權或其他訴訟中,
與本軟件無關或與本軟件有關的,或與本軟件的使用或其他交易有關的。
*/
/// <summary>
/// 在這個枚舉中放置轉換的標籤。
/// 不要更改第一個標籤,因爲FSMSystem類使用了它。
/// </summary>
public enum Transition
{
NullTransition = 0, // 使用此轉換表示系統中不存在的轉換
StartButtonClick,
PauseButtonClick
}
/// <summary>
/// 在這個枚舉中放置狀態的標籤。
/// 不要更改第一個標籤,因爲FSMSystem類使用了它。
/// </summary>
public enum StateID
{
NullStateID = 0, // 使用此ID表示系統中不存在的狀態
Menu,
Play,
Pause,
GameOver
}
/// <summary>
/// 該類表示有限狀態系統中的狀態。
/// 每個狀態都有一個顯示對(轉換狀態)的字典
/// 如果在此狀態下觸發轉換,FSM應該處於哪種狀態
/// 是當前狀態。
/// 方法原因用於確定應該觸發哪個轉換。
/// Method Act有代碼來執行NPC在這個狀態下應該執行的操作。
/// </summary>
public abstract class FSMState : MonoBehaviour
{
protected Ctrl ctrl; //Control腳本
public Ctrl CTRL { set { ctrl = value; } }
protected FSMSystem fsm;
public FSMSystem FSM { set { fsm = value; } }
protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();
protected StateID stateID;
public StateID ID { get { return stateID; } }
public void AddTransition(Transition trans, StateID id)
{
// 檢查是否有arg是無效的
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed for a real transition");
return;
}
if (id == StateID.NullStateID)
{
Debug.LogError("FSMState ERROR: NullStateID is not allowed for a real ID");
return;
}
// 因爲這是一個確定性的FSM,
// 檢查當前轉換是否已經在映射中
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>
/// 此方法從該狀態映射中刪除一對轉換狀態。
/// 如果轉換不在狀態映射中,則會打印一條錯誤消息。
/// </summary>
public void DeleteTransition(Transition trans)
{
// Check for NullTransition
if (trans == Transition.NullTransition)
{
Debug.LogError("FSMState ERROR: NullTransition is not allowed");
return;
}
// 在刪除之前,檢查對是否在映射中
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>
/// 該方法返回FSM應該是if的新狀態
/// 這個狀態接收一個轉換和
/// </summary>
public StateID GetOutputState(Transition trans)
{
// 檢查映射是否具有此轉換
if (map.ContainsKey(trans))
{
return map[trans];
}
return StateID.NullStateID;
}
/// <summary>
/// 此方法用於在輸入狀態之前設置狀態條件。
/// 在分配它之前,FSMSystem類會自動調用它
/// 到當前狀態。
/// </summary>
public virtual void DoBeforeEntering() { }
/// <summary>
/// 此方法用於使任何必要的東西,如重新設置變量
/// 在FSMSystem切換到另一個之前。它是自動調用的
/// 在切換到新的狀態之前通過FSMSystem。
/// </summary>
public virtual void DoBeforeLeaving() { }
/// <summary>
/// 該方法決定狀態是否應該轉換到其列表中的另一個狀態
/// NPC是對這個類控制的對象的引用
/// </summary>
public virtual void Reason() { }
/// <summary>
/// 這種方法控制NPC在遊戲世界中的行爲。
/// NPC所做的每一個動作、每一個動作、每一次交流都應該放在這裏
/// NPC是對這個類控制的對象的引用
/// </summary>
public virtual void Act() { }
} // class FSMState
/// <summary>
/// FSMSystem類表示有限狀態機類。
/// It has a List with the States the NPC has and methods to add,,
/// 刪除一個狀態,並更改機器當前處於的狀態。
/// </summary>
public class FSMSystem
{
private List<FSMState> states;
// 更改FSM狀態的惟一方法是執行轉換
// 不要直接改變當前狀態
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 SetCurrentState(FSMState s)
{
currentState = s;
currentStateID = s.ID;
s.DoBeforeEntering();
}
*/
/// <summary>
/// 該方法在FSM中放置新的狀態,
/// 或者,如果狀態已經在列表中,則打印錯誤消息。
/// 添加的第一個狀態也是初始狀態。
/// </summary>
public void AddState(FSMState s, Ctrl ctrl)
{
// Check for Null reference before deleting
if (s == null)
{
Debug.LogError("FSM ERROR: Null reference is not allowed");
}
s.FSM = this;
s.CTRL = ctrl;
// 插入的第一個狀態也是初始狀態,
// 模擬開始時機器所處的狀態
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: Impossible to add state " + s.ID.ToString() +
" because state has already been added");
return;
}
}
states.Add(s);
}
/// <summary>
/// 這個方法從FSM列表中刪除一個狀態,如果它存在,
/// 或者,如果狀態不在列表中,則打印錯誤消息。
/// </summary>
public void DeleteState(StateID id)
{
// 刪除之前檢查NullState
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: NullStateID is not allowed for a real state");
return;
}
// 搜索列表並刪除列表中的狀態
foreach (FSMState 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>
/// 該方法試圖改變FSM所處的狀態
/// 當前狀態和轉換已通過。如果當前狀態
/// 轉換沒有目標狀態,
/// 打印錯誤消息。
/// </summary>
public void PerformTransition(Transition trans)
{
//在更改當前狀態之前檢查NullTransition
if (trans == Transition.NullTransition)
{
Debug.LogError("FSM ERROR: NullTransition is not allowed for a real transition");
return;
}
// 檢查當前狀態是否將轉換作爲參數傳遞
StateID id = currentState.GetOutputState(trans);
if (id == StateID.NullStateID)
{
Debug.LogError("FSM ERROR: State " + currentStateID.ToString() + " does not have a target state " +
" for transition " + trans.ToString());
return;
}
// 更新currentStateID和currentState
currentStateID = id;
foreach (FSMState state in states)
{
if (state.ID == currentStateID)
{
// 在設置新狀態之前是否對狀態進行後處理
currentState.DoBeforeLeaving();
currentState = state;
// 在進行推理或操作之前,將狀態重置爲所需的狀態
currentState.DoBeforeEntering();
break;
}
}
} // PerformTransition()
} //class FSMSystem