Unity學(xué)習(xí)之FSM有限狀態(tài)機(jī)
前言:一個(gè)游戲里的一個(gè)人物會(huì)存在多種狀態(tài),那么就需要有一個(gè)專門管理這些狀態(tài)的類。不然會(huì)顯得雜亂無章,不易于后面狀態(tài)的增加或者減少。
思路:既然要方便管理,那么首先肯定得有個(gè)系統(tǒng)類(專門用來存放所有的狀態(tài)、狀態(tài)的增刪等功能);然后就是需要把所有的狀態(tài)都單獨(dú)寫一個(gè)類(已達(dá)到修改某個(gè)狀態(tài)的時(shí)候,其他狀態(tài)不會(huì)受到影響)。
狀態(tài)管理類:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FSMSystem
{
private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();
private StateID currentStateID;
private FSMState currentFSMState;
public void Update(GameObject npc)
{
currentFSMState.Act(npc);
currentFSMState.Reason(npc);
}
/// <summary>
/// 添加狀態(tài)
/// </summary>
/// <param name="fSMState"></param>
public void AddState(FSMState fSMState)
{
if (fSMState == null) return;
//if (currentFSMState == null)
//{
currentStateID = fSMState.ID;
currentFSMState = fSMState;
//}
if (states.ContainsKey(currentStateID)) return;
states.Add(currentStateID, currentFSMState);
}
/// <summary>
/// 刪除狀態(tài)
/// </summary>
/// <param name="stateID"></param>
public void DeleteState(StateID stateID)
{
if (stateID == StateID.Null) return;
if (!states.ContainsKey(stateID)) return;
states.Remove(stateID);
}
/// <summary>
/// 執(zhí)行狀態(tài)條件轉(zhuǎn)換
/// </summary>
/// <param name="transition"></param>
public void PerformTransition(Transition transition)
{
if (transition == Transition.NullTransition) return;
StateID stateID = currentFSMState.GetStateID(transition);
if (stateID == StateID.Null) return;
if (!states.ContainsKey(stateID)) return;
FSMState fSMState = states[stateID];
currentFSMState.StateExit();
currentFSMState = fSMState;
currentStateID = fSMState.ID;
currentFSMState.StateEnter();
}
}
狀態(tài)基類:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Transition
{
NullTransition,
SeePlayer,//發(fā)現(xiàn)玩家
LostPlayer,//玩家脫離視野范圍
AttackPlayer,//攻擊玩家
}
public enum StateID
{
Null,
Chase,//追逐
Patrol,//巡邏
Attack,//攻擊
}
public abstract class FSMState
{
protected Transition transition;
protected StateID stateID;
protected FSMSystem fSM;
public StateID ID
{
get { return stateID; }
}
protected Dictionary<Transition, StateID> dic = new Dictionary<Transition, StateID>();
public FSMState(FSMSystem fSM)
{
this.fSM = fSM;
}
/// <summary>
/// 增加狀態(tài)
/// </summary>
/// <param name="transition"></param>
/// <param name="stateID"></param>
public void AddTransition(Transition transition, StateID stateID)
{
if (transition == Transition.NullTransition) return;
if (stateID == StateID.Null) return;
if (dic.ContainsKey(transition)) return;
dic.Add(transition, stateID);
}
/// <summary>
/// 刪除狀態(tài)
/// </summary>
/// <param name="transition"></param>
public void DeleteTransition(Transition transition)
{
if (transition == Transition.NullTransition) return;
if (!dic.ContainsKey(transition)) return;
dic.Remove(transition);
}
/// <summary>
/// 獲取狀態(tài)
/// </summary>
/// <param name="transition"></param>
/// <returns></returns>
public StateID GetStateID(Transition transition)
{
if (transition == Transition.NullTransition) return StateID.Null;
if (!dic.ContainsKey(transition)) return StateID.Null;
return dic[transition];
}
/// <summary>
/// 進(jìn)入狀態(tài)
/// </summary>
public virtual void StateEnter() { }
/// <summary>
/// 退出狀態(tài)
/// </summary>
public virtual void StateExit() { }
/// <summary>
/// 狀態(tài)持續(xù)中,,,
/// </summary>
/// <param name="npc"></param>
public abstract void Act(GameObject npc);
/// <summary>
/// 狀態(tài)退出前,,,
/// </summary>
/// <param name="npc"></param>
public abstract void Reason(GameObject npc);
}
巡邏狀態(tài):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 巡邏狀態(tài)
/// </summary>
public class PatrolState : FSMState
{
/// <summary>
/// 巡邏路徑點(diǎn)集合
/// </summary>
private Transform[] paths;
/// <summary>
/// 當(dāng)前巡邏路徑點(diǎn)索引
/// </summary>
private int index = 0;
/// <summary>
/// 移動(dòng)速度
/// </summary>
private float moveSpeed = 0.5f;
/// <summary>
/// 玩家
/// </summary>
private Transform player;
public PatrolState(FSMSystem fSM, Transform player) : base(fSM)
{
this.player = player;
paths = GameObject.Find("Path").GetComponentsInChildren<Transform>();
stateID = StateID.Patrol;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(paths[index].position);
npc.transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed);
if (Vector3.Distance(npc.transform.position, paths[index].position) < 1)
{
index++;
index %= paths.Length;
}
}
public override void Reason(GameObject npc)
{
npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed );
if (Vector3.Distance(player.position, npc.transform.position) < 10)
{
fSM.PerformTransition(Transition.SeePlayer);
}
}
}
追逐狀態(tài):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 追逐狀態(tài)
/// </summary>
public class ChaseState : FSMState
{
/// <summary>
/// 移動(dòng)速度
/// </summary>
private float moveSpeed = 2f;
/// <summary>
/// 玩家
/// </summary>
private Transform player;
public ChaseState(FSMSystem fSM, Transform player) : base(fSM)
{
stateID = StateID.Chase;
this. player = player;
}
public override void Act(GameObject npc)
{
npc.transform.LookAt(player.position);
npc.transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed);
}
public override void Reason(GameObject npc)
{
npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed / 2);
if (Vector3.Distance(player.position, npc.transform.position) >= 10)
{
fSM.PerformTransition(Transition.LostPlayer);
}
else if (Vector3.Distance(player.position, npc.transform.position) <= 1f )
{
fSM.PerformTransition(Transition.AttackPlayer);
}
}
}
攻擊狀態(tài):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 攻擊狀態(tài)
/// </summary>
public class AttackState : FSMState
{
/// <summary>
/// 玩家
/// </summary>
private Transform player;
public AttackState(FSMSystem fSM, Transform player) : base(fSM)
{
stateID = StateID.Attack;
this.player = player;
}
public override void Act(GameObject npc)
{
}
public override void Reason(GameObject npc)
{
if (Vector3.Distance(player.position, npc.transform.position) > 1f)
{
if (Vector3.Distance(player.position, npc.transform.position) >= 10)
{
fSM.PerformTransition(Transition.LostPlayer);
}
else if (Vector3.Distance(player.position, npc.transform.position) < 10)
{
fSM.PerformTransition(Transition.SeePlayer);
}
return;
}
npc.GetComponent<Animator>().SetTrigger("Attack01");
}
}
狀態(tài)持有者實(shí)現(xiàn)類:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
private FSMSystem fSM;
private Transform player;
private void Start()
{
fSM = new FSMSystem();
FSMState patrolState = new PatrolState(fSM, player);
patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);
patrolState.AddTransition(Transition.AttackPlayer, StateID.Attack);
//patrolState.AddTransition(Transition.LostPlayer, StateID.Patrol);
FSMState chaseState = new ChaseState(fSM, player);
chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);
chaseState.AddTransition(Transition.AttackPlayer, StateID.Attack);
//chaseState.AddTransition(Transition.SeePlayer, StateID.Chase);
FSMState attackState = new AttackState(fSM, player);
attackState.AddTransition(Transition.SeePlayer, StateID.Chase);
attackState.AddTransition(Transition.LostPlayer, StateID.Patrol);
//attackState.AddTransition(Transition.AttackPlayer, StateID.Attack);
fSM.AddState(patrolState);
fSM.AddState(chaseState);
fSM.AddState(attackState);
}
private void Update()
{
fSM.Update(gameObject);
}
}
到此這篇關(guān)于Unity學(xué)習(xí)之FSM有限狀態(tài)機(jī)的文章就介紹到這了,更多相關(guān)UnityFSM有限狀態(tài)機(jī)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C#中三個(gè)關(guān)鍵字params,Ref,out
本文主要討論params關(guān)鍵字,ref關(guān)鍵字,out關(guān)鍵字。非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-05-05
Windows Form 分頁 具體實(shí)現(xiàn)
其實(shí)功能實(shí)現(xiàn)很簡單。我做的是一個(gè)通用的分頁控件。項(xiàng)目時(shí)間很緊,可能有點(diǎn)粗糙。歡迎大家斧正。不說了直接貼代碼吧2013-12-12
c# winform treelistview的使用(treegridview)實(shí)例詳解
這篇文章主要介紹了c# winform treelistview的使用(treegridview),本文通過實(shí)例代碼給大家詳細(xì)介紹,需要的朋友可以參考下2017-12-12
c#使用FreeSql生產(chǎn)環(huán)境時(shí)自動(dòng)升級(jí)備份數(shù)據(jù)庫
使用FreeSql,包含所有的ORM數(shù)據(jù)庫,都會(huì)存在這樣的問題。在codefirst模式下,根據(jù)代碼自動(dòng)更新數(shù)據(jù)庫,都建議不要在生產(chǎn)環(huán)境使用。因?yàn)槿菀讈G失數(shù)據(jù),本文提供一種自動(dòng)更新數(shù)據(jù)庫的解決的思路:在判斷需要升級(jí)時(shí),才自動(dòng)升級(jí),同時(shí)升級(jí)前先備份數(shù)據(jù)庫2021-06-06
c#實(shí)現(xiàn)字符串反序輸出字符串的實(shí)例
下面小編就為大家分享一篇c#實(shí)現(xiàn)字符串反序輸出字符串的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2017-12-12
C#實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條效果
這篇文章主要介紹了基于C#實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條 效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
在Unity中實(shí)現(xiàn)簡單的偽時(shí)間同步
這篇文章主要介紹了在Unity中實(shí)現(xiàn)簡單的偽時(shí)間同步,為什么說是偽同步呢,因?yàn)閮H僅是獲取的數(shù)據(jù)庫所在服務(wù)器的系統(tǒng)時(shí)間,分享給大家,有需要的小伙伴可以參考下2015-03-03

