• 【Unity 框架】QFramework v1.0 使用指南 架构篇:06. 引入 System | Unity 游戏框架 | Unity 游戏开发 | Unity 独立游戏


    在这一篇,我们来引入最后一个基本概念 System。

    首先我们来看下代码,如下:

    using UnityEngine;
    using UnityEngine.UI;
    
    namespace QFramework.Example
    {
        
        // 1. 定义一个 Model 对象
        public class CounterAppModel : AbstractModel
        {
            private int mCount;
    
            public int Count
            {
                get => mCount;
                set
                {
                    if (mCount != value)
                    {
                        mCount = value;
                        PlayerPrefs.SetInt(nameof(Count),mCount);
                    }
                }
            }
    
            protected override void OnInit()
            {
                var storage = this.GetUtility<Storage>();
    
                Count = storage.LoadInt(nameof(Count));
    
                // 可以通过 CounterApp.Interface 监听数据变更事件
                CounterApp.Interface.RegisterEvent<CountChangeEvent>(e =>
                {
                    this.GetUtility<Storage>().SaveInt(nameof(Count), Count);
                });
            }
        }
    
        // 定义 utility 层
        public class Storage : IUtility
        {
            public void SaveInt(string key, int value)
            {
                PlayerPrefs.SetInt(key,value);
            }
    
            public int LoadInt(string key, int defaultValue = 0)
            {
                return PlayerPrefs.GetInt(key, defaultValue);
            }
        }
    
    
        // 2.定义一个架构(提供 MVC、分层、模块管理等)
        public class CounterApp : Architecture<CounterApp>
        {
            protected override void Init()
            {
                // 注册 Model
                this.RegisterModel(new CounterAppModel());
                
                // 注册存储工具的对象
                this.RegisterUtility(new Storage());
            }
        }
        
        // 定义数据变更事件
        public struct CountChangeEvent // ++
        {
            
        }
        
        // 引入 Command
        public class IncreaseCountCommand : AbstractCommand 
        {
            protected override void OnExecute()
            {
                this.GetModel<CounterAppModel>().Count++;
                this.SendEvent<CountChangeEvent>(); // ++
            }
        }
        
        public class DecreaseCountCommand : AbstractCommand
        {
            protected override void OnExecute()
            {
                this.GetModel<CounterAppModel>().Count--;
                this.SendEvent<CountChangeEvent>(); // ++
            }
        }
    
        // Controller
        public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
        {
            // View
            private Button mBtnAdd;
            private Button mBtnSub;
            private Text mCountText;
            
            // 4. Model
            private CounterAppModel mModel;
    
            void Start()
            {
                // 5. 获取模型
                mModel = this.GetModel<CounterAppModel>();
                
                // View 组件获取
                mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();
                mBtnSub = transform.Find("BtnSub").GetComponent<Button>();
                mCountText = transform.Find("CountText").GetComponent<Text>();
                
                
                // 监听输入
                mBtnAdd.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand<IncreaseCountCommand>();
                });
                
                mBtnSub.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
                });
                
                UpdateView();
                
                // 表现逻辑
                this.RegisterEvent<CountChangeEvent>(e =>
                {
                    UpdateView();
    
                }).UnRegisterWhenGameObjectDestroyed(gameObject);
            }
            
            void UpdateView()
            {
                mCountText.text = mModel.Count.ToString();
            }
    
            // 3.
            public IArchitecture GetArchitecture()
            {
                return CounterApp.Interface;
            }
    
            private void OnDestroy()
            {
                // 8. 将 Model 设置为空
                mModel = null;
            }
        }
    }
    
    

    这里我们假设一个功能,即策划提出了一个成就达成的功能,即 Count 到 10 的时候,触发一个点击达人成就,点击二十次 则触发一个 点击专家成就。

    逻辑听起来很简单,我们直接在 IncreaseCountCommand 里编写即可,如下:

        public class IncreaseCountCommand : AbstractCommand 
        {
            protected override void OnExecute()
            {
                var model = this.GetModel<CounterAppModel>();
                    
                model.Count++;
                this.SendEvent<CountChangeEvent>(); // ++
    
                if (model.Count == 10)
                {
                    Debug.Log("触发 点击达人 成就");
                }
                else if (model.Count == 20)
                {
                    Debug.Log("触发 点击专家 成就");
                }
            }
        }
    

    代码很简单,我们运行测试一下。

    运行之后,笔者点击了 20 次 + 号,结果如下:

    image.png

    这个功能很快就完成了。

    但是这个时候策划说,希望再增加一个当点击 - 号到 -10 时,触发一个 点击菜鸟成就,然后策划还说,点击达人 和 点击专家 成就太容易达成了,需要分别改成 1000 次 和 2000 次。

    而这次策划提出的需求,需要我们修改两处的代码,即 IncreaseCountCommand 里需要修改数值为 1000 和 2000,然后再 DecreaseCountCommand 增加一个判断逻辑。

    一次提出的需求,结果造成了多处修改,这说明代码有问题。

    首先像这种规则类的逻辑,比如分数统计或者成就统计等代码,不适合分散写在 Command 里,而适合统一写在一个对象里,而这种对象,在 QFramework 里有提供,就是 System 对象。

    使用代码如下:

    using UnityEngine;
    using UnityEngine.UI;
    
    namespace QFramework.Example
    {
        
        // 1. 定义一个 Model 对象
        public class CounterAppModel : AbstractModel
        {
            private int mCount;
    
            public int Count
            {
                get => mCount;
                set
                {
                    if (mCount != value)
                    {
                        mCount = value;
                        PlayerPrefs.SetInt(nameof(Count),mCount);
                    }
                }
            }
    
            protected override void OnInit()
            {
                var storage = this.GetUtility<Storage>();
    
                Count = storage.LoadInt(nameof(Count));
    
                // 可以通过 CounterApp.Interface 监听数据变更事件
                CounterApp.Interface.RegisterEvent<CountChangeEvent>(e =>
                {
                    this.GetUtility<Storage>().SaveInt(nameof(Count), Count);
                });
            }
        }
    
    
        public class AchievementSystem : AbstractSystem // +
        {
            protected override void OnInit()
            {
                var model = this.GetModel<CounterAppModel>();
    
                this.RegisterEvent<CountChangeEvent>(e =>
                {
                    if (model.Count == 10)
                    {
                        Debug.Log("触发 点击达人 成就");
                    }
                    else if (model.Count == 20)
                    {
                        Debug.Log("触发 点击专家 成就");
                    } else if (model.Count == -10)
                    {
                        Debug.Log("触发 点击菜鸟 成就");
                    }
                });
            }
        }
    
        // 定义 utility 层
        public class Storage : IUtility
        {
            public void SaveInt(string key, int value)
            {
                PlayerPrefs.SetInt(key,value);
            }
    
            public int LoadInt(string key, int defaultValue = 0)
            {
                return PlayerPrefs.GetInt(key, defaultValue);
            }
        }
    
    
        // 2.定义一个架构(提供 MVC、分层、模块管理等)
        public class CounterApp : Architecture<CounterApp>
        {
            protected override void Init()
            {
                // 注册 System 
                this.RegisterSystem(new AchievementSystem()); // +
                 
                // 注册 Model
                this.RegisterModel(new CounterAppModel());
                
                // 注册存储工具的对象
                this.RegisterUtility(new Storage());
            }
        }
        
        // 定义数据变更事件
        public struct CountChangeEvent // ++
        {
            
        }
        
        // 引入 Command
        public class IncreaseCountCommand : AbstractCommand 
        {
            protected override void OnExecute()
            {
                var model = this.GetModel<CounterAppModel>();
                    
                model.Count++;
                this.SendEvent<CountChangeEvent>(); // ++
            }
        }
        
        public class DecreaseCountCommand : AbstractCommand
        {
            protected override void OnExecute()
            {
                this.GetModel<CounterAppModel>().Count--;
                this.SendEvent<CountChangeEvent>(); // ++
            }
        }
    
        // Controller
        public class CounterAppController : MonoBehaviour , IController /* 3.实现 IController 接口 */
        {
            // View
            private Button mBtnAdd;
            private Button mBtnSub;
            private Text mCountText;
            
            // 4. Model
            private CounterAppModel mModel;
    
            void Start()
            {
                // 5. 获取模型
                mModel = this.GetModel<CounterAppModel>();
                
                // View 组件获取
                mBtnAdd = transform.Find("BtnAdd").GetComponent<Button>();
                mBtnSub = transform.Find("BtnSub").GetComponent<Button>();
                mCountText = transform.Find("CountText").GetComponent<Text>();
                
                
                // 监听输入
                mBtnAdd.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand<IncreaseCountCommand>();
                });
                
                mBtnSub.onClick.AddListener(() =>
                {
                    // 交互逻辑
                    this.SendCommand(new DecreaseCountCommand(/* 这里可以传参(如果有) */));
                });
                
                UpdateView();
                
                // 表现逻辑
                this.RegisterEvent<CountChangeEvent>(e =>
                {
                    UpdateView();
    
                }).UnRegisterWhenGameObjectDestroyed(gameObject);
            }
            
            void UpdateView()
            {
                mCountText.text = mModel.Count.ToString();
            }
    
            // 3.
            public IArchitecture GetArchitecture()
            {
                return CounterApp.Interface;
            }
    
            private void OnDestroy()
            {
                // 8. 将 Model 设置为空
                mModel = null;
            }
        }
    }
    
    

    代码越来越多,但是不难。

    运行游戏,笔者点击的结果如下:

    结果没问题。

    好了,笔者写的成就系统非常简陋,实际上额度成就系统可以写得非常完善,比如可以再成就系统里进行存储加载等操作,而此文的成就系统仅仅是展示目的。

    到此,我们就接触到了 QFramework 架构所提供的核心概念。

    我们回顾一下第一篇的两张图,如下:

    到此,大家应该能看懂这两张图了。

    QFramework 总共分四个层级,即

    • 表现层:IController
    • 系统层:ISystem
    • 数据层:IModel
    • 工具层:IUtility

    除了四个层级,还接触了为 Controller 的交互逻辑减负的 Command 和 为表现逻辑减负的 Event。

    还有一个非常重要的 CQRS 原则的简易版本,Command->Model->State Changed Event。

    到目前为止 QFramework 的基本用法我们过了一遍了。

    从下一篇开始,我们开始介绍 QFramework 架构提供的剩余功能,这些功能是可选的。

    这篇就到这里。

    更多内容

  • 相关阅读:
    BZOJ4416 SHOI2013阶乘字符串(状压dp)
    雅礼集训 Day2 T3 联盟 解题报告
    雅礼集训 Day1 T2 折射
    雅礼集训 Day1 T1 养花
    P1494 [国家集训队]小Z的袜子/莫队学习笔记(误
    洛谷 P2155 [SDOI2008]沙拉公主的困惑 解题报告
    动态MST
    洛谷 P2606 [ZJOI2010]排列计数 解题报告
    牛客 2018NOIP 模你赛2 T2 分糖果 解题报告
    洛谷 P3396 哈希冲突 解题报告
  • 原文地址:https://www.cnblogs.com/liangxiegame/p/16798135.html
Copyright © 2020-2023  润新知