cocos creator主程入門教程(六)—— 消息分發
阿新 • • 發佈:2019-02-23
any 模式 index 相關 定義 true light mov splice
五邑隱俠,本名關健昌,10年遊戲生涯,現隱居五邑。本系列文章以TypeScript為介紹語言。
本篇開始介紹遊戲業務架構相關的內容。在遊戲業務層,所有需要隔離的系統和模塊間通信都可以通過消息分發解耦。例如網絡返回通知、數據更新同步到界面等。
消息分發基於觀察者模式設計。需要處理消息的地方向消息中心註冊監聽回調,派發消息時,調用消息中心的派發接口遍歷該消息的監聽隊列,調用對應的回調方法。
先定義監聽回調類型
/** * 消息監聽回調方法 */ export type NotifyListener = (src: any, data: any) => void;
通過key-value方式保存監聽隊列
private static msg2listDict: Dictionary< string, Array<NotifyListenerInfo> > = new Dictionary< string, Array<NotifyListenerInfo> >();
接口定義
/** * 添加多次監聽者,需要手動移除 * @param msg * @param listener * @param target */ public static addListener(msg: string, listener: NotifyListener, target?: any): void {} /** * 添加單次監聽者,事件觸發後即移除 * @param msg * @param listener * @param target */ public static addOnceListener(msg: string, listener: NotifyListener, target?: any): void {} /** * 移除指定消息指定的監聽者 * @param msg * @param listener */ public static removeMsgListener(msg: string, listener: NotifyListener): void {} /** * 移除指定消息所有監聽者 * @param msg */ public static removeMsgAllListeners(msg: string): void {} /** * 移除指定目標對指定消息的監聽 * @param msg * @param target */ public static removeTargetMsgListen(msg: string, target: any): void {} /** * 移除指定目標所有消息監聽 * @param target */ public static removeTargetAllMsgListen(target: any): void {} /** * 派發消息 * @param msg * @param src * @param data */ public static notify(msg: string, src: any, data: any): void {}
在添加移除實現中,需要註意某消息可能正在派發。
對於一個消息新添加的監聽者,應該在當前隊列消息派發完後再派發,因此,添加一個待添加隊列
private static listener2add: Array<NotifyListenerInfo> = [];
在添加監聽者時做以下判斷
// 該消息正在派發,放入待添加隊列 if (NotifyCenter.notifyMsgs.indexOf(msg) >= 0) { NotifyCenter.listener2add.push(info); return; }
同樣在移除監聽者時,可能正在派發消息,避免對隊列的修改導致for循環異常,添加一個待移除隊列,派發消息時,如果該監聽者在移除隊列則不派發。在消息派發完後再將其移出隊列
private static listener2remove: Array<NotifyListenerInfo> = [];
在移除監聽者時做以下判斷
// 該消息正在派發,放入待移除隊列 if (NotifyCenter.notifyMsgs.indexOf(msg) >= 0) { NotifyCenter.listener2remove.push(list[i]); } else { list.splice(i, 1); }
派發消息時遍歷指定消息下的隊列
// 隊列不存在,不需要處理 let list = NotifyCenter.msg2listDict.get(msg); if (!list) { return; } // 標記消息正在派發,多個消息可能同時在派發,同一消息可能標記多次 NotifyCenter.notifyMsgs.push(msg); // 處理消息派發 for (let i = 0, n = list.length; i < n; i++) { NotifyCenter._dispatch(list[i], src, data, false); }
派發消息時先判斷是否在移除隊列
// 在移除隊列,不派發 if (NotifyCenter.listener2remove.indexOf(info) >= 0) { return; }
當前隊列派發完後檢查待添加隊列
// 處理待添加隊列派發 for (let i = 0, n = msg2add.length; i < n; i++) { if (listener2add[i].msg == msg) { NotifyCenter._dispatch(listener2add[i], src, data, true); } }
引入消息分發中心,隔離的系統、模塊間通過消息監聽和派發通信,避免互相引用耦合。
消息分發先說到這裏,下一篇我們將介紹遊戲業務層架構。
cocos creator主程入門教程(六)—— 消息分發