赞
踩
状态模式是一种对象型模式,他将复杂的逻辑判断提取到不同状态对象中,允许状态对象在其内部状态发生改变时,改变其行为。状态的改变和各个状态的行为是状态模式的核心。
这里模式就需要谈到一个游戏中经常使用的状态模式的形式。它就是有限状态机,有限状态机是作为对象不同状态的管理而使用的(游戏AI也经常使用有限状态机)。其主要思想是程序在任意时刻仅可处在有限的几个状态中。在任意状态中,程序行为将随状态的改变,发生改变。而状态和状态之间的切换都是预先设计好的。
预先定义的状态切换规则称为转移。
说明
这里将实现一个有限状态机,状态机分为四个部分
我们使用了泛型来增强有限状态机的复用性,使用工厂来创建状态机(避免复杂的创建过程,停留在调用端来污染代码)
为了方便考虑,我只枚举了 Idle(闲置)和 Chase(追击)两种状态
状态枚举
public enum StateId
{
Idle,
Chase,
}
状态接口
public interface IState<T>
where T : Enum
{
//获得对应状态类的Id
T Id { get; }
//状态进入前,调用此函数
void OnEnterState();
//状态时,调用此函数
void OnUpdateState();
//状态退出前,调用此函数
void OnExitState();
//状态转换函数,通过此函数判断是否转移状态
bool TransitionState(out T id);
}
敌人抽象状态
public abstract class EnemyState : IState<StateId> { private readonly StateId _id; private readonly ITransitionState<StateId> _transitionState; protected EnemyState(StateId id, ITransitionState<StateId> transitionState) { _id = id; _transitionState = transitionState; } public StateId Id => _id; public virtual void OnEnterState() { } public abstract void OnUpdateState(); public virtual void OnExitState() { } public bool TransitionState(out StateId id) => _transitionState.Transition(out id); }
之所以多出来这个抽象类,是为了将状态条件逻辑和状态行为逻辑分开,使得子类无需关注状态转移,只关注实现即可。而状态的转移实现转交给条件类完成(实现状态判断和状态行为实现的分离)。
具体状态类(Idle,Chase)
public class EnemyIdleState : EnemyState
{
public EnemyIdleState(ITransitionState<StateId> transitionState) :
base(StateId.Idle, transitionState)
{
}
public override void OnUpdateState()
{
}
}
public class EnemyChaseState : EnemyState { private float _chaseSpeed; private float _chaseRange; private GameObject _go; private GameObject _chaseTarget; //物理缓存 private Collider[] _colliders = new Collider[1]; public EnemyChaseState(float chaseSpeed, float chaseRange, GameObject go, ITransitionState<StateId> transitionState) : base(StateId.Chase, transitionState) { _go = go; _chaseSpeed = chaseSpeed; _chaseRange = chaseRange; } public override void OnEnterState() { _chaseTarget = null; int num = Physics.OverlapSphereNonAlloc(_go.transform.position, _chaseRange, _colliders, 1 << LayerMask.NameToLayer("Player")); if (num != 0) _chaseTarget = _colliders[0].gameObject; } public override void OnUpdateState() { //移动 var position = _go.transform.position; position += _chaseSpeed * Time.deltaTime * (_chaseTarget.transform.position - position).normalized; _go.transform.position = position; //旋转 _go.transform.LookAt(_chaseTarget.transform); } public override void OnExitState() { _chaseTarget = null; } }
条件接口
public interface ITransitionState<T>
where T : Enum
{
bool Transition(out T id);
}
具体条件接口(IdleTransition,Chase Transition)
public class EnemyIdleStateTransition : ITransitionState<StateId> { //自身游戏对象 private GameObject _go; //侦察范围 private float _scoutingRange; //侦察范围间隔(每帧调用,不利于程序性能) private readonly float _scoutingTime = 0.2f; private float _currentTime; public EnemyIdleStateTransition(GameObject go, float scoutingRange) { _scoutingRange = scoutingRange; _go = go; } public bool Transition(out StateId id) { _currentTime += Time.deltaTime; if (_currentTime >= _scoutingTime) { _currentTime = 0f; if (Physics.CheckSphere(_go.transform.position, _scoutingRange, 1 << LayerMask.NameToLayer("Player"))) { id = StateId.Chase; return true; } } id = StateId.Idle; return false; } }
public class EnemyChaseStateTransition : ITransitionState<StateId> { //脱离追击的距离 private float _outChaseDistance; //自身游戏对象 private GameObject _go; //脱离范围间隔(每帧调用不利于程序性能) private readonly float _outChaseTime = 0.2f; private float _currentTime; public EnemyChaseStateTransition(GameObject go, float outChaseDistance) { _outChaseDistance = outChaseDistance; _go = go; } public bool Transition(out StateId id) { _currentTime += Time.deltaTime; if (_currentTime >= _outChaseTime) { _currentTime = 0f; if (!Physics.CheckSphere(_go.transform.position, _outChaseDistance, 1 << LayerMask.NameToLayer("Player"))) { id = StateId.Idle; return true; } } id = StateId.Chase; return false; } }
有限状态机系统类
public class FsmSystem<T> where T : Enum { private Dictionary<T, IState<T>> _stateDic; private T _currentStateId; private IState<T> _currentState; public T Id => _currentStateId; public FsmSystem() { _stateDic = new Dictionary<T, IState<T>>(); } public void Add(IState<T> state) { if (state == null) return; if (_stateDic.ContainsKey(state.Id)) return; _stateDic.Add(state.Id, state); } public void Remove(T id) { if (!_stateDic.ContainsKey(id)) return; _stateDic.Remove(id); } public bool Enable(T id) { if (!_stateDic.ContainsKey(id)) return false; _currentStateId = id; _currentState = _stateDic[id]; _currentState.OnEnterState(); return true; } public void Update() { if (_currentState.TransitionState(out T id)) TransferState(id); _currentState.OnUpdateState(); } //转移状态函数 private void TransferState(T id) { if (!_stateDic.ContainsKey(id)) return; _currentState.OnExitState(); _currentState = _stateDic[id]; _currentStateId = id; _currentState.OnEnterState(); } }
工厂类
public class FsmFactory { public static FsmSystem<StateId> CreateEnemyFsm(GameObject go, float chaseRange, float chaseSpeed, float outChaseRange) { var fsm = new FsmSystem<StateId>(); //创建条件,并添加条件所需对应参数 var idleStateTransition = new EnemyIdleStateTransition(go, chaseRange); var chaseStateTransition = new EnemyChaseStateTransition(go, outChaseRange); //创建状态,并添加状态所需参数,而且将条件与状态绑定 var idleState = new EnemyIdleState(idleStateTransition); var chaseState = new EnemyChaseState(chaseSpeed, chaseRange, go, chaseStateTransition); fsm.Add(idleState); fsm.Add(chaseState); fsm.Enable(StateId.Idle); return fsm; } }
调用端
public class StateExample : MonoBehaviour { //追击速度 [SerializeField] private float _chaseSpeed = 3.0f; //追击范围 [SerializeField] private float _chaseRange = 4.0f; //脱离追击距离 [SerializeField] private float _outChaseRange = 5.0f; //此时状态 [SerializeField] private StateId _stateId; private FsmSystem<StateId> _system; private void Awake() { _system = FsmFactory.CreateEnemyFsm(gameObject, _chaseRange, _chaseSpeed, _outChaseRange); } private void Update() { _system.Update(); _stateId = _system.Id; } }
将玩家对象设置为 Player 层
效果图
由于不会作动图只能将就这看吧,代码没有问题,效果也还不错。
优点
缺点
我新写了一个有限状态机文章,简化了很多东西。可以去看看,点击链接即可
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。