探秘Unity游戏开发中的状态设计模式

 更新时间:2023年05月06日 10:20:41   作者:iukam  
这篇文章主要介绍了探秘Unity游戏开发中的状态设计模式,状态模式是Unity游戏开发中常用的一种设计模式,可以帮助开发者更好地管理游戏对象状态,提高游戏的可维护性和可扩展性

一、状态模式定义

状态模式(state)在GoF中的解释:

让一个对象的行为随着内部状态的改变而改变,而该对象也想换了类一样。

二、实现范例

结构图:

Context(状态拥有者)

  /// <summary>
    /// Describe:状态拥有者
    /// Note:是一个具有“状态”属性的类,可以制定相关的接口,让外界能够得知状态的改变或通过操作让状态改变。
    /// 比如:游戏角色有潜行,攻击、施法等状态;好友上线,脱机、忙碌等状态;
    /// GoF使用TCP联网为例,有已连接、等待连接、短线等状态;
    /// </summary>
    public class Context
    {
        State state = null;
        public void Request(int Value)
        {
            state.Handle(Value);
        }
        public void SetState(State state)
        {
            this.state = state;
        }
    }

State(状态接口类)

 /// <summary>
    /// Describe:状态接口类
    /// Note:指定状态的接口,负责规范Context(状态拥有者)在特定状态下要表现的行为。
    /// </summary>
    public abstract class State
    {
        protected Context m_Context = null;
        public State(Context context)
        {
            m_Context = context;
        }
        public abstract void Handle(int Value);
    }

ConcreteState(具体状态类)

   /*
     Describe:具体状态类
     Note:
     1、继承自State(状态接口类)
     2、实现Context(状态拥有者)在特定状态下该有的行为。
 */
    //状态A
    public class ConcreteStateA : State
    {
        public ConcreteStateA(Context context) : base(context) 
        { }
        public override void Handle(int Value)
        {
            if (Value>10)
            {
                m_Context.SetState(new ConcreteStateB(m_Context));
            }
        }
    }
    //状态A
    public class ConcreteStateB : State
    {
        public ConcreteStateB(Context context) : base(context)
        { }
        public override void Handle(int Value)
        {
            if (Value > 10)
            {
                m_Context.SetState(new ConcreteStateC(m_Context));
            }
        }
    }
    //状态A
    public class ConcreteStateC : State
    {
        public ConcreteStateC(Context context) : base(context)
        { }
        public override void Handle(int Value)
        {
            if (Value > 10)
            {
                m_Context.SetState(new ConcreteStateA(m_Context));
            }
        }
    }

三、使用状态模式(state)实现游戏场景的转换

场景结构示意图:

ISceneState 场景类接口

  /// <summary>
    /// Describe:场景类接口
    /// Note:定义场景转换和执行时需要调用的方法。
    /// </summary>
    public class ISceneState
    {
        //状态名称
        private string m_StateName = "ISceneState";
        public string StateName
        {
            get => m_StateName;
            set => m_StateName = value;
        }
        //控制者
        protected SceneStateController m_Controller = null;
        //建造者
        public ISceneState(SceneStateController controller)
        {
            m_Controller = controller;
        }
        //开始
        public virtual void StateBegin() { }
        //结束
        public virtual void StateEnd() { }
        //更新
        public virtual void StateUpdate() { }
        //结束
        public override string ToString() 
        {
            return $"[I_SceneState: StateName={StateName}]";
        }
    }

三个可切换场景(主画面场景,主画面场景,战斗场景)

主画面场景

  /// <summary>
    /// Describe:开始场景
    /// </summary>
    public class StartState : ISceneState
    {
        public StartState(SceneStateController controller) : base(controller)
        {
            this.StateName="StartState";
        }
        //开始
        public override void StateBegin()
        {
            //可在此进行游戏数据加载和初始化
        }
        //更新
        public override void StateUpdate() 
        {
            //更换为
            m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuScene");
        }
    }

主画面场景

 /// <summary>
    /// Author:maki
    /// Time:2021-12-2
    /// Describe:主画面场景
    /// </summary>
    public class MainMenuState:ISceneState
    {
        private Button tmpBtn;
        public MainMenuState(SceneStateController controller) : base(controller)
        {
            this.StateName = "MainMenuState";
        }
        //开始
        public override void StateBegin()
        {
            //获取开始按钮
            // tmpBtn=UITool.GetUIComponent<Button>("StartGameBtn");
            tmpBtn?.onClick.AddListener(()=>OnStartGameBtnClick(tmpBtn));
        }
        //开始游戏
        private void OnStartGameBtnClick(Button tmpBtn)
        {
            m_Controller.SetState(new BattleState(m_Controller), "BattleScene");
        }
    }

战斗场景

   /// <summary>
    /// Author:maki
    /// Time:2021-12-2
    /// Describe:战斗场景
    /// </summary>
    public class BattleState:ISceneState
    {
        public BattleState(SceneStateController controller) : base(controller)
        {
            this.StateName = "BattleState";
        }
        //开始
        public override void StateBegin() 
        { 
        }
        //结束
        public override void StateEnd() 
        {
        }
        //更新
        public override void StateUpdate() 
        {
            //输入
            InputProcess();
            //游戏逻辑
            //游戏是否结束
            m_Controller.SetState(new MainMenuState(m_Controller), "MainMenuState");
        }
        //输入
        private void InputProcess()
        {
          //玩家输入判断程序代码。。。
        }
    }

