开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1585

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 1082|回复: 0

[碧俐千仞] Unity3D热更新LuaFramework入门实战(7)——PureMVC

[复制链接]  [移动端链接]
排名
14863
昨日变化
9

14

主题

152

帖子

536

积分

Rank: 9Rank: 9Rank: 9

UID
53741
好友
18
蛮牛币
1554
威望
0
注册时间
2014-11-6
在线时间
74 小时
最后登录
2017-2-28

专栏作家

发表于 2016-10-14 21:39:24 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
LuaFramework使用了PureMVC框架。百度百科上说:“PureMVC是在基于模型、视图和控制器MVC模式建立的一个轻量级的应用框架”。PureMVC框架可以做到较好的解耦,减少游戏代码的相互调用。然而LuaFramework整合PureMVC属于“杀鸡用牛刀”,实质上只用到了事件分发(也可能是我理解得不够透彻)。如果单纯写一套事件分发系统,可能不到100行代码就能完成。

知乎 @罗培羽

1、解耦的好处

如果没有很好的解耦设计,游戏功能越多,代码就越乱,最后没人敢改动。举个例子,假如游戏中背包(item)和成就(Achieve)两项功能,各用一个类实现。当玩家获得100个经验豆(一种道具)时,会获得“拥有100个经验豆”的成就;当成就点数达到300时,会获得道具奖励。一种常见的实现方法是调用对方的public函数,代码如下所示。然而如果一款游戏有几百上千个类,之间又相互调用,如果某些功能需要大改(例如删掉成就功能),那其他的类也得改动。
Class Item
{
    Public AddItem()
    {
        if(经验豆 > 100)
            achieve.AddAchieve(“拥有100个经验豆”)
    }
}

Class Achieve
{
    Public AddAchieve()
    {
        成就点数 + 10
        if(成就点数 > 300)
            item.AddItem(宝石)
    }
}

如果使用事件分发,各个类之间的联系就减弱了。如下所示的代码中背包类(Item)监听了消息“添加道具”,成就类(Achieve)监听了消息“添加成就”。如果达成成就需要添加奖励,只需派发“添加道具”这条消息,由背包类去执行。这样类与类之间不存在相互调用,就算大改功能甚至删掉功能,其他类都受到的影响比较小。
Class Item
{
    Start()
    {
         监听(“添加道具”,AddItem)
    }


    Private AddItem()
    {
        if(经验豆 > 100)
            分发(“添加成就”,“拥有100个经验豆”)
    }
}

Class Achieve
{
    Start()
    {
         监听(“添加成就”,AddAchieve)
    }

    Private AddAchieve()
    {
        成就点数 + 10
        if(成就点数 > 300)
            分发(“添加道具”, 宝石)
    }
}

2、MVC的使用方法

LuaFramework中的Framwork目录存放着PureMVC框架的代码,个人认为在LuaFramework中属于过度设计(毕竟从其他地方拷过来的)。它的原理并不复杂,用一个列表把监听信息保存起来,在派发消息时,查找对应的监听表,找到需要回调的对象。
Unity3D热更新LuaFramework入门实战71222.png

PureMVC框架便是实现了“注册/分发”模式(发布/订阅、观察者模式),可以调用RegisterCommand注册消息(命令),调用SendMessageCommand方法分发消息。RegisterCommand方法可以把某个继承ControllerCommand 的类注册到指定的消息下,在事件分发时调用该类的Execute方法。

例如新建一个名为TestCommand的类,让它继承ControllerCommand,然后编写Execute方法处理具体事务。
using UnityEngine;
using System.Collections;

public class TestCommand : ControllerCommand
{
    public override void Execute(IMessage message)
    {
        Debug.Log("name=" + message.Name);
        Debug.Log("type=" + message.Type);
    }
}

接着,编写另一个类来处理消息。这个类先调用AppFacade.Instance.RegisterCommand()将TestCommand类注册到“TestMessage”消息下。然后使用SendMessageCommand()派发“TestMessage”消息。框架将会创建一个TestCommand实例,并调用它的Execute方法。


public class Main : MonoBehaviour
{
   void Start()
    {
        AppFacade.Instance.RegisterCommand ("TestMessage", typeof(TestCommand));
        AppFacade.Instance.SendMessageCommand ("TestMessage");
    }
}

运行结果如下所示,可以看到分发消息后,TestCommand的Execute方法被调用。
Unity3D热更新LuaFramework入门实战72116.png

Execute方法的参数message包含了Name,Body,Type三个成员(如下图所示)。其中Name是命令名,Body是一个任意类型的参数。
Unity3D热更新LuaFramework入门实战72194.png

如下代码所示,在SendMessageCommand中可以给消息的Body传值,相应的Execute方法便可以获取它。
void Start()
{
    AppFacade.Instance.RegisterCommand ("TestMessage", typeof(TestCommand));
    AppFacade.Instance.SendMessageCommand ("TestMessage", "这是字符串");
}

运行结果如下图所示。
Unity3D热更新LuaFramework入门实战72449.png

总而言之,LuaFramework中所谓的pureMVC只是一套“注册/分发”机制,完全可以用c#的事件来实现。另《网络游戏实战》中的客户端网络模块部分也使用的“注册/分发”机制,有兴趣的读者可以看看。

3、MVC与Unity3D组件的结合

pureMVC与Unity3D组件之间有一些封装,只要让组件继承View类(View类继承MonoBehavior),即使用pureMVC框架的RegisterMessage和SendMessageComman方法实现“注册/分发”机制。

例如,新建一个继承自View的TestManage组件,在Start 方法中它注册了“msg1”、“msg2”、“msg3”三个消息的监听。在Update方法中,当按下空格键时,分发消息“msg1”。

当接收到消息后,指定对象(这里指定this)的OnMessage方法会被调用,参数message里面包含了命令名、Body等信息。代码如下所示。
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class TestManage : View
{

    // Use this for initialization
    void Start ()
    {
        List<string> regList = new List<string>();
        regList.Add("msg1");
        regList.Add("msg2");
        regList.Add("msg3");

        RegisterMessage(this,regList);
    }


    // Update is called once per frame
    void Update ()
    {
        if (Input.GetKeyUp (KeyCode.Space))
        {
            facade.SendMessageCommand("msg1", null);
        }
    }

    public override void OnMessage(IMessage message)
    {
        Debug.Log ("OnMessage " + message.Name);
    }
}

此外LuaFramework的各个Manager(如GameManager,LuaManager,SoundManager等)也都继承自View类,可以使用“注册/分发”机制。

4、后记

也许我对pureMVC的设计理解不足,但在LuaFramework中,我依然认为它过度设计。最后依然是广告时间。

笔者即将出版的一本Unity3D实战类书籍《Unity3D网络游戏实战》。通过一个完整的多人坦克对战实例,详细介绍网络游戏开发过程中涉及到的知识和技巧。书中还介绍了服务端框架、客户端网络模块、UI系统的架构等内容。下图为《Unity3D网络游戏实战》的示例游戏。

  
AR仙剑:一款手机应用,配合手机或pad使用,能将二次元动漫人物零距离展现在你的身旁!
http://pal5h.com/arpal/

《不会电脑也汇编》笔者N多年前写的汇编教程
http://pan.baidu.com/s/1pJBs1mz


评分

参与人数 1鲜花 +2 收起 理由
rgcn + 2

查看全部评分


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表