---恢复内容开始---
仿LOL项目开发第四天
by草帽
上节讲了几乎所有的更新版本的逻辑,那么这节课我们来补充界面框架的搭建的讲解。
我们知道游戏中的每个界面都有自己的一个类型:比如登陆界面,创建角色界面。
既然有这么多的界面,所以呢,我们创建一个单例的UI管理器:WindowManager.cs,然后里面创建一个字典来存所有类型的界面:
using UnityEngine;
using System.Collections.Generic;
using Game;
using Game.Common;
public class WindowManager : Singleton<WindowManager>
{private Dictionary<EWindowType, BaseWindow> mWidowDic;public WindowManager(){mWidowDic = new Dictionary<EWindowType, BaseWindow>();mWidowDic[EWindowType.e_MessageWindow] = new MessageWindow();}
}
EWindowType枚举类型,定义了所有类型的UI界面,比如登陆类型等。那么,这些枚举属于公共类型,所以我们定义在公共的地方,我们创建一个DefineCommon来存放这些公共类型变量,搞个命名空间为Game.Common:
using UnityEngine;
using System.Collections;
namespace Game.Common
{public enum EWindowType{e_LoginWindow,e_MessageWindow}
}
然后WindowManager里面引用该命名空间,注意到没有,因为存放界面的字典value对应着WindowBase,它是UI界面的基类。
什么是基类,就是处理所有不同类型的界面的公共类。也就是说所有界面都有的特性都包含在这个类中。
using UnityEngine;
using System.Collections;
using Utility;
/// <summary>
/// 界面抽象基类
/// </summary>
public abstract class BaseWindow
{protected Transform mRoot;//UI根目录//protected EScenesType mScenesType; //场景类型protected string mResName; //资源名protected bool mResident; //是否常驻 protected bool mVisible = false; //是否可见//类对象初始化public abstract void Init();//类对象释放public abstract void Realse();//窗口控制初始化protected abstract void InitWidget();//窗口控件释放protected abstract void RealseWidget();//游戏事件注册protected abstract void OnAddListener();//游戏事件注消protected abstract void OnRemoveListener();//显示初始化public abstract void OnEnable();//隐藏处理public abstract void OnDisable();//每帧更新public virtual void Update(float deltaTime) { }/*//取得所以场景类型public EScenesType GetScenseType(){return mScenesType;}*///是否已打开public bool IsVisible() { return mVisible; }//是否常驻public bool IsResident() { return mResident; }//显示public void Show(){if (mRoot == null){if (Create()){InitWidget();//初始化组件}}if (mRoot && mRoot.gameObject.activeSelf == false){mRoot.gameObject.SetActive(true);mVisible = true;OnEnable();OnAddListener();}}//隐藏public void Hide(){if (mRoot && mRoot.gameObject.activeSelf == true){OnRemoveListener();OnDisable();if (mResident){mRoot.gameObject.SetActive(false);}else{RealseWidget();Destroy();}}mVisible = false;}//预加载public void PreLoad(){if (mRoot == null){if (Create()){InitWidget();}}}//延时删除public void DelayDestory(){if (mRoot){RealseWidget();Destroy();}}//创建窗体private bool Create(){if (mRoot){Debug.LogError("Window Create Error Exist!");return false;}if (mResName == null || mResName == ""){Debug.LogError("Window Create Error ResName is empty!");return false;}if (UnityTools.GetUICamera.transform == null){Debug.LogError("Window Create Error GetUiCamera is empty! WindowName = " + mResName);return false;}GameObject obj = null;// LoadUiResource.LoadRes(GameMethod.GetUiCamera.transform, mResName);if (obj == null){Debug.LogError("Window Create Error LoadRes WindowName = " + mResName);return false;}mRoot = obj.transform;mRoot.gameObject.SetActive(false);//设置为隐藏return true;}//销毁窗体protected void Destroy(){if (mRoot){// LoadUiResource.DestroyLoad(mRoot.gameObject);mRoot = null;}}//取得根节点public Transform GetRoot(){return mRoot;}
}
里面封装了不同类型界面的公有的方法,比如说创建界面的资源,初始化等。
然后UnityTools里面添加GetUICamera方法:
/// <summary>/// 取得UICamera/// </summary>public static Camera GetUICamera{get {if (UICamera.currentCamera == null){UICamera.currentCamera = GameObject.Find("UI Root").transform.FindChild("Camera").GetComponent<Camera>();}return UICamera.currentCamera;}}
这个UI界面的管理方式我就不详细讲了,因为在共享群里面,我已经发了这个框架的研究文章。
因为UI界面是需要从Resources加载界面的Prefab的,所以这里又需要用到资源加载的框架。
我们新建一个单例脚本:ResourceManager.cs:
因为加载场景是需要在Update或者协程里面的,所以呢,ResourceManager他既然是要继承MonoBehavior的单例,所以我这里又搞了一个Mono单例的基类:UnitySingleton.cs:
public class UnitySingleton<T> : MonoBehaviourwhere T : Component{private static T _instance;public static T Instance{get{if (_instance == null){_instance = FindObjectOfType(typeof(T)) as T;//如果激活的物体上找到这个脚本//没有找到这个脚本,就自己创建一个物体,附上这个脚本if (_instance == null){GameObject obj = new GameObject();//obj.hide Flags = HideFlags.DontSave;obj.hideFlags = HideFlags.HideAndDontSave;//设置物体不显示_instance = (T)obj.AddComponent(typeof(T));}}return _instance;}}/// <summary>/// 加载另外一个场景的时候不要销毁这个物体/// </summary>public virtual void Awake(){DontDestroyOnLoad(this.gameObject);if (_instance == null){_instance = this as T;}else{Destroy(gameObject);}}}
因为我们还没有涉及到ab打包,所以呢,我们这里就直接在Resources里面加载。
ResourceManager:
using UnityEngine;
using System.Collections.Generic;
using Game;
using Game.Common;
/// <summary>
/// 资源加载管理器
/// </summary>
public class ResourceManager : UnitySingleton<ResourceManager>
{public bool UsedAssetBundle = false;//是否使用ab加载private bool m_Init = false;private Dictionary<string, ResourceUnit> m_LoadedResourceUnit = new Dictionary<string,ResourceUnit>();public void Init(){if (UsedAssetBundle){}this.m_Init = true;}/// <summary>/// 加载资源/// </summary>/// <param name="filePath"></param>/// <param name="type"></param>/// <returns></returns>public ResourceUnit LoadImmediate(string filePath,ResourceType type){if (UsedAssetBundle){return null;}else{Object asset = Resources.Load(filePath);ResourceUnit resource = new ResourceUnit(null,0,asset,null,type);return resource;}}public void Update(){if (!this.m_Init){return ;}}
}
这里我定义了一个bool变量:UsedAssetbundle,来判断是否是ab加载。这里因为还没有用到ab,所以我暂时先不写ab的代码。
因为资源有很多特性,所以我定义了一个ResourceUnit来管理加载的资源:
using UnityEngine;
using System.Collections.Generic;
using System;
using Object = UnityEngine.Object;
using Game.Common;
public class ResourceUnit : IDisposable
{private string mPath;//资源路径private Object mAsset;//资源private ResourceType mResourceType;//资源类型private List<ResourceUnit> mNextLevelAssets;//用到的所有资源,ab加载时有用到private AssetBundle mAssetBundle;//资源的ab文件private int mAssetBundleSize;//ab文件的大小private int mReferenceCount;//被引用的次数internal ResourceUnit(AssetBundle assetBundle, int assetBundleSize, Object asset, string path, ResourceType resourceType/*, int allDependencesAssetSize*/){mPath = path;mAsset = asset;mResourceType = resourceType;mNextLevelAssets = new List<ResourceUnit>();mAssetBundle = assetBundle;mAssetBundleSize = assetBundleSize;mReferenceCount = 0;}public Object Asset{get{return mAsset;}internal set{mAsset = value;}}public ResourceType resourceType{get{return mResourceType;}}public List<ResourceUnit> NextLevelAssets{get{return mNextLevelAssets;}internal set{foreach (ResourceUnit asset in value){mNextLevelAssets.Add(asset);}}}public AssetBundle Assetbundle{get{return mAssetBundle;}set{mAssetBundle = value;}}public int AssetBundleSize{get{return mAssetBundleSize;}}public int ReferenceCount{get{return mReferenceCount;}}public void dumpNextLevel(){string info = mPath + " the mReferenceCount : " + mReferenceCount + "\n";foreach (ResourceUnit ru in mNextLevelAssets){ru.dumpNextLevel();info += ru.mPath + "\n";}Debug.Log(info);}public void addReferenceCount(){++mReferenceCount;foreach (ResourceUnit asset in mNextLevelAssets){asset.addReferenceCount();}}public void reduceReferenceCount(){--mReferenceCount;foreach (ResourceUnit asset in mNextLevelAssets){asset.reduceReferenceCount();}if (isCanDestory()){//ResourcesManager.Instance.mLoadedResourceUnit.Remove(ResourceCommon.getFileName(mPath, true));Dispose();}}public bool isCanDestory() { return (0 == mReferenceCount); }public void Dispose(){Debug.Log("Destory " + mPath);if (null != mAssetBundle){mAssetBundle = null;}mNextLevelAssets.Clear();mAsset = null;}}
当然ResourceType也是枚举类型,所以定义在DefineCommon类中:
using UnityEngine;
using System.Collections;
namespace Game.Common
{/// <summary>/// UI界面类型/// </summary>public enum EWindowType{e_LoginWindow,e_MessageWindow}/// <summary>/// 资源类型,Asset,Prefab,Level/// </summary>public enum ResourceType{ASSET,PREFAB,LEVELASSET,LEVEL,}
}
OK,现在调用ResourceManager.LoadImmediate就可以加载出资源了。但是我前面说过,单例模式不好扩展,不符合单一职责原则,所以我们自己再封装一层单一职责的类,比如界面加载,我们就定义一个LoadUIResource加载类,然后具体实现又ResourceManage里面实现。
这样也符合开闭原则,对扩展开放,对修改关闭,我们不是没有修改ResourceManager的代码,就能实现UI界面的加载。
OK,废话讲的有点多,我们就来写LoadUIResource.cs:
using UnityEngine;
using System.Collections.Generic;
using Game.Common;
/// <summary>
/// UI界面加载类
/// </summary>
public class LoadUIResource/// <summary>/// 加载过的缓存字典/// </summary>public static Dictionary<string, GameObject> m_LoadResDic = new Dictionary<string, GameObject>();/// <summary>/// 实例化资源/// </summary>/// <param name="parent"></param>/// <param name="path"></param>/// <returns></returns>public static GameObject LoadRes(Transform parent, string path){if (CheckResInDic(path)){GameObject asset = null;m_LoadResDic.TryGetValue(path, out asset);if (asset != null){return asset;}else {m_LoadResDic.Remove(path);}}GameObject obj = null;ResourceUnit objUnit = ResourceManager.Instance.LoadImmediate(path, ResourceType.PREFAB);if (objUnit == null || objUnit.Asset == null){Debug.LogError("加载资源失败:" + path);return null;}obj = GameObject.Instantiate(objUnit.Asset) as GameObject;obj.transform.SetParent(parent);obj.transform.localScale = Vector3.one;obj.transform.localPosition = Vector3.zero;m_LoadResDic.Add(path, obj);return obj;}/// <summary>/// 销毁资源/// </summary>/// <param name="obj"></param>public static void DestroyLoad(GameObject obj){if (m_LoadResDic.Count == null || obj == null){return;}foreach (var key in m_LoadResDic.Keys){GameObject objLoad;if (m_LoadResDic.TryGetValue(key, out objLoad) && obj == objLoad){GameObject.DestroyImmediate(obj);m_LoadResDic.Remove(key);break;}}}/// <summary>/// 检查是否已经包含该资源/// </summary>/// <param name="path"></param>/// <returns></returns>private static bool CheckResInDic(string path){if (m_LoadResDic == null && m_LoadResDic.Count == 0){return false;}return m_LoadResDic.ContainsKey(path);}
}
OK,现在我们就可以加载界面了,所以我们回到WindowBase.Create代码里面:
修改代码:
写完加载界面之后,我们来写写具体的界面实现,MessageWindow这个是我们现在要用到的,所以先写这个:
因为我们消息有很多类型,所以定义一个消息枚举类型:MessageType:
/// <summary>/// 消息类型/// </summary>public enum EMessageType{EMT_None = -1,EMT_NetTryAgain, //重试消息提示EMT_ReConnect //重新连接}
OK,我们现在就开始用NGUI来搭建消息UI界面:
这是我随手搭建的一个,然后制作成Prefab,保存在Resources/Guis文件夹下。那么搭建完之后,我们开始在代码里面定义组件,然后赋值:
可以看到一个消息提示框有:
1.UILabel----->Title:消息标题
2.UILabel----->Conent:消息内容
3.UIButton------>FirstButton第一个按钮
4.UIButton------>SecondButton第二个按钮
所以在MessageWindow里定义:
using UnityEngine;
using System.Collections;
using System;
using Game.Common;
/// <summary>
/// 消息UI
/// </summary>
public class MessageWindow : BaseWindow
{private EMessageType m_eMessageType = EMessageType.EMT_None;private UILabel m_title;//消息标题private UILabel m_content;//消息内容private UIButton m_firstButton;//消息第一个按钮private UIButton m_secondButton;//消息第二个按钮
private Action<bool> m_actCallBack;//委托回调public MessageWindow(){mResName = "Guis/MessageWindow";mResident = false;}public override void Init(){}protected override void InitWidget(){}protected override void OnAddListener(){}protected override void OnRemoveListener(){}public override void OnEnable(){}public override void Update(float deltaTime){base.Update(deltaTime);}public override void OnDisable(){}protected override void RealseWidget(){}public override void Realse(){}public void ShowMessage(EMessageType type,Action<bool> callback=null){//如果已经显示了,就直接返回if (mVisible){return;}this.m_eMessageType = type;
this.m_actCallBack = callback;Show();//根据不同的消息类型,显示不同的提示消息switch (this.m_eMessageType){case EMessageType.EMT_NetTryAgain:break;case EMessageType.EMT_ReConnect:break;case EMessageType.EMT_None:break;}}
}
然后先初始化各个组件,在InitWidget():
protected override void InitWidget(){this.m_title = this.mRoot.FindChild("Frame/Title").GetComponent<UILabel>();this.m_content = this.mRoot.FindChild("Frame/Content").GetComponent<UILabel>();this.m_firstButton = this.mRoot.FindChild("Frame/FirstButton").GetComponent<UIButton>();this.m_secondButton = this.mRoot.FindChild("Frame/SecondButton").GetComponent<UIButton>();EventDelegate.Add(this.m_firstButton.onClick, OnFirstBtn);EventDelegate.Add(this.m_secondButton.onClick, OnSecondBtn);}
public void OnFirstBtn(){switch (this.m_eMessageType){//如果是重试消息的话case EMessageType.EMT_NetTryAgain:this.m_actCallBack(true);Hide();break;case EMessageType.EMT_ReConnect:break;case EMessageType.EMT_None:break;}}public void OnSecondBtn(){switch (this.m_eMessageType){//如果是重试消息的话case EMessageType.EMT_NetTryAgain:this.m_actCallBack(false);Hide();break;case EMessageType.EMT_ReConnect:break;case EMessageType.EMT_None:break;}}
我们在NetTryAgain里面修改消息显示的效果:
public void ShowMessage(EMessageType type,Action<bool> callback = null){//如果已经显示了,就直接返回if (mVisible){return;}this.m_eMessageType = type;this.m_actCallBack = callback;Show();//根据不同的消息类型,显示不同的提示消息switch (this.m_eMessageType){//如果是重试消息的话case EMessageType.EMT_NetTryAgain:this.m_firstButton.normalSprite = "image 168";this.m_secondButton.normalSprite = "image 172";this.m_title.text = "网路错误";this.m_content.text = "您的网络无法连接上服务器,请检查下网络是否良好。";break;case EMessageType.EMT_ReConnect:break;case EMessageType.EMT_None:break;}}
OK,那么怎么显示消息呢,我们可以看到在ShowMessage方法里面呢,有调用Show()方法。
所以我们想要显示消息,就得调用ShowMessage(),但是基本上呢,我们是在其他地方调用这个方法,所以如果如果直接使用实例,就耦合度非常的高。
所以我们处理了一个事件中心器,专门处理各种事件,比如我想要显示消息的时候,直接调用事件中心器里面对应的显示事件。
这个事件中心器呢,我这里不详细讲解了,你们直接粘贴复制,拿来用就行了。
EventCenter.cs:
/** Advanced C# messenger by Ilya Suzdalnitski. V1.0* * Based on Rod Hyde's "CSharpMessenger" and Magnus Wolffelt's "CSharpMessenger Extended".* * Features:* Prevents a MissingReferenceException because of a reference to a destroyed message handler.* Option to log all messages* Extensive error detection, preventing silent bugs* * Usage examples:1. Messenger.AddListener<GameObject>("prop collected", PropCollected);Messenger.Broadcast<GameObject>("prop collected", prop);2. Messenger.AddListener<float>("speed changed", SpeedChanged);Messenger.Broadcast<float>("speed changed", 0.5f);* * Messenger cleans up its evenTable automatically upon loading of a new level.* * Don't forget that the messages that should survive the cleanup, should be marked with Messenger.MarkAsPermanent(string)* *///#define LOG_ALL_MESSAGES
//#define LOG_ADD_LISTENER
//#define LOG_BROADCAST_MESSAGE
#define REQUIRE_LISTENERusing System;
using System.Collections.Generic;
using UnityEngine;
using Game.Common;
static internal class EventCenter
{//Disable the unused variable warning
#pragma warning disable 0414//Ensures that the MessengerHelper will be created automatically upon start of the game.// static private MessengerHelper mMessengerHelper = ( new GameObject("MessengerHelper") ).AddComponent< MessengerHelper >();
#pragma warning restore 0414static public Dictionary<EGameEvent, Delegate> mEventTable = new Dictionary<EGameEvent, Delegate>();//Message handlers that should never be removed, regardless of calling Cleanupstatic public List<EGameEvent> mPermanentMessages = new List<EGameEvent>();//Marks a certain message as permanent.static public void MarkAsPermanent(EGameEvent eventType){
#if LOG_ALL_MESSAGESDebug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\"");
#endifmPermanentMessages.Add(eventType);}static public void Cleanup(){
#if LOG_ALL_MESSAGESDebug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed.");
#endifList<EGameEvent> messagesToRemove = new List<EGameEvent>();foreach (KeyValuePair<EGameEvent, Delegate> pair in mEventTable){bool wasFound = false;foreach (EGameEvent message in mPermanentMessages){if (pair.Key == message){wasFound = true;break;}}if (!wasFound)messagesToRemove.Add(pair.Key);}foreach (EGameEvent message in messagesToRemove){mEventTable.Remove(message);}}static public void PrEGameEventEventTable(){Debug.Log("\t\t\t=== MESSENGER PrEGameEventEventTable ===");foreach (KeyValuePair<EGameEvent, Delegate> pair in mEventTable){Debug.Log("\t\t\t" + pair.Key + "\t\t" + pair.Value);}Debug.Log("\n");}static public void OnListenerAdding(EGameEvent eventType, Delegate listenerBeingAdded){
#if LOG_ALL_MESSAGES || LOG_ADD_LISTENERDebug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}");
#endifif (!mEventTable.ContainsKey(eventType)){mEventTable.Add(eventType, null);}Delegate d = mEventTable[eventType];if (d != null && d.GetType() != listenerBeingAdded.GetType()){throw new ListenerException(string.Format("Attempting to add listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being added has type {2}", eventType, d.GetType().Name, listenerBeingAdded.GetType().Name));}}static public void OnListenerRemoving(EGameEvent eventType, Delegate listenerBeingRemoved){
#if LOG_ALL_MESSAGESDebug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}");
#endifif (mEventTable.ContainsKey(eventType)){Delegate d = mEventTable[eventType];if (d == null){throw new ListenerException(string.Format("Attempting to remove listener with for event type \"{0}\" but current listener is null.", eventType));}else if (d.GetType() != listenerBeingRemoved.GetType()){throw new ListenerException(string.Format("Attempting to remove listener with inconsistent signature for event type {0}. Current listeners have type {1} and listener being removed has type {2}", eventType, d.GetType().Name, listenerBeingRemoved.GetType().Name));}}else{throw new ListenerException(string.Format("Attempting to remove listener for type \"{0}\" but Messenger doesn't know about this event type.", eventType));}}static public void OnListenerRemoved(EGameEvent eventType){if (mEventTable[eventType] == null){mEventTable.Remove(eventType);}}static public void OnBroadcasting(EGameEvent eventType){
#if REQUIRE_LISTENERif (!mEventTable.ContainsKey(eventType)){}
#endif}static public BroadcastException CreateBroadcastSignatureException(EGameEvent eventType){return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType));}public class BroadcastException : Exception{public BroadcastException(string msg): base(msg){}}public class ListenerException : Exception{public ListenerException(string msg): base(msg){}}//No parametersstatic public void AddListener(EGameEvent eventType, Callback handler){OnListenerAdding(eventType, handler);mEventTable[eventType] = (Callback)mEventTable[eventType] + handler;}//Single parameterstatic public void AddListener<T>(EGameEvent eventType, Callback<T> handler){OnListenerAdding(eventType, handler);mEventTable[eventType] = (Callback<T>)mEventTable[eventType] + handler;}//Two parametersstatic public void AddListener<T, U>(EGameEvent eventType, Callback<T, U> handler){OnListenerAdding(eventType, handler);mEventTable[eventType] = (Callback<T, U>)mEventTable[eventType] + handler;}//Three parametersstatic public void AddListener<T, U, V>(EGameEvent eventType, Callback<T, U, V> handler){OnListenerAdding(eventType, handler);mEventTable[eventType] = (Callback<T, U, V>)mEventTable[eventType] + handler;}//Four parametersstatic public void AddListener<T, U, V, X>(EGameEvent eventType, Callback<T, U, V, X> handler){OnListenerAdding(eventType, handler);mEventTable[eventType] = (Callback<T, U, V, X>)mEventTable[eventType] + handler;}//No parametersstatic public void RemoveListener(EGameEvent eventType, Callback handler){OnListenerRemoving(eventType, handler);mEventTable[eventType] = (Callback)mEventTable[eventType] - handler;OnListenerRemoved(eventType);}//Single parameterstatic public void RemoveListener<T>(EGameEvent eventType, Callback<T> handler){OnListenerRemoving(eventType, handler);mEventTable[eventType] = (Callback<T>)mEventTable[eventType] - handler;OnListenerRemoved(eventType);}//Two parametersstatic public void RemoveListener<T, U>(EGameEvent eventType, Callback<T, U> handler){OnListenerRemoving(eventType, handler);mEventTable[eventType] = (Callback<T, U>)mEventTable[eventType] - handler;OnListenerRemoved(eventType);}//Three parametersstatic public void RemoveListener<T, U, V>(EGameEvent eventType, Callback<T, U, V> handler){OnListenerRemoving(eventType, handler);mEventTable[eventType] = (Callback<T, U, V>)mEventTable[eventType] - handler;OnListenerRemoved(eventType);}//Four parametersstatic public void RemoveListener<T, U, V, X>(EGameEvent eventType, Callback<T, U, V, X> handler){OnListenerRemoving(eventType, handler);mEventTable[eventType] = (Callback<T, U, V, X>)mEventTable[eventType] - handler;OnListenerRemoved(eventType);}//No parametersstatic public void Broadcast(EGameEvent eventType){
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endifOnBroadcasting(eventType);Delegate d;if (mEventTable.TryGetValue(eventType, out d)){Callback callback = d as Callback;if (callback != null){callback();}else{throw CreateBroadcastSignatureException(eventType);}}}static public void SendEvent(CEvent evt){Broadcast<CEvent>(evt.GetEventId(), evt);}//Single parameterstatic public void Broadcast<T>(EGameEvent eventType, T arg1){
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endifOnBroadcasting(eventType);Delegate d;if (mEventTable.TryGetValue(eventType, out d)){Callback<T> callback = d as Callback<T>;if (callback != null){callback(arg1);}else{throw CreateBroadcastSignatureException(eventType);}}}//Two parametersstatic public void Broadcast<T, U>(EGameEvent eventType, T arg1, U arg2){
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endifOnBroadcasting(eventType);Delegate d;if (mEventTable.TryGetValue(eventType, out d)){Callback<T, U> callback = d as Callback<T, U>;if (callback != null){callback(arg1, arg2);}else{throw CreateBroadcastSignatureException(eventType);}}}//Three parametersstatic public void Broadcast<T, U, V>(EGameEvent eventType, T arg1, U arg2, V arg3){
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endifOnBroadcasting(eventType);Delegate d;if (mEventTable.TryGetValue(eventType, out d)){Callback<T, U, V> callback = d as Callback<T, U, V>;if (callback != null){callback(arg1, arg2, arg3);}else{throw CreateBroadcastSignatureException(eventType);}}}//Four parametersstatic public void Broadcast<T, U, V, X>(EGameEvent eventType, T arg1, U arg2, V arg3, X arg4){
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGEDebug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endifOnBroadcasting(eventType);Delegate d;if (mEventTable.TryGetValue(eventType, out d)){Callback<T, U, V, X> callback = d as Callback<T, U, V, X>;if (callback != null){callback(arg1, arg2, arg3, arg4);}else{throw CreateBroadcastSignatureException(eventType);}}}
}
/*
//This manager will ensure that the messenger's mEventTable will be cleaned up upon loading of a new level.
public sealed class MessengerHelper : MonoBehaviour {void Awake (){DontDestroyOnLoad(gameObject); }//Clean up mEventTable every time a new level loads.public void OnDisable() {Messenger.Cleanup();}
}
*/
然后,在DefineCommon里面定义委托类型和事件类型:
public delegate void Callback();public delegate void Callback<T>(T arg1);public delegate void Callback<T, U>(T arg1, U arg2);public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);public delegate void Callback<T, U, V, X>(T arg1, U arg2, V arg3, X arg4);
/// <summary>/// 事件类型/// </summary>public enum EGameEvent{eGameEvent_ShowMessage //显示MessageBox}
CEvent.cs事件类:
using UnityEngine;
using System.Collections.Generic;
using Game.Common;
public class CEvent
{private EGameEvent eventId;private Dictionary<string, object> paramList;public CEvent(){paramList = new Dictionary<string, object>();}public CEvent(EGameEvent id){eventId = id;paramList = new Dictionary<string, object>();}public EGameEvent GetEventId(){return eventId;}public void AddParam(string name, object value){paramList[name] = value;}public object GetParam(string name){if (paramList.ContainsKey(name)){return paramList[name];}return null;}public bool HasParam(string name){if (paramList.ContainsKey(name)){return true;}return false;}public int GetParamCount(){return paramList.Count;}public Dictionary<string, object> GetParamList(){return paramList;}
}
OK,消息中心器处理好了,接着在MessageWindow里面注册事件,在Init()方法里面:
public override void Init(){EventCenter.AddListener<EMessageType,Action<bool>>(EGameEvent.eGameEvent_ShowMessage, ShowMessage);}
那么这个Init()是什么时候调用的,我们回到WindowManager里面,定义一个Init()方法,初始化所有的WindowsUI界面。
public void Init(){foreach (var pWindow in this.mWidowDic.Values){pWindow.Init();if (pWindow.IsResident()){pWindow.PreLoad();}}}
然后我们知道显示消息界面是在LOLGameDriver脚本里面:
checkTimeout.AsynIsNetworkTimeout((result) => {//网络良好if (!result){//开始更新检测DoInit();}else //说明网络错误{//开始消息提示框,重试和退出EventCenter.Broadcast<EMessageType, Action<bool>>(EGameEvent.eGameEvent_ShowMessage, EMessageType.EMT_NetTryAgain, (isOk) => {if (isOk){TryInit();//重试}else {Application.Quit();//退出}});}});
然后在Awake里面添加WindowManager.Init():
断开网络,运行程序:
仿LOL项目开发第五天地址链接
---恢复内容结束---