[转]Untiy学习 -一个简单的有限状态机(FSM)

前言

参考资料:unity3D FSM有限状态机(状态设计模式)

核心

先列举有限数量的状态,让需要被控制的物体在状态中根据设定流转,并且每次只存在一个状态被激活。

三个方案

  • 声明一个enum字典,写入所有的状态

public enum EnemyStateEnum
{
    IDLE,//待机 -> 追击/死亡
    TRACE,//追击 -> 攻击/丢失/死亡
    LOST,//丢失 -> 待机/追击/死亡
    ATK1,//近战 -> 追击/丢失/死亡
    DIE,//死亡
}

后面是我想要让他能够流转的关系(提前写一下)

方案一 switch

public EnemyStateEnum traceState = EnemyStateEnum.IDLE;//声明一个状态属性

    void Update()
    {
        switch (traceState)
        {
            case EnemyStateEnum.IDLE:
                要做啥的事情();
                break;
            case EnemyStateEnum.TRACE:
                要做啥的事情();
                break;
            case EnemyStateEnum.LOST:
                要做啥的事情();
                break;
            case EnemyStateEnum.ATK1:
                要做啥的事情();
                break;
            case EnemyStateEnum.DIE:
                要做啥的事情();
                break;
        }
	}

然后在应触发转换的位置进行触发就行了。

这是非常偷懒的办法,并且局限性很大,如果状态非常多,或者想要区分状态开始、中间、结束,会非常麻烦

我写了很久才发现上面的有问题……紧急学了以下内容

方案二 参考资料:unity3D FSM有限状态机(状态设计模式)

1. 状态基类
状态基类需要3个虚方法,以及虚拟机对象

2. 拥有者泛型类
继承状态基类,构造出使用者对象

3. 玩家脚本类
在Start方法里构造new各个状态机类(传入枚举id,使用者this(自己)),new状态机对象,添加各个状态类对象。
在Update通过按键,并一直调用状态机的切换方法。
在LateUpdate()调用状态机的保持状态方法

4. 状态机类
包含添加状态类,切换状态类方法(控制Enter()),保存状态类方法(控制(Stay()))
加若干个状态类
每个状态具体有3种状态方法(OnEnter,OnStay,OnExit)需要重写来具体实现,通过OnExit()方法改变使用者的枚举id来切换状态
在这里插入图片描述

我做了一些调整,让onEnter每次只需单次调用

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 状态机器类:由Player控制。完成状态的存储,切换,和状态的保持
/// </summary>
public class StateMachine
{

    //用来存储当前机器所控制的所有状态
    public Dictionary<int, StateBase> m_StateCache;

    //定义当前状态
    public StateBase m_currentState;

    //机器初始化时,没有上一个状态
    public StateMachine(StateBase beginState)
    {

        m_currentState = beginState;

        m_StateCache = new Dictionary<int, StateBase>();
        //把状态添加到集合中
        AddState(beginState);
        m_currentState.OnEnter();
    }

    public void AddState(StateBase state)
    {
        if (!m_StateCache.ContainsKey(state.ID))
        {
            m_StateCache.Add(state.ID, state);
            state.machine = this;
        }
    }

    //通过Id来切换状态
    public void TranslateState(int id)
    {
        if (!m_StateCache.ContainsKey(id))
        {
            Debug.Log("未添加ID");
            return;
        }

        if (m_currentState.ID == id)
        {
            Debug.Log("正处于"+ m_StateCache[id] + "状态");
            return;
        }

        m_currentState.OnExit();
        m_currentState = m_StateCache[id];
        m_currentState.OnEnter();
        Debug.Log("切换至" + m_StateCache[id] + "状态");
    }

    //状态保持
    public void Update()
    {
        if (m_currentState != null)
        {
            m_currentState.OnStay();
        }
    }
}

其他注意的点

在这里插入图片描述

  • 如果你改写了玩家脚本,记得要在LateUpdate()中进行调用,不然会拿不到stay()状态。
  • 可以将所有行为写在一个脚本文件的不同类里
    在这里插入图片描述
  • 并且通过owner关键字可以调用到你关联的脚本
    在这里插入图片描述

方案三

利用unity的动画状态机
在这里插入图片描述
创建空的动画用来表示事件,并通过bool开关进行控制

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值