加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
FSMSystem.cs 8.00 KB
一键复制 编辑 原始数据 按行查看 历史
UnitySir 提交于 2021-05-09 11:55 . 004
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum Transition
{
NullTransition = 0, // Use this transition to represent a non-existing transition in your system
}
public enum StateID
{
NullStateID = 0, // Use this ID to represent a non-existing State in your system
}
public abstract class FSMState
{
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)
{
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;
}
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);
}
public void DeleteTransition(Transition trans)
{
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");
}
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);
}
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: Null reference is not allowed");
}
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);
}
public void DeleteState(StateID id)
{
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");
}
public void PerformTransition(Transition trans)
{
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 = id;
foreach (FSMState state in states)
{
if (state.ID == currentStateID)
{
currentState.DoBeforeLeaving();
currentState = state;
currentState.DoBeforeEntering();
break;
}
}
}
}
//======================================---Example---==========================================
using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class NPCControl : MonoBehaviour
{
public GameObject player;
public Transform[] path;
private FSMSystem fsm;
public void SetTransition(Transition t) { fsm.PerformTransition(t); }
public void Start()
{
MakeFSM();
}
public void FixedUpdate()
{
fsm.CurrentState.Reason(player, gameObject);
fsm.CurrentState.Act(player, gameObject);
}
private void MakeFSM()
{
FollowPathState follow = new FollowPathState(path);
follow.AddTransition(Transition.SawPlayer, StateID.ChasingPlayer);
ChasePlayerState chase = new ChasePlayerState();
chase.AddTransition(Transition.LostPlayer, StateID.FollowingPath);
fsm = new FSMSystem();
fsm.AddState(follow);
fsm.AddState(chase);
}
}
public class FollowPathState : FSMState
{
private int currentWayPoint;
private Transform[] waypoints;
public FollowPathState(Transform[] wp)
{
waypoints = wp;
currentWayPoint = 0;
stateID = StateID.FollowingPath;
}
public override void Reason(GameObject player, GameObject npc)
{
RaycastHit hit;
if (Physics.Raycast(npc.transform.position, npc.transform.forward, out hit, 15F))
{
if (hit.transform.gameObject.tag == "Player")
npc.GetComponent<NPCControl>().SetTransition(Transition.SawPlayer);
}
}
public override void Act(GameObject player, GameObject npc)
{
Vector3 vel = npc.rigidbody.velocity;
Vector3 moveDir = waypoints[currentWayPoint].position - npc.transform.position;
if (moveDir.magnitude < 1)
{
currentWayPoint++;
if (currentWayPoint >= waypoints.Length)
{
currentWayPoint = 0;
}
}
else
{
vel = moveDir.normalized * 10;
npc.transform.rotation = Quaternion.Slerp(npc.transform.rotation,
Quaternion.LookRotation(moveDir),
5 * Time.deltaTime);
npc.transform.eulerAngles = new Vector3(0, npc.transform.eulerAngles.y, 0);
}
npc.rigidbody.velocity = vel;
}
}
public class ChasePlayerState : FSMState
{
public ChasePlayerState()
{
stateID = StateID.ChasingPlayer;
}
public override void Reason(GameObject player, GameObject npc)
{
if (Vector3.Distance(npc.transform.position, player.transform.position) >= 30)
npc.GetComponent<NPCControl>().SetTransition(Transition.LostPlayer);
}
public override void Act(GameObject player, GameObject npc)
{
Vector3 vel = npc.rigidbody.velocity;
Vector3 moveDir = player.transform.position - npc.transform.position;
npc.transform.rotation = Quaternion.Slerp(npc.transform.rotation,
Quaternion.LookRotation(moveDir),
5 * Time.deltaTime);
npc.transform.eulerAngles = new Vector3(0, npc.transform.eulerAngles.y, 0);
vel = moveDir.normalized * 10;
npc.rigidbody.velocity = vel;
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化