文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-05-19 08:57

关注

一、状态模式定义

状态模式(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(具体状态类)

   
    //状态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状态模式内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