软件编程
位置:首页>> 软件编程>> C#编程>> Unity学习之FSM有限状态机

Unity学习之FSM有限状态机

作者:念丶小宇  发布时间:2022-09-10 06:18:33 

标签:Unity,FSM,有限状态机

前言:一个游戏里的一个人物会存在多种状态,那么就需要有一个专门管理这些状态的类。不然会显得杂乱无章,不易于后面状态的增加或者减少。
思路:既然要方便管理,那么首先肯定得有个系统类(专门用来存放所有的状态、状态的增删等功能);然后就是需要把所有的状态都单独写一个类(已达到修改某个状态的时候,其他状态不会受到影响)。

状态管理类:


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>
   /// 添加状态
   /// </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>
   /// 删除状态
   /// </summary>
   /// <param name="stateID"></param>
   public void DeleteState(StateID stateID)
   {
       if (stateID == StateID.Null) return;
       if (!states.ContainsKey(stateID)) return;

states.Remove(stateID);
   }

/// <summary>
   /// 执行状态条件转换
   /// </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();
   }
}

状态基类:


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

public enum Transition
{
   NullTransition,
   SeePlayer,//发现玩家
   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>
   /// 增加状态
   /// </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>
   /// 删除状态
   /// </summary>
   /// <param name="transition"></param>
   public void DeleteTransition(Transition transition)
   {
       if (transition == Transition.NullTransition) return;
       if (!dic.ContainsKey(transition)) return;

dic.Remove(transition);
   }
   /// <summary>
   /// 获取状态
   /// </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>
   /// 进入状态
   /// </summary>
   public virtual void StateEnter() { }
   /// <summary>
   /// 退出状态
   /// </summary>
   public virtual void StateExit() { }

/// <summary>
   /// 状态持续中,,,
   /// </summary>
   /// <param name="npc"></param>
   public abstract void Act(GameObject npc);
   /// <summary>
   /// 状态退出前,,,
   /// </summary>
   /// <param name="npc"></param>
   public abstract void Reason(GameObject npc);
}

巡逻状态:


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

/// <summary>
/// 巡逻状态
/// </summary>
public class PatrolState : FSMState
{
   /// <summary>
   /// 巡逻路径点集合
   /// </summary>
   private Transform[] paths;
   /// <summary>
   /// 当前巡逻路径点索引
   /// </summary>
   private int index = 0;
   /// <summary>
   /// 移动速度
   /// </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);
       }
   }
}

追逐状态:


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

/// <summary>
/// 追逐状态
/// </summary>
public class ChaseState : FSMState
{
   /// <summary>
   /// 移动速度
   /// </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);
       }
   }
}

攻击状态:


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

/// <summary>
/// 攻击状态
/// </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");
   }
}

状态持有者实现类:

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);    }}

来源:https://blog.csdn.net/qq_43815828/article/details/117918980

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com