zoukankan      html  css  js  c++  java
  • “PurMVC”在Unity中的应用

    序章:

      这是"游戏设计进阶技巧篇"内容,游戏中不使用如下技巧也可以正常运行,但是有了它以后可以增加项目的可读性,使功能”模块化“,”可视化“,”装逼化“(慢慢的恶意>,>)。

      游戏设计进阶技巧篇内容整体包含:

    1. PureMvc框架
    2. 设计模式
    3. 数据结构 & 算法

      框架:这部分当然就是我下面要讲的PureMVC框架(C#)了,它总体来说是一种消息传递机制思想,通过反射形式实现的。

      设计模式:抽象工厂 AB对象池(详情见“对象池篇”)

      数据结构与算法:最大堆,顺序表,链表,循环队列

      简而言之:框架是大智慧,用来对软件设计进行分工;设计模式是小技巧,对具体问题提出解决方案,提高代码复用度,降低耦合;数据结构和算法是工具,无形中支撑起整个游戏。

      学了这些内容你就不能算是一个小白了!咋个也可以算个初级程序员了吧!!

    正文:


    MVC:

      全名“Model View Controller” 模型_视图_控制器 的缩写,一种软件的典范,将逻辑数据界面分离的代码组织方法。好!反正很牛B就对了!

    优点:

      1.耦合低,模块化

      2.代码复用度高 (这个我倒没觉得有啥特别感想!)

      3.部署快 

      4.利于多人项目合作

      5.可维护度,可读性高

    缺点:

      1.理解耗时 反射方面虽然用的不多,但是我也不怎么用反射所以能看懂但不推荐大量使用反射。

      2.不利于中小项目?这尼玛我就更不同意了,我一个人写项目都喜欢MVC!

      3. 由于其设计的关系,在添加一个消息时,需要“注册”“删除”“关心”“处理”,使用起来会比较麻烦,没有传统模式来的简单直接。

    PureMVC 官网结构图:

      

    这张图,我能看出来的仅仅是下列几点

      1. Facade 外观模式 ,与“游戏业务逻辑”所有交互都通过它走,它包含了Proxy(M),Mediator(V),Controller(C)3个实例(单例)。

      2. 所有视图UI都被一个叫“Mediator”的类所管理,它负责接收Command消息并通知其UI做对应相应。

      3. 所有的Command 被 Controller管理,然而controller其实没啥重要的事可以做,除了收到消息时 执行一下 对应command的Execute方法。

      4. 上图数据可以是local也可以是Remote数据这块我理解的不是很清楚,但是我数据这部分不会用它的Proxy。

    个人见解:

      我使用PureMVC的目的是在于断开耦合,而它的Proxy数据部分就是一个“字典(Dictionary)”没啥特别的,所以玩家数据部分我还是习惯写单例获取,UI数据就存在自己身上,仅仅使用其“消息传递机制部分”。什么叫消息传递机制呢,如果按照传统的类关联形式,类A要调用类B的函数,在没有中间者出现的时候,A类中必然会出现B类的名称~,而PureMVC就是通过“装箱”“开箱”操作提供了这样的一个中间者(第三者)类似于邮递员,A类可以通过这个邮递员在完全不与B类接触的情况下调用B类的函数,而当A类是“一对多”或”多对多”形式时,这种设计模式就更是讨喜,某个类的消失并不会大量影响代码逻辑,让代码的健壮度大大提升!

    使用篇:

    1. 当然是导入对应代码了!!我这里保留一份下载地址 链接:https://pan.baidu.com/s/1RMrmN9y6yxUP3co2Hklsyw 密码:xu96
    2. 将 修改“AppFacade”“Const_GameTest”代码,修改AppFacade的类型名,使之与其他游戏区分开(如果大厅中包含2个使用同一框架的游戏,名字相同会导致BUG);Const_XXX中添加开始游戏和关闭游戏的消息。
    3. 编写GameStartCommand类的Execute方法,注册其他Command、注册Mediator、删除开始游戏命令代码如下
    /***************************************
    Author: Tason
    Version: v1.0
    Last Updata: 2018-6-7 
    Tel: 159285XXXX
    Method of Use: 启动命令
    1.注册基础的用户数据
    ***************************************/
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using PureMVC.Patterns;
    using PureMVC.Interfaces;
    
    public class StartUpCommand : SimpleCommand
    {
        public override void Execute(INotification notification)
        {
            base.Execute(notification);
    
            //提示
            Debug.Log("Command Excute ----- GameStart");
    
            //注册Model - 这里不用模型
            //Facade.RegisterProxy(new UserProxy());
             
            //注册Command 这里要先注册Command 这关系掉调用顺序
            Facade.RegisterCommand(Const_GameTest.GAMEOVER, typeof(GameOverCommand));
            Facade.RegisterCommand(Const_GameTest.PREPIC, typeof(PrePicCommand));
            Facade.RegisterCommand(Const_GameTest.AFTERPIC, typeof(AfterPicCommand));
            Facade.RegisterCommand(Const_GameTest.DELPIC, typeof(DelPicCommand));
    
            //注册View
            Facade.RegisterMediator(new MiddleShowMediator(GameManager_GameTest.Instance.m_middleShowManager));
        
          
            
            //删除启动命令
            Facade.RemoveCommand(Const_GameTest.GAMESTART);
        }
    }
    View Code

      4. 编写Mediator用于接收消息(包括它关心什么,它如何响应2部分)

    /***************************************
    Editor: Tason
    Version: v1.0
    Last Edit Date: 2018-XX-XX 
    Tel: 328791554@qq.com
    Function Doc: 
    
    ***************************************/
    
    using UnityEngine;
    using PureMVC.Patterns;
    using PureMVC.Interfaces;
    using System.Collections.Generic;
    
    public class MiddleShowMediator : Mediator 
    {
        //名字
        public new const string NAME = "MiddleShowMediator";
    
        //关联到的类
        private MiddleShowManager View
        {
            get { return (MiddleShowManager)ViewComponent; }
        }
    
        //构造
        public MiddleShowMediator(object _viewComponent)
            : base(NAME, _viewComponent){}
    
    
        //添加关心的事件
        public override IList<string> ListNotificationInterests()
        {
            IList<string> list = new List<string>();
            list.Add(Const_GameTest.PREPIC);
            list.Add(Const_GameTest.AFTERPIC);
            return list;
        }
    
        //处理事件
        public override void HandleNotification(PureMVC.Interfaces.INotification notification)
        {
            switch (notification.Name)
            {
                case Const_GameTest.PREPIC:
                    Debug.Log("!!!");
                    View.ChangeDisplay(DataManager.Instance.GetCurrentSpriteName());
                    break;
                case Const_GameTest.AFTERPIC:
                    View.ChangeDisplay(DataManager.Instance.GetCurrentSpriteName());
                    break;
            }
        }
    }
    View Code

      5.编写GameManager用于启动MVC框架

       AppFacadeGT.Instance.StartUp();

      6.发送消息都是通过单例发送

    //带参消息 
    AppFacadeGT.Instance.SendNotification(Const_GameTest.PREPIC, "上一张?");
    //不带参消息
     AppFacadeGT.Instance.SendNotification(Const_GameTest.PREPIC);
    //带参Command解析
    public class AfterPicCommand : SimpleCommand
    {
        public override void Execute(INotification notification)
        {
    
            string a = notification.Body as string;
            Debug.Log(a);
        }
    }

    注意:

      1.消息部分请注意编写时尽量带上游戏名称简写,好与其他游戏进行区分。

      2.GameStartCommand 注册了的东西 在 GameOverCommand时一定要删除。

      3. 发送消息时Command的Execute运行顺序优先于,Mediator的HandleNotification。我觉得这样是正确的,如果要修改顺序,在注册时先注册Command后注册Mediator即可。反之就一定要先注册Command。

    项目链接:

      简单做了个demo,版本是Unity5.4.3f1 链接:https://pan.baidu.com/s/17chym5cYKqb2v5-kkGdjIw 密码:9uwz

    原理解析:

      1. GameManager中 AppFacadeGT.Instance.StartUp()时,AppFacade创建自身、Model、View、Controller单例,并注册了GameStart消息。

      2.GameCommand中 注册其他command & Mediator、但是逻辑写哪呢?是写在Command的Execute中还是Mediator的HandleNotification中执行逻辑?貌似都可以?

      当然不是!比如玩家扣钱,你在主页面要显示这个金钱,在背包界面也要现实金钱的时候,那么就会有2个物品存在扣钱的消息监听,如果你在2个Mediator中都执行扣钱逻辑,那玩家不就GG了!所以逻辑应该放在Command中而Mediator中只放自己的显示逻辑!

      3.注册部分,这里不管Proxy,View是核心部分,它管理了2个Dictionary数据结构,第一个IDictionary<string, IList<IObserver>> m_observerMap 存放 消息与监听者List,在注册Mediator或Command时,它会生成对应的监听者,存放在这个List中。第二个IDictionary<string, IMediator> m_mediatorMap 存放 mediator名称与mediator实例,这里面最重要的就是第一个表,它的反射代码如下:

      

                Type t = context.GetType();
                BindingFlags f = BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase;
                MethodInfo mi = t.GetMethod(method, f);
                mi.Invoke(context, new object[] { notification });        

      说实在的,这个pureMVC不太好讲,需要的知识点很多:

    1. 观察者模式  
    2. 外观模式
    3. 代理模式(Proxy中,没太在意)
    4. 命令模式
    5. 单例模式

      等,所以啊 我这只能提供代码,理解的话还是要自己去读代码!!!!!!!哈哈哈哈!!!

     提供一篇别人的PureMVC解析资料,感觉写的比我详细:https://blog.csdn.net/qq_29579137/article/details/73692842

  • 相关阅读:
    推荐一个wpf&sliverlight的图表控件
    数独求解
    WPF中的 CollectionChanged事件通知
    Windows 7 任务栏之缩略图预览(Thumbnail)
    把Google HK设为IE默认的搜索引擎
    F#小记——1. Hello F#
    F#小记——2. 基本数据类型
    使用异步socket的时候需要注意memory spike
    《everytime you kissed me》的中文歌词
    我回来了o(∩_∩)o...
  • 原文地址:https://www.cnblogs.com/jwv5/p/9152098.html
Copyright © 2011-2022 走看看