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

 更新时间:2023年05月06日 10:20:41   作者:iukam  
这篇文章主要介绍了探秘Unity游戏开发中的状态设计模式,状态模式是Unity游戏开发中常用的一种设计模式,可以帮助开发者更好地管理游戏对象状态,提高游戏的可维护性和可扩展性
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

一、状态模式定义

状态模式(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#存储相同键多个值的Dictionary实例详解

    C#存储相同键多个值的Dictionary实例详解

    在本篇文章里小编给大家整理的是关于C#存储相同键多个值的Dictionary实例内容,需要的朋友们可以学习下。
    2020-03-03
  • Silverlight实现跑马灯动画

    Silverlight实现跑马灯动画

    这篇文章主要为大家详细介绍了Silverlight实现跑马灯动画,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • C# 删除数组内的某个值、一组值方法详解

    C# 删除数组内的某个值、一组值方法详解

    在本篇文章里小编给大家整理的是关于C# 如何删除数组内的某个值、一组值的相关知识点,需要的朋友们学习下。
    2020-03-03
  • C#递归实现回文判断算法

    C#递归实现回文判断算法

    这篇文章主要介绍了C#递归实现回文判断算法,方法简单实用,需要的朋友可以参考下
    2014-10-10
  • C# 利用VS编写一个简单的网游客户端

    C# 利用VS编写一个简单的网游客户端

    本文主要介绍了在visual studio中利用C#编写一个简单的网游客户端,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • c#调用c++的DLL的实现方法

    c#调用c++的DLL的实现方法

    本文主要介绍了c#调用c++的DLL的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • asp.net实现遍历Request的信息操作示例

    asp.net实现遍历Request的信息操作示例

    这篇文章主要介绍了asp.net实现遍历Request的信息操作,涉及asp.net针对请求信息相关操作打印操作技巧,需要的朋友可以参考下
    2020-03-03
  • C# WPF如何反射加载Geometry几何图形数据图标

    C# WPF如何反射加载Geometry几何图形数据图标

    这篇文章主要介绍了C# WPF如何反射加载Geometry几何图形数据图标,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • 详解C#读取Appconfig中自定义的节点

    详解C#读取Appconfig中自定义的节点

    我们往往需要在App.config中自定义一些节来满足实际需要,而不依赖于App.config的appSettings,下面通过一个简单的实例来说明自定义配置节点的设置与读取
    2015-06-06
  • 在WPF中使用Interaction.Triggers

    在WPF中使用Interaction.Triggers

    这篇文章介绍了在WPF中使用Interaction.Triggers的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06

最新评论

?


http://www.vxiaotou.com