首页 > 编程知识 正文

unity实现有限状态机,unity3d 状态机

时间:2023-05-03 21:33:01 阅读:190459 作者:4490

在游戏开发过程中,各种游戏状态的切换随处可见。 但是,给单纯粗暴的if else添加标志的方式经常不能很好地解决状态复杂的变换问题,在这种情况下,可以使用状态模式和状态机有效地完成任务。 状态模式与状态机密切相关,因此经常一起讨论和运用。 本文将探讨他们在游戏开发中的使用。

当然,想让我好好理解,但我觉得不可能。 依旧进行文章和代码分析,最后进行总结。 首先通过几个小案例进行说明,了解有限状态机在什么样的运用,然后根据这些案例进行总结,最后规范有限状态机和有限状态机在unity中的分发和作用。

情况之一: NPC发现Player发射炮弹,简单的if () { }elseif )也是一种状态机,只是比较简单

代码如下所示。

效果如下

情况2 )枚举和Switch case的组合,该模式可以采用,代码比较规则,容易理解:

首先在枚举中枚举所有状态,然后写方法,进行switch case并枚举绑定到每个状态的函数。 然后,实际使用每个枚举类型绑定的函数。 然后用Update函数进行监听。

实际上,也可以将Fsm_enum这样的脚本组合到一个实例中进行全局调用。

以上两个是简单的有限状态机。 游戏中人物的状态会不断变化,所以有必要写FSM来管理状态。 有限状态机可为装置或装置模型,其可具有有限数目的状态,且可基于输入而在任何时间操作,以便将一个状态转变到另一状态,或产生一个输入或动作。 有限状态机在任何瞬间都只能成为一种状态。

案例3 :典型状态机设计模式

有限状态机设计的核心原则是单一职责原则和fqdmt置换原则。 单一的作用是所有状态都有特殊的脚本来处理他的行为。 fqdmt置换原则:所有具体的状态类都被一个抽象类继承,不管其状态是实例化的对象,都可以通过基类进行。

大体上状态机模式的实现需要三个点。 1、为所有状态定义一个接口或基类

2、按状态定义类

3、妥善进行状态委托(关联,如何实现类和方法的调用) )。

通常,在状态模式下存储状态对象有两种实现存储的思路。

1、静态状态是指初始化时将所有可能的状态设为new,在状态切换时通过代入改变现在的状态

2、实例化状态,每次切换状态时,new动态地出现新的状态

分析一下下面的例子吧。 有三个场景:主场景、电池场景和开始场景。 基类ISceneState,场景控制类打开SceneStateManager、游戏或所有脚本的类GameContext。 脚本代码如下所示。 在GameContext类中对代码进行了项目符号分析。

ISceneState基类

电池扫描

MainMenuSceneState

StartSceneState

方案管理器

由MonoBehaviour继承并挂载在开始场景的游戏对象上的开始游戏场景的类

剩下的是上面案例代码的所有分析

///summary

//每个场景继承的基类

////summary

//ISceneState类的内容

//protectedstringmscenename { get; set; }

//publiciscenestate (stringscenename ) { this.mSceneName=sceneName; }

创建ISceneState类时,将为字符串类型的mSceneName赋值

///summary

//各场景的管理类SceneStateManager

////summary

//此类是单个实例,SceneStateManager.GetInstance )是为了检索SceneStateManager类中的唯一对象而执行的

//privete ISceneState mState{get; set; }这是为了赋值。

//publicvoidsetscenestate () iscenestatestate ) )。

//{

//if(Mstate!=null如果当前场景不为空,则结束当前场景

//

 {
//        mState.EndScene();
//    }
//    mState = state;  //同时开始传入要开始的场景   经过这一步mState肯定不为空了
//    if (mState != null)
//    {
//        mState.StartScene();
//    }
//}
//这个SetSceneState()方法中无形之间有了一个循环,bzdrg调用这个方法传入一个ISceneState子类对象时候
//开始判断如果当前mState不为空,就表示已经有场景在运行了。那就当有调用SetScenenState()的时候mState.EndScenen;
//然后再给mState = state 相当于重新赋值
//最后在进行mState.StartScenen

///<summary>
///BattleScene继承ISceneState
///</summary>
//继承有参构造器public BattleScene() : base("BattleScene"){ },当创建BattleScene对象的时候就会给mScenenName赋值
//就可以执行
//public override void StartScene()
//{
//    SceneManager.LoadScene(this.mSceneName)
//}

//同理
///<summary>
///MainMenuSceneState类
///</summary>
//public class MainMenuSceneState : ISceneState
//{
//    public MainMenuSceneState() : base("MainMenuScene")
//    {
//    }
//    public override void StartScene()
//    {
//        SceneManager.LoadScene(this.mSceneName);
//    }
//}

///<summary>
///场景开始界面控制脚本StartSceneState
///</summary>
//同样StartSceneState继承ISceneState类,也是一个界面,只是是开始界面,所以有一些功能的集成
//首先还是继承ISceneState这个构造器,只要创建StartSceneState这个类的子类,就会给mSceneName进行赋值
//public StartSceneState():base("StartScene "){ }
//然后在开始界面中添加两个按钮事件    控制界面的转换  重写基累中的StartScene方法
//public override void StartScene()
//{
//    GameObject.FindGameObjectWithTag("Battle").GetComponent<Button>().onClick.AddListener(OnBtnBattle);
//    GameObject.FindGameObjectWithTag("MainMenu").GetComponent<Button>().onClick.AddListener(OnBtnMainMenu);
//}
//按钮点击事件
//private void OnBtnBattle()
//{
//      SceneStateManager.GetInstance().SetSceneSate(new BattleScene())
//}
//private void OnBtnMainMenu()
//{
//      SceneStateManager.GetInstance().SetSceneSate(new MainMenuSceneState())
//}

///<summary>
///创建一个基类调用SceneStateManager类,继承于MonoBehaviour开始调用脚本,挂载到开始场景中的游戏对象上
///开始运行程序
///</summary>
//class GameContext:MonoBehaviour
//{
//      void Start()   //刚一开始就开启StartScene场景
//      {
//            SceneStateManager.GetInstance.SetSceneState(new StartSceneState());
//      }
//      void Update()  //在Update函数函数中进行更细
//      {
//            SceneStateManager.GetInstance.UpdateSceneState();
//            这个更新函数是BattleScene类    StartSceneState类   MainMenuScene类这三个类里面需要重写具体实现的
//      }
//}

     在这个案例中,我们首先定义可一个基类ISceneState类,在这个基类中,定义了一个string类型的属性(mScenenName),以及一个带有string类型参数的构造器。当启动构造器的时候就给属性赋值。此外还包含三个虚函数SartScene(){ }、UpdateScene(){ }、EndScene(){ }。当三个子类MainMenuSceneState、BattleScene、StartSceneState继承以后、首先通过构造器给mSceneName赋值,然后就是可执行切换场景的功能。


       根据之前我们总结的这个案例符合状态模式的实现三个要点,在状态对象存放方式上采用了第二种:即实例化状态,每次切换状态的时候动态的new出来新的状态。这一篇就先到这里,我准备用两个篇幅专门用于解析状态机和状态模式。


之前买了一本书,关于游戏开发和设计模式的,看到了状态模式设计,关于用状态模式进行场景场景切换的代码小框架。我写这些的用处主要时自己学习,加深巩固。如果你会了,或者觉得小儿科,原谅我,你可以无视。所以,即便很多类似相同,我还是决定继续刨析一遍。



版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。