【Unity游戏开发日志】FSM有限状态机模板

在各类RPG游戏中,NPC是整个游戏结构中不可缺少的一环,也可以说是整个游戏的重要组成部分。

在设计NPC结构时,我们往往会给他们添加许多不同的状态,实现他们在游戏中的不同功能。倘若状态数过多,在一个NPC类使用switch,if-else语句来进行状态管理,在理论上违反了开放封闭原则,同时也不便于我们对程序的进一步维护管理。因此,我们引入了状态机这一设计模式。下文以NPC待机,巡逻状态为例。

整体状态机的设计分为三个部分:接口:IState,状态机管理类:FSM,状态类:以IdleState,PatrolState等等为例。

 第一部分:IState的设计代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//接口IState
public interface IState
{
    void OnEnter();//进入状态时执行

    void OnExit();//退出状态时执行

    void OnUpdate();//状态响应时执行

}

第二部分:FSM管理类的设计代码:

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

[Serializable]//注意这里的序列化!
//参数列表,根据你所需要的人物设计进行添加

public class Parameter
{
    public float moveSpeed;

    public float idleTime;

    public Transform[] patrolPoints;
    
    
}

public class FSM : MonoBehaviour
{
    
    public enum StateType
    {
        Idle,Patrol,InDialog//待机状态,巡逻状态,对话状态等等
    }
    public Parameter parameters;//传参数

    private IState currentState;//当前状态

    //字典存储状态 通过枚举类型的键值来找到应该要做出什么状态响应。
    private Dictionary<StateType,IState> states = new Dictionary<StateType,IState>();

    void Start()
    {
        //把各种状态添加入存储字典当中
        states.Add(StateType.Idle, new IdleState(this));
        states.Add(StateType.Patrol, new PatrolState(this));
        states.Add(StateType.InDialog, new DialogState(this));

        TransitionState(StateType.Idle);//状态机需要有一个初始状态,这里给到一个待机(IdleState)
    }

    // Update is called once per frame
    void Update()
    {
        currentState.OnUpdate();//持续执行当前状态响应
    }

    //切换状态的方法//
    public void TransitionState(StateType type)
    {
        if(currentState!=null)
        {
            currentState.OnExit();
        }
        currentState = states[type];//通过键值type找到相应的状态值
        currentState.OnEnter();
    }
}

第三部分:状态类的设计:

以下以待机类,巡逻状态类举例:

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

public class IdleState : IState
{

    private FSM manager;//状态机管理类引入

    private Parameter parameter;//参数获取途径

    private float timer=0;//待机状态持续多长时间,通过一个Timer变量计时

    public IdleState(FSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameters;
    }//构造函数,是用于状态的存储
    
    public void OnEnter()
    {
        
    }

    public void OnExit()
    {
        timer = 0;
    }

    public void OnUpdate()
    {
        timer += Time.deltaTime;
        if(timer>=parameter.idleTime)
        {
            manager.TransitionState(FSM.StateType.Patrol);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PatrolState : IState
{

    private FSM manager;

    private Parameter parameter;

    private int patrolPostion;

    public PatrolState(FSM manager)
    {
        this.manager = manager;
        this.parameter = manager.parameters;
    }

    public void OnEnter()
    {
        Debug.Log("进入巡逻状态");
    
    }

    public void OnExit()
    {
        patrolPostion++;

        if(patrolPostion>=parameter.patrolPoints.Length)
            patrolPostion=0;
    }

    public void OnUpdate()
    {
        manager.transform.position = Vector2.MoveTowards(manager.transform.position,
    parameter.patrolPoints[patrolPostion].position, parameter.moveSpeed * Time.deltaTime);
        if (Vector2.Distance(manager.transform.position, parameter.patrolPoints[patrolPostion].position) <= 0f)
        {
            manager.TransitionState(FSM.StateType.Idle);//如果小于0f的距离,那就说明在待机点的附近,此时角色切换到待机状态
        }
    }
}

运行实例:

把FSM挂在到对应的NPC物体上,通过Inspector窗口对相关变量进行赋值:

 运行效果:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shotar0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值