SimpleFramework NGUI/UGUI基础知识[2]

   看完上面的图,不知道是否已经对热更有了新的概念,如果有的话,我们继续说下,SimpleFramework怎么来做热更的具体步骤。

 

(1)第一步打包资源到StreaminAssets目录,为啥要打包到这个目录下呢?懂U3D游戏开发的都知道,这个目录会随着Unity最终生成APK/IPA的包原目录打包出去,我们的游戏客户端框架可以通过代码读取到里面的资源,并且把里面的资源复制到玩家的手机本地存储里面,这叫做解包。
那怎么打包呢?打包的资源分为素材资源与代码资源,这两部分的打包,框架都集成了,你可以直接修改里面的脚本逻辑适应自己的游戏项目,我们打开ulua/Editor/Packager.cs打包脚本。这里面根据不同的平台打包相应的资源。
 
    [MenuItem("Game/Build iPhone Resource", false, 11)]
    public static void BuildiPhoneResource() {
        BuildTarget target;
#if UNITY_5
        target = BuildTarget.iOS;
#else
        target = BuildTarget.iPhone;
#endif
        BuildAssetResource(target, false);
    }
 
    [MenuItem("Game/Build Android Resource", false, 12)]
    public static void BuildAndroidResource() {
        BuildAssetResource(BuildTarget.Android, true);
    }
 
    [MenuItem("Game/Build Windows Resource", false, 13)]
    public static void BuildWindowsResource() {
        BuildAssetResource(BuildTarget.StandaloneWindows, true);
    }
重要的函数是下面这个,它打包了框架自带例子的素材文件后,继续处理Lua代码文件的打包。
 
    public static void BuildAssetResource(BuildTarget target, bool isWin) {
        if (AppConst.ExampleMode) {
            HandleExampleBundle(target);
        }
        HandleLuaFile(isWin);
        AssetDatabase.Refresh();
    }
HandleExampleBundle函数就是将Examples/Builds下面的素材统一按照Unity的规则进行打包成assetbundle文件。没什么好说的。
 
我们主要是看HandleLuaFile函数的操作流程。
 
(1)在StreamingAssets目录下面新建lua目录,用于存放编码后的lua文件。
(2)遍历Lua目录下面所有的lua文件,并且根据目录结构创建相应目录树。
(3)如果AppConst.LuaEncode 设置了编码开关,就启动编码操作,否则直接复制源码过去。
(4)然后将前面的图片素材assetbundle跟相对应的lua文件目录,统一遍历计算出MD5/CRC,生成到files.txt里面。
 
这个代码就做了这几件事情,唯一需要展开介绍的只有怎么编码Lua文件了吧。这个函数其实并不长,
他就是根据相应的平台配置其编码器,编码器存放的路径也就是前面工程外的LuaEncoder的目录,拼凑出它的路径后,我们开始拼凑其编码的参数命令行,
需要注意的是luajit跟luavm的编码命令行不同:
luajit的:luajit.exe -b srcfile outfile
luavm的:luac -o outfile srcfile
命令行的格式其实都很简洁,然后我们启动C#的调用外部shell程序的代码,调用他们来编码出2进制文件即可。那最后统一计算MD5的文件就变成了编码的2进制的值。
 //------------------------------------------------------------------------------------------------------------
说完了打包流程,接下来说下怎么更新,只有能顺利更新下面后,才能够算作热更的最后一环。关于更新这一块,我们是用C#写成的,为啥?因为我们真实项目中,游戏的基础功能,比如下载、线程操作都建议在C#中完成,为了效率,而不是为了花架子都在lua中完成。因为这些基础功能,相对于游戏来说,更新的频率非常之低,用C#完成追求了效率,也没有任何损失。
 
