仿LOL项目开发第四天

---恢复内容开始---

仿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> : MonoBehaviour
       where 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_LISTENER

using 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 0414

    static public Dictionary<EGameEvent, Delegate> mEventTable = new Dictionary<EGameEvent, Delegate>();

    //Message handlers that should never be removed, regardless of calling Cleanup
    static public List<EGameEvent> mPermanentMessages = new List<EGameEvent>();


    //Marks a certain message as permanent.
    static public void MarkAsPermanent(EGameEvent eventType)
    {
#if LOG_ALL_MESSAGES
		Debug.Log("Messenger MarkAsPermanent \t\"" + eventType + "\"");
#endif

        mPermanentMessages.Add(eventType);
    }


    static public void Cleanup()
    {
#if LOG_ALL_MESSAGES
		Debug.Log("MESSENGER Cleanup. Make sure that none of necessary listeners are removed.");
#endif

        List<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_LISTENER
		Debug.Log("MESSENGER OnListenerAdding \t\"" + eventType + "\"\t{" + listenerBeingAdded.Target + " -> " + listenerBeingAdded.Method + "}");
#endif

        if (!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_MESSAGES
		Debug.Log("MESSENGER OnListenerRemoving \t\"" + eventType + "\"\t{" + listenerBeingRemoved.Target + " -> " + listenerBeingRemoved.Method + "}");
#endif

        if (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_LISTENER
        if (!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 parameters
    static public void AddListener(EGameEvent eventType, Callback handler)
    {
        OnListenerAdding(eventType, handler);
        mEventTable[eventType] = (Callback)mEventTable[eventType] + handler;
    }

    //Single parameter
    static public void AddListener<T>(EGameEvent eventType, Callback<T> handler)
    {
        OnListenerAdding(eventType, handler);
        mEventTable[eventType] = (Callback<T>)mEventTable[eventType] + handler;
    }

    //Two parameters
    static public void AddListener<T, U>(EGameEvent eventType, Callback<T, U> handler)
    {
        OnListenerAdding(eventType, handler);
        mEventTable[eventType] = (Callback<T, U>)mEventTable[eventType] + handler;
    }

    //Three parameters
    static 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 parameters
    static 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 parameters
    static public void RemoveListener(EGameEvent eventType, Callback handler)
    {
        OnListenerRemoving(eventType, handler);
        mEventTable[eventType] = (Callback)mEventTable[eventType] - handler;
        OnListenerRemoved(eventType);
    }
    //Single parameter
    static public void RemoveListener<T>(EGameEvent eventType, Callback<T> handler)
    {
        OnListenerRemoving(eventType, handler);
        mEventTable[eventType] = (Callback<T>)mEventTable[eventType] - handler;
        OnListenerRemoved(eventType);
    }

    //Two parameters
    static 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 parameters
    static 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 parameters
    static 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 parameters
    static public void Broadcast(EGameEvent eventType)
    {
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
		Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
        OnBroadcasting(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 parameter
    static public void Broadcast<T>(EGameEvent eventType, T arg1)
    {
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
		Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
        OnBroadcasting(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 parameters
    static public void Broadcast<T, U>(EGameEvent eventType, T arg1, U arg2)
    {
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
		Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
        OnBroadcasting(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 parameters
    static public void Broadcast<T, U, V>(EGameEvent eventType, T arg1, U arg2, V arg3)
    {
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
		Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
        OnBroadcasting(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 parameters
    static public void Broadcast<T, U, V, X>(EGameEvent eventType, T arg1, U arg2, V arg3, X arg4)
    {
#if LOG_ALL_MESSAGES || LOG_BROADCAST_MESSAGE
		Debug.Log("MESSENGER\t" + System.DateTime.Now.ToString("hh:mm:ss.fff") + "\t\t\tInvoking \t\"" + eventType + "\"");
#endif
        OnBroadcasting(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项目开发第五天地址链接

 

---恢复内容结束---

posted @ 2016-05-08 18:45  草帽领  阅读(1358)  评论(0编辑  收藏  举报