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

关于Unity学习之FSM有限状态机的文章就介绍至此,更多相关UnityFSM有限状态机内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

在 Windows 窗体应用程序中显示图片时要使用图片控件 ( PictureBox ),图片的设置方式与背景图片的设置方式相似。图片控件中常用的属性如下表所示:图片控件中图片的设置除了可以直 ...