Unity有限状态机的简易实现

本人嘴笨,不会说。
该代码实现一个功能较为齐全的有限状态机,可用于大部分的应用场景。
大致实现几个功能

  • 状态更新
  • 状态转换
  • 状态消息处理
  • 全局状态转换和反转状态(转换为前一个状态)

代码分为

  • 状态类
  • 状态管理类
  • 枚举(状态枚举和消息枚举)

简易通用框架代码

状态接口

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

敌人主要实现追逐和闲置两个状态,玩家靠近就追逐,远离就闲置。
画面就不展示了,可以复制代码自己尝试

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity动画状态机是一种用于控制游戏对象动画行为的工具。它基于状态机的概念,通过定义不同的状态状态之间的转换来实现动画的播放和切换。 在Unity中,可以通过以下步骤来实现动画状态机: 1. 创建动画状态机:在Unity编辑器中,可以创建一个Animator Controller(动画控制器)作为动画状态机的容器。可以通过右键点击Assets面板,选择Create -> Animator Controller来创建。 2. 添加动画状态:在Animator Controller中,可以添加多个动画状态。每个动画状态代表一个特定的动画片段或动画行为。可以通过拖拽动画片段或者创建新的动画状态来添加。 3. 设置状态之间的转换:在Animator Controller中,可以设置不同状态之间的转换条件。转换条件可以是触发器、布尔值、整数等。当满足转换条件时,Animator会自动切换到下一个状态。 4. 添加过渡动画:在状态之间的转换过程中,可以添加过渡动画来实现平滑的过渡效果。可以设置过渡动画的淡入淡出时间、过渡曲线等参数。 5. 控制动画播放:通过代码或者其他方式,可以控制Animator组件的参数来触发状态之间的转换和动画的播放。例如,可以使用Animator.SetTrigger()方法来触发转换条件。 总结一下,Unity动画状态机通过定义不同的状态状态之间的转换来实现动画的播放和切换。它是一种强大的工具,可以帮助开发者实现复杂的动画逻辑和交互效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值