1.游戏简要说明:
游戏中有一个玩家,他手上拿着一个炮弹,可以射击游戏中的物体,比如飞机。
游戏中有显示玩家信息的UI,比如血量,射击命中次数、丢失次数,击败的飞机数量等等。
游戏中有成就系统,当主角击落一些飞机时,会达成一些成就。
2.使用观察者模式的原因
游戏中有许多的事件,比如:
玩家射击事件:OnMarineShoot
玩家击落飞机事件:OnBulletHit
在这些事件发生之后,会有许多的东西发生变化,比如UI和成就系统。
假如不使用观察者模式,在该事件发生后需直接写ui和成就系统变化的代码,那么模块之间就会有很高的耦合。
而使用观察者模式,我们将执行以下操作:
-在游戏中声明主要的事件:OnMarineShoot,OnBulletHit......
-创建EventDispatcher:作为中介,接受和转发事件
-在游戏开始时,UI 和AchievementManager对象将向EventDispatcer 注册,以便在OnMarineShoot,OnBulletHit...等事件被引发时被通知
-玩家对象:当他的HP更改或杀死怪物时,他会向EventDispatcher发送消息,EventDispatcher会将其转发给收件人。(UI和成就系统)
3.下面我们用部分代码来展示观察者模式
声明EventID,即游戏中会发生的事件:
public enum EventID { None = 0, OnMarineShoot, OnBulletHit, OnHelicopterDead, OnHelicopterEscaped, }
创建EventDispatcher,即观察者模式的subject,在其中可以注册和取消observer。
public class EventDispatcher : MonoBehaviour { // Register to listen for eventID, callback will be invoke when event with eventID be raise public void RegisterListener (EventID eventID, Action<object> callback); // Post event, this will notify all listener which register to listen for eventID public void PostEvent (EventID eventID, Component sender, object param = null); // Use for Unregister, not listen for an event anymore. public void RemoveListener (EventID eventID, Action<object> callback); } /// An Extension class, declare some "shortcut" for using EventDispatcher public static class EventDispatcherExtension { /// Use for registering with EventDispatcher public static void RegisterListener (this MonoBehaviour listener, EventID eventID, Action<object> callback) { EventDispatcher.Instance.RegisterListener(eventID, callback); } /// Post event with param public static void PostEvent (this MonoBehaviour listener, EventID eventID, object param) { EventDispatcher.Instance.PostEvent(eventID, sender, param); } /// Post event with no param (param = null) public static void PostEvent (this MonoBehaviour listener, EventID eventID) { EventDispatcher.Instance.PostEvent(eventID, sender, null); } }
ui注册监听示例:UITextManager需要监听游戏中的所有事件来更新ui
void Start () { // register to receive events this.RegisterListener(EventID.OnMarineShoot, (param) => OnMarineShoot()); this.RegisterListener(EventID.OnBulletHit, (param) => OnBulletHit()); this.RegisterListener(EventID.OnHelicopterDead, (param) => OnHelicopterDead()); this.RegisterListener(EventID.OnHelicopterEscaped, (param) => OnHelicopterEscaped()); } /// Will be invoke when OnMarineShoot event was raised void OnMarineShoot() { // some code to modify text on UI } /// Will be invoke when OnBulletHit event was raised void OnBulletHit() { // some code to modify text on UI } ......other event
当不想再“监听”某个事件时,使用RemoveListener来取消监听
Action<object> _OnReceiveEventRef; void Start () { // Reference to our OnReceiveEvent, we'll use it to RegisterListener() and RemoveListener() _OnReceiveEventRef = (param) => OnReceiveEvent(); EventDispatcher.Instance.RegisterListener(EventID.OnBulletHit, _OnReceiveEventRef); } void UnregisterListener () { /// Dont use this way, it'll create a new Action, instead of a reference to our OnReceiveEvent(), /// then it still be invoked from EventDispatcher //EventDispatcher.Instance.RemoveListener(EventID.OnBulletHit, (para) => OnReceiveEvent()); // Right way EventDispatcher.Instance.RemoveListener(EventID.OnBulletHit, _OnReceiveEventRef); }
事件的触发
void Update () { if (Input.GetMouseButtonDown(0))//left mouse { // code to Instantiate the bullet // raise shoot event this.PostEvent(EventID.OnMarineShoot); } }
4.总结:
使用观察者模式很好的降低观察者和被观察者的耦合程度,并且观察者模式满足了“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标非常地方便。
5.项目的github地址:
https://github.com/ThinhHB/UnityObserverPatternDemo/tree/01afc838bca310271988832b30b713d91ba721e3