我们打开Scripts/Manager/GameManager.cs文件,定位到IEnumerator OnUpdateResource()函数,
(1)它一上来就做些初始化的操作,找到更新的地址URL等。
(2)请求更新列表文件files.txt,因为里面存放了上面生成的目录结构及其MD5/CRC的信息。
(3)分析Web服务器上的files.txt文件内容,然后遍历检查本地的文件结构是否完整、MD5是否匹配。
(4)如果MD5不匹配,或者本地文件不存在,就开始创建一个下载请求,并且将它传递给线程,请求线程下载。
(5)本地协程会每一帧查询线程下载完后是否将下载的文件名存放到下载文件列表中,如果找到,继续下载下一个,直至全部下载完成。
其实当全部更新完成后,此时手机存储的文件结构及其内容已经是最新的了,客户端程序便可以顺利启动,完成了热更的最后一环。
 
2015/8/10 23:20:36
--------------------------------------------------------------------------------------------------------------
 
今天继续更新啊,说些啥呢,说下现在的Lua端的代码结构与怎么创建一个新的对话框出来,因为问的人较多,稍微介绍下这块。
经过改造过的代码架构有了变化,原来的lua除了管理器类,比如GameManager、NetworkManager等,每个面板文件直接就是一个类似xxxPanel.lua的格式,有人喜欢这个形式,有的人讨厌,觉得不够专业化,强调用过多。口味难调。
后来将xxxPanel.lua分开了,一个是纯粹的View层,名称还是xxxPanel.lua形式,它里面维护了面板的GameObject上面所有的控件变量,以便提供给xxxCtrl.lua使用,你可以用工具代码生成这一层。相比之下,大量的操作逻辑移到了xxxCtrl.lua里面,这样View层跟Controller层就此分离开了。那Module层因为没有数据,所以还是使用者自己添加吧,我就不画蛇添足,免得被人骂。
我们继续说Controller层,既然有了这一层,那就得有个管理器去管理Controller层,所以就出现了CtrlManager.lua,它里面维护了所有的控制器的关系,我们可以通过它获取需要的Controller,进而Open、Close操控View层。这样解释完,基本上都懂得为啥要这样操作了吧~~
接下来我们说下,怎么创建一个新的面板,样例代码请参考最新的版本,当下是0.3.7 f4版本。
(1)创建一个Unity3d的面板对象,不管你使用UGUI还是NGUI,请做好布局准备。
(2)如果是NGUI,请将这个面板的图集、Prefab等文件,加入到Editor/Package.cs的打包函数里面。
(3)如果是UGUI,请给这个面板的Prefab一个AssetBundle名称(我们用的U5新版打包方式),
(4)面板的名称请以"xxxPanel"命名,然后单击Game菜单Build XXX Resource打包素材。
(5)在lua中的Controller目录中添加相应控制器,比如MessageCtrl.lua,里面的格式按照框架示例添加。
(6)在lua中的View目录中添加相应的视图层,比如MessagePanel.lua,里面添加好面板的Button、Image的变量关联。
(7)在Logic/GameManager.lua里面的LuaScriptPanel函数里面添加面板的名称,作用是lua告诉c#哪些面板的lua文件需要提前加载到luavm。
(8)在CtrlManager.lua里面按照相应的格式,添加初始化控制器代码。
(9)非常非常重要的一步!!(很多人都会忽略),记得在Common/define.lua的初始化面板table中添加"MessagePanel",这样当C#的GameManager初始化的时候,才会将这个MessagePanel.lua注册进lua虚拟机里面。再当显示面板的时候,才不会出现类似"Push xxxPanel failed"的操作提示。
启动吧~
 
--------------------------------------------------------------------------------------------------------------
 今天帮大家梳理下新版框架的头,可能会说不完,慢慢更新吧。
 
看过老版框架同学应该知道,我的框架有个全局构造器“GlobalGenerator”对象,是框架的第一入口,之前的游戏管理器“GameManager”起源于它,InitGameMangager,也就是在它身上脚本用Prefab实例化的,但是新版里面没有了GameManager的Prefab,变成了直接new GameObject(),为了精简。
 
GameManager的对象创建了,需要往它身上添加管理器,这个跟原来的方式相同,没啥变化。但是变得有些绕,我也不能说PureMVC不好,但是的确不是我喜欢的,没办法,用的人多就是真理,顺了它了。
 