SceneStateController-场景状态控制者

   /// <summary>
    /// Author:maki
    /// Time:2021-12-2
    /// Describe:场景状态的拥有者(Context),保持当前游戏场景状态,并作为与GameLoop类互动的接口,
    /// 除此以外,也是U3D场景转换的地方。
    /// </summary>
    public class SceneStateController
    {
        private ISceneState m_State;
        private bool m_bRunBegin = false;
        public SceneStateController() { }
        //设置状态
        public void SetState(ISceneState state, string loadSceneName)
        {
            m_bRunBegin = false;
            //载入场景
            LoadScene(loadSceneName);
            //通知前一个State结束
            if (m_State != null)
                m_State.StateEnd();
            //设置
            m_State = state;
        }
        //载入场景
        private void LoadScene(string loadSceneName)
        {
            if (string.IsNullOrEmpty(loadSceneName))
            {
                return;
            }
            SceneManager.LoadScene(loadSceneName);
            //  Application.LoadLevel(loadSceneName); 过时
        }
        //更新
        public void StateUpdate()
        {
            //通知新的State开始
            if (m_State != null && m_bRunBegin == false)
            {
                m_State.StateBegin();
                m_bRunBegin = true;
            }
            if (m_State != null)
            {
                m_State.StateUpdate();
            }
        }
    }

GameLoop-游戏主循环类

 /// <summary>
    /// Author:maki
    /// Time:2021-12-2
    /// Describe:游戏主循环类
    /// Note:包含初始化游戏和定期调用更新操作
    /// </summary>
    public class GameLoop:MonoBehaviour
    {
        //场景状态
        SceneStateController sceneStateController = new SceneStateController();
       void Awake()
        {
            // 转换场景不会被删除
            GameObject.DontDestroyOnLoad(gameObject);
            //随机数种子
            Random.seed = (int)System.DateTime.Now.Ticks;
        }
        private void Start()
        {
            //设置起始场景
            sceneStateController.SetState(new StartState(sceneStateController), "");
        }
        private void Update()
        {
            sceneStateController.StateUpdate();
        }
    }

四、使用状态模式的优点

优点

  • 减少错误的发生并降低维护难度;
  • 状态执行环境单一化;
  • 项目之间可以共享场景;

具体来说,使用状态模式可以清楚地了解某个场景状态执行时所需要配合使用的类对象,并且减少因新增状态而需要大量修改现有程序代码的维护成本。

缺点

在应用有大量状态的系统时,会遇到“产生过多状态类”的情况,此时会伴随着类爆炸的问题。

到此这篇关于探秘Unity游戏开发中的状态设计模式的文章就介绍到这了,更多相关Unity状态模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C# 将数据库SqlServer数据绑定到类中的过程详解

    C# 将数据库SqlServer数据绑定到类中的过程详解

    本文讲述的是读取数据库中数据的常用做法,即将数据库中的数据绑定到创建的类中,再将类绑定到DataGridView的数据源中的做法,对C#将SqlServer数据绑定到类中感兴趣的朋友一起看看吧
    2022-06-06
  • c# 9.0新特性nint和Pattern matching的使用方法

    c# 9.0新特性nint和Pattern matching的使用方法

    这篇文章主要介绍了c# 9.0新特性nint和Pattern matching的使用方法,文中讲解非常细致,帮助你更好的学习c# 9.0,有需求的朋友可以参考下
    2020-06-06
  • C# 基于消息发布订阅模型的示例(上)

    C# 基于消息发布订阅模型的示例(上)

    这篇文章主要介绍了C# 基于消息发布订阅模型的示例,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • c# wpf如何附加依赖项属性

    c# wpf如何附加依赖项属性

    这篇文章主要介绍了c# wpf如何附加依赖项属性,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • Unity Shader实现径向模糊效果

    Unity Shader实现径向模糊效果

    这篇文章主要为大家详细介绍了Unity Shader实现径向模糊效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • LINQ(语言集成查询)使用案例

    LINQ(语言集成查询)使用案例

    这篇文章介绍了LINQ(语言集成查询)的使用案例,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • C#使用ThreadPriority设置线程优先级

    C#使用ThreadPriority设置线程优先级

    这篇文章介绍了C#使用ThreadPriority设置线程优先级的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • C# WinForm自动更新程序之文件上传操作详解

    C# WinForm自动更新程序之文件上传操作详解

    这篇文章主要为大家详细介绍了C# WinForm自动更新程序中文件上传操作,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解一下
    2022-10-10
  • C#很简单而又很经典的一句代码实例

    C#很简单而又很经典的一句代码实例

    这篇文章主要给大家分享介绍了关于C#很简单而又很经典的一句代码,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-07-07
  • C#中使用Lambda表达式自定义比较器实现两个列表合并实例

    C#中使用Lambda表达式自定义比较器实现两个列表合并实例

    这篇文章主要介绍了C#中使用Lambda表达式自定义比较器实现两个列表的合并实例,本文给出示例代码和运行效果,需要的朋友可以参考下
    2014-10-10

最新评论