本人嘴笨,不会说。
该代码实现一个功能较为齐全的有限状态机,可用于大部分的应用场景。
大致实现几个功能
- 状态更新
- 状态转换
- 状态消息处理
- 全局状态转换和反转状态(转换为前一个状态)
代码分为
- 状态类
- 状态管理类
- 枚举(状态枚举和消息枚举)
简易通用框架代码
状态接口
using System;
namespace FSM
{
public interface IStateBase<T, TState, TMessage>
where TState : Enum
where TMessage : Enum
{
//确定该状态枚举
public TState GetState();
//进入状态
void OnEnter(T owner);
//更新状态
void OnUpdate(T owner);
//退出状态
void OnExit(T owner);
// 转换状态 (-1 为返回上一个状态,0 为保持不变,1 为转换为下一个状态)
int OnTransfer(T owner, out TState newState);
//消息接收
void OnMessage(T owner, TMessage e);
}
}
全局状态接口
using System;
namespace FSM
{
public interface IGlobalState<T, TState, TMessage> : IStateBase<T, TState, TMessage>
where TState : Enum
where TMessage : Enum
{
//全局转换状态
bool OnGlobalTransfer(T owner);
}
}
状态管理类
using System;
using System.Collections.Generic;
using UnityEngine;
namespace FSM
{
public class FsmMachine<T, TState, TMessage>
where TState : Enum
where TMessage : Enum
{
//状态类存储
private Dictionary<TState, IStateBase<T, TState, TMessage>> _states =
new Dictionary<TState, IStateBase<T, TState, TMessage>>();
//全局状态类存储
private Dictionary<TState, IGlobalState<T, TState, TMessage>> _globalStates =
new Dictionary<TState, IGlobalState<T, TState, TMessage>>();
//Fsm的使用对象
private T _owner;
//状态枚举
private TState _stateID;
//上一个状态
private IStateBase<T, TState, TMessage> _previousState;
//状态类
private IStateBase<T, TState, TMessage> _state;
//初始化
public void Init(T owner, TState stateID)
{
if (owner == null)
throw new NullReferenceException();
if (!_states.ContainsKey(stateID))
throw new AggregateException(stateID + "不存在");
_owner = owner;
_stateID = stateID;
_state = _states[stateID];
_state.OnEnter(_owner);
}
//注册状态类
public void RegisterState(IStateBase<T, TState, TMessage> state)
{
if (_states == null)
_states = new Dictionary<TState, IStateBase<T, TState, TMessage>>();
if (_states.ContainsKey(state.GetState()))
Debug.Log(state.GetState() + "已存在");
_states.Add(state.GetState(), state);
}
//删除状态类
public void RemoveState(TState stateID)
{
if (_states == null || !_states.ContainsKey(stateID))
return;
_states.Remove(stateID);
}
//注册全局状态类
public void RegisterGlobalState(IGlobalState<T, TState, TMessage> globalState)
{
if (_globalStates == null)
_globalStates = new Dictionary<TState, IGlobalState<T, TState, TMessage>>();
if (_globalStates.ContainsKey(globalState.GetState()))
Debug.Log(globalState.GetState() + "已存在");
_globalStates.Add(globalState.GetState(), globalState);
RegisterState(globalState);
}
//删除全局状态类
public void RemoveGlobalState(TState stateID)
{
if (_globalStates == null || !_globalStates.ContainsKey(stateID))
return;
_globalStates.Remove(_stateID);
RemoveState(stateID);
}
//更新状态
public void Update()
{
if (_state == null)
return;
//状态更新
_state.OnUpdate(_owner);
//全局状态转换
foreach (var globalState in _globalStates.Values)
{
if (globalState.OnGlobalTransfer(_owner))
{
ChangeState(globalState.GetState());
return;
}
}
//状态转换
switch (_state.OnTransfer(_owner, out TState stateID))
{
case -1:
RevertToPreviousState();
break;
case 0:
//不做任何事
break;
case 1:
ChangeState(stateID);
break;
}
}
//状态反转(返回上一个状态)
private void RevertToPreviousState()
{
ChangeState(_previousState.GetState());
}
//转换状态
public void ChangeState(TState stateID)
{
if (_states == null || !_states.ContainsKey(stateID)) return;
if (_stateID.Equals(stateID)) return;
_state.OnExit(_owner);
_stateID = stateID;
_previousState = _state;
_state = _states[stateID];
_state.OnEnter(_owner);
}
}
}
实现代码
敌人枚举部分
public enum EnemyState
{
None,
//闲置
Idle,
//追逐
Chase,
}
public enum EnemyMessage
{
None,
//消息
Log,
}
敌人状态基类
using FSM;
namespace Enemy
{
public abstract class EnemyStateBase : IGlobalState<EnemyEntity, EnemyState, EnemyMessage>
{
public abstract EnemyState GetState();
public abstract void OnEnter(EnemyEntity owner);
public abstract void OnUpdate(EnemyEntity owner);
public abstract void OnExit(EnemyEntity owner);
public abstract int OnTransfer(EnemyEntity owner, out EnemyState newState);
public virtual bool OnGlobalTransfer(EnemyEntity owner) => false;
public void OnMessage(EnemyEntity owner, EnemyMessage e)
{
//可以通过虚方法的方式,让子类继承实现对应消息的方法
if (e == EnemyMessage.Log)
OnLog();
}
protected virtual void OnLog() { }
}
}
实现了两个状态 Idle 和 Chase
using UnityEngine;
namespace Enemy.State
{
public class EnemyIdleState : EnemyStateBase
{
public override EnemyState GetState() => EnemyState.Idle;
public override void OnEnter(EnemyEntity owner)
{
owner.SetVelocity(Vector3.zero);
}
public override void OnUpdate(EnemyEntity owner) { }
public override void OnExit(EnemyEntity owner) { }
public override int OnTransfer(EnemyEntity owner, out EnemyState newState)
{
if (Vector3.SqrMagnitude(owner.target.transform.position - owner.transform.position)
<= owner.chaseRange * owner.chaseRange)
{
newState = EnemyState.Chase;
return 1;
}
newState = GetState();
return 0;
}
}
}
using UnityEngine;
namespace Enemy.State
{
public class EnemyChaseState : EnemyStateBase
{
public override EnemyState GetState() => EnemyState.Chase;
public override void OnEnter(EnemyEntity owner) { }
public override void OnUpdate(EnemyEntity owner)
{
Vector3 v = owner.target.transform.position - owner.transform.position;
//靠太近就挺下来,但状态还是追逐
if (Vector3.SqrMagnitude(v) < 1)
owner.SetVelocity(Vector3.zero);
else
owner.SetVelocity(v.normalized * owner.speed);
}
public override void OnExit(EnemyEntity owner) { }
public override int OnTransfer(EnemyEntity owner, out EnemyState newState)
{
if (Vector3.SqrMagnitude(owner.target.transform.position - owner.transform.position)
> owner.escapeRange * owner.escapeRange)
{
newState = EnemyState.Idle;
return 1;
}
newState = GetState();
return 0;
}
}
}
敌人部分
using Enemy;
using Enemy.State;
using FSM;
using UnityEngine;
public class EnemyEntity : MonoBehaviour
{
//移动速度
public float speed = 2f;
//追逐范围
public float chaseRange = 5f;
//逃脱范围
public float escapeRange = 8f;
//追逐目标
public GameObject target;
private Rigidbody _rigidbody;
private FsmMachine<EnemyEntity, EnemyState, EnemyMessage> _machine;
public void SetVelocity(Vector3 v3) => _rigidbody.velocity = v3;
private void Awake()
{
_rigidbody = GetComponent<Rigidbody>();
//创建Fsm并添加状态
_machine = new FsmMachine<EnemyEntity, EnemyState, EnemyMessage>();
_machine.RegisterState(new EnemyIdleState());
_machine.RegisterState(new EnemyChaseState());
_machine.Init(this, EnemyState.Idle);
}
private void Update()
{
_machine.Update();
}
}
玩家部分
using System;
using UnityEngine;
public class PlayerEntity : MonoBehaviour
{
public float speed = 4f;
private void Update()
{
float hor = Input.GetAxis("Horizontal");
float ver = Input.GetAxis("Vertical");
Vector3 v = new Vector3(hor, 0, ver).normalized;
transform.position += (speed * Time.deltaTime) * v;
}
}
敌人主要实现追逐和闲置两个状态,玩家靠近就追逐,远离就闲置。
画面就不展示了,可以复制代码自己尝试