Unity 游戏框架:UI 管理神器 UI Kit (6)

事件的注册:

public partial class UIGamePanel : UIPanel { protected override void InitUI(IUIData uiData = null) { mData = uiData as UIGamePanelData ?? new UIGamePanelData(); //please add init code here Level.text = "第" + mData.LevelIndex + "关"; RegisterEvent(UIGamePanelEvent.GameResume); } ... }

事件的处理:

public partial class UIGamePanel : UIPanel { ... protected override void ProcessMsg (int eventId,QMsg msg) { if (eventId == (int) UIGamePanelEvent.GameResume) { GameResume(); } } ... }

接收消息之后,马上调用 GameResume 方法就好了。

完整 UIGamePanel.cs 代码如下:

/* 2018.7 凉鞋的MacBook Pro (2) */ namespace QFramework.Example { public class UIGamePanelData : UIPanelData { public int LevelIndex = 1; } public enum UIGamePanelEvent { Start = QMgrID.UI, GameResume, End } public partial class UIGamePanel : UIPanel { protected override void InitUI(IUIData uiData = null) { mData = uiData as UIGamePanelData ?? new UIGamePanelData(); //please add init code here Level.text = "第" + mData.LevelIndex + "关"; RegisterEvent(UIGamePanelEvent.GameResume); } protected override void ProcessMsg (int eventId,QMsg msg) { if (eventId == (int) UIGamePanelEvent.GameResume) { GameResume(); } } protected override void RegisterUIEvent() { BtnPause.onClick.AddListener(() => { GamePause(); UIMgr.OpenPanel<UIGamePausePanel>(UILevel.PopUI); }); } void GameStart() { } void GamePause() { Log.E("GamePause"); } void GameResume() { Log.E("GameResume"); } void GameOver() { } } }

接下来是在 UIGamePausePanel 中发送事件的部分。

非常简单,代码如下:

/* 2018.7 凉鞋的MacBook Pro (2) */ namespace QFramework.Example { public class UIGamePausePanelData : UIPanelData { // TODO: Query Mgr's Data } public partial class UIGamePausePanel : UIPanel { protected override void InitUI(IUIData uiData = null) { mData = uiData as UIGamePausePanelData ?? new UIGamePausePanelData(); //please add init code here } protected override void ProcessMsg (int eventId,QMsg msg) { throw new System.NotImplementedException (); } protected override void RegisterUIEvent() { BtnMain.onClick.AddListener(() => { CloseSelf(); UIMgr.ClosePanel<UIGamePanel>(); UIMgr.OpenPanel<UIMainPanel>(); }); BtnReplay.onClick.AddListener(() => { Log.E("BtnPlay Clicked"); }); BtnContinue.onClick.AddListener(() => { SendEvent(UIGamePanelEvent.GameResume); CloseSelf(); }); } } }

在 BtnContinue 按钮点击之后进行事件的发送就好了。

这就是事件机制的方式。

目前有三种方式:

获取父 Panel 调用方法。

对父 Panel 提供委托。

发送消息。

这里笔者比较推荐使用第二种和第三种。

其中最推荐的还是,第二种,提供委托的方式。这样事件能够很好地进行接收,保持单向的引用,可以通过代码了解两者之间的关系,所以这通常是很紧实的设计。

而第三种虽然推荐,但是多少会有一些风险。可能造成消息满天飞的情况,万不得已的情况下慎用,唯一的好处就是松耦合。在跨模块之间通信,或者同级的对象之间建议用消息,这种情况已经是万不得已的情况下了。

而第一种方式呢,造成了双向引用,是完全违背常识的,所以不推荐,不过项目紧的时候先完成需求为先。

ok,三种方式的利弊介绍到这里。

观察者模式与事件机制

观察者模式是对象/模块之间解耦的利器

观察者模式是什么?笔者看了很多官方和书上定义后也是一头雾水,我们先抛弃 Observer/Subscriber 等技术概念,直接来段简单易读的代码更容易理解些。

class Person { public string Name; public void Say(string msg) { Log.E ("Person:{0} Say:{1}", Name, msg); } public void ReceiveMsg(string msg) { Say (msg); } }

代码不难理解,主要是 ReceiveMsg 方法用来接收消息。

class Me { List<Person> mContacts = new List<Person>(); public void RegisterContact(Person person) { mContacts.Add(person); } public void SendMsgToContancts() { mContacts.ForEach(person => person.ReceiveMsg("Hi")); } }

Me 就是,也就是发送者,将消息发送出去。

mContacts,就是联系人的意思。

RegisterContact,需要在我的联系人名单里注册好 Person,Person 才能接收到我发出去的消息。

SendMsgToContacts,则是我向联系人发送消息。

测试代码:

public class ObserverPatternExample : MonoBehaviour { // Use this for initialization IEnumerator Start () { Me me = new Me (); me.RegisterPerson(new Person (){ Name = "张三" }); me.RegisterPerson(new Person (){ Name = "李四" }); me.RegisterPerson(new Person (){ Name = "王五 "}); yield return new WaitForSeconds (1.0f); me.SendMsgToContancts (); } }

输出结果为:

Person:张三 Say:Hi Person:李四 Say:Hi Person:王五 Say:Hi

这是一种一对多的消息广播。

当然多对一,多对多很容易实现,原理都是通过观察者模式。

有了以上例子为基础,再去看设计模式中的观察者模式就会更简单了。

观察者模式的经典实现,都有一个消息注册列表,一般是在,Subject 中,这个 Subject 对应的是 以上例子中的 Me,而 Observer 则对应的是 Person。

接下来介绍下观察者模式的应用,消息机制 QEventSystem。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsppfj.html