有一行代码AppFacade.Instance.StartUp();   //启动游戏,它其实就是启动PMVC,不懂的,自己查文档去,别问我。这行会启动PMVC框架,进到函数里面,可以看到,它里面就2行代码,一个是发送Command,一个是移除Command,一次性的用完就删,全民好习惯,不用夸我。
那这个命令是在什么地方注册的?上面
 override protected void InitializeController()
 {
        base.InitializeController();
        RegisterCommand(NotiConst.START_UP, typeof(StartUpCommand));
 }
所以有了注册,下面有了发送,那我们开始找接收的地方,在Controller/Command/StartUpCommand.cs里面了,
 
里面除了检查框架运行环境的Util.CheckEnvironment()之外,后面还有3行启动命令,我日,好麻烦,什么玩意儿,我当时学到此,也是这种感觉。
        //BootstrapModels
        AddSubCommand(typeof(BootstrapModels));
 
        //BootstrapCommands
        AddSubCommand(typeof(BootstrapCommands));
 
        //BootstrapViewMediators
        AddSubCommand(typeof(BootstrapViewMediators));
 
其实就是启动MVC各自层的子命令,PMVC作者你过来过来,我保证不打死你。 
别的先不看,先打开看下中间的BootstrapCommands类吧,进去之后,我们看到:
里面除了添加了一条新消息Facade.RegisterCommand(NotiConst.DISPATCH_MESSAGE, typeof(SocketCommand));
 
为了Socket消息做准备外,下面就是一段怎么添加管理器,我日,facade啥东西?
在PMVC里面,它的含义叫“门面”,他们不建议用单例,建议facade是以前外部访问框架内部的总入口,为了解耦。
那我就按照它的规则用了:Facade.AddManager(ManagerName.Lua, new LuaScriptMgr());
 
挨个的添加每个管理器,老版用户对这一幕很熟悉,原来是用Util.Add<GameManager>(gameObject)添加的,那这个Facade.AddManager也是类似功能,只是将原来的Util.Add转移到了Facade中,那我们可以继续跟进去看下AddManager怎么操作的?
 
        //SimpleFramework Code By Jarjin lee 
        void AddManager(string typeName, object obj);
        T AddManager<T>(string typeName) where T : Component;
        T GetManager<T>(string typeName) where T : class;
        void RemoveManager(string typeName);
      这是我新建的4个接口定义,原PMVC没有这些,单击AddManager的引用实现函数,大概在Facede.cs的523行位置,就是我4个函数体的实现部分, 
        GameObject AppGameManager {
            get {
                if (m_GameManager == null) {
                    m_GameManager = GameObject.Find("GameManager");
                }
                return m_GameManager;
            }
        } 

原来如此,我找到新New出来的GameManager,然后根据传进来的不同的类型T,添加到了GameManager对象身上,完成了原来很简单的Util.Add操作,
多说两句,为啥我脑残非要放到这里?原因是facade的设计是全框架通用,任意位置都可以直接访问,这个构想跟我原来的ioo类是一样的,为了搭上它的顺风车,让框架任意地方都能访问到所有的管理器,因此,只能在这里找个安身之所。被这么绕了半天,我也挺需要安慰的,毕竟不是我设计的PMVC。
如果能看到PMVC作者,我非要第一个上去,给他一脚,但是谁让用它的多呢?

 



[本日志由 admin 于 2015-10-30 11:13 AM 更新]
上一篇: SimpleFramework NGUI/UGUI基础知识[1]
下一篇: SimpleFramework NGUI/UGUI基础知识[3]
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
相关日志:
评论: 0 | 引用: 0 | 查看次数: -
发表评论
昵 称:
密 码: 游客发言不需要密码.
邮 箱: 邮件地址支持Gravatar头像,邮箱地址不会公开.
网 址: 输入网址便于回访.
内 容:
验证码:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 1000 字 | UBB代码 开启 | [img]标签 关闭