ToLua热更新之LuaFramework框架之PureMVC(七)

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中属于过度设计(毕竟从其他地方拷过来的)。它的原理并不复杂,用一个列表把监听信息保存起来,在派发消息时,查找对应的监听表,找到需要回调的对象。

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方法被调用。

Execute方法的参数message包含了Name,Body,Type三个成员(如下图所示)。其中Name是命令名,Body是一个任意类型的参数。

如下代码所示,在SendMessageCommand中可以给消息的Body传值,相应的Execute方法便可以获取它。

void Start() 
{
	AppFacade.Instance.RegisterCommand ("TestMessage", 
							typeof(TestCommand));
	AppFacade.Instance.SendMessageCommand ("TestMessage", "这是字符串");
}

运行结果如下图所示。

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


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类,可以使用“注册/分发”机制。

猜你喜欢

转载自blog.csdn.net/weixin_39706943/article/details/80679149