01游戏框架设计之初识框架

写在前面:
写本博客的初心是为了更好的总结学习游戏框架遇到的知识点,难免会有理解错误的地方,望大神批评指正。

本框架使用的消息分发机制来实现的。重要组成部分如下:

  • 消息处理中心MsgCenter
    消息处理中心是整个模块的中转站,模块管理者Manager如果想与其它模块通讯的话,必须通过此中转站,中转站通过消息ID找到对应模块,然后交付给此模块内部处理。
    提供的功能:注册消息,销毁消息,分发广播消息,更新消息
  • 消息体Msg
    消息是每个模块传递数据的载体,其必须包含唯一的消息ID,设计架构时根据需要划分每个模块的ID范围,一般用枚举表示范围。
  • 模块管理者Manager
    模块的管理者Manager统一继承至一个模板类,节省代码,方便管理。
    模块管理者调用消息管理中心MsgCenter提供的方法,注册消息,发送消息,接收消息 ,销毁消息。
    如果本模块需要与其它模块通信,在注册消息时也需要注册其它模块,这样通过委托事件可以得到其它模块的消息。

消息处理中心MsgCenter

using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 消息回调函数
/// </summary>
/// <param name="msg"></param>
public delegate void MsgCallbackd(Msg msg);

public class MsgCenter : MonoBehaviour
{
    /*
     * 实现功能:
     * 1.注册注销消息:消息集合,记录待处理事件,注册消息,销毁消息,广播通知,刷新
     * 2.发送消息到对应模块
     */


    private static MsgCenter _instance;

    /// <summary>
    /// 单例
    /// </summary>
    public static MsgCenter Instance
    {
        get
        {
            if (_instance == null)
            {
                GameObject obj = new GameObject("MsgCenter");
                _instance = obj.AddComponent<MsgCenter>();
                DontDestroyOnLoad(obj);
            }
            return _instance;
        }
    }

    /// <summary>
    /// 消息集合
    /// </summary>
    private Dictionary<int, MsgCallbackd> MsgDic = new Dictionary<int, MsgCallbackd>();

    /// <summary>
    /// 待处理消息集合
    /// </summary>
    Queue<Action> todoCallBack = new Queue<Action>();

    #region 注册消息

    /// <summary>
    /// 注册多条消息
    /// </summary>
    /// <param name="callback"></param>
    /// <param name="msgIds"></param>
    /// <returns></returns>
    public bool RegistMsgs(MsgCallbackd callback, int[] msgIds)
    {
        if (callback == null)
        {
            Debug.LogWarning("注册消息失败");
            return false;
        }
        for (int i = 0; i < msgIds.Length; i++)
        {
            RegistMsg(callback, msgIds[i]);
        }
        Debug.Log("注册消息成功");
        return true;
    }

    /// <summary>
    /// 注册一条消息
    /// </summary>
    /// <param name="callback"></param>
    /// <param name="i"></param>
    public bool RegistMsg(MsgCallbackd callback, int msgId)
    {
        //通过操作消息集合MsgDic建立消息ID和委托建立联系
        /*
         * 1.没有委托内容返回
         * 2.集合不存在,添加内容到集合
         * 3.集合存在,添加委托事件给消息
         */
        if (callback == null)
            return false;
        if (MsgDic.ContainsKey(msgId))
        {
            MsgDic[msgId] += callback;
        }
        else
        {
            MsgDic.Add(msgId, callback);
        }

        return true;
    }
    #endregion

    #region 注销消息
    /// <summary>
    /// 注销多条消息
    /// </summary>
    /// <param name="msgIds"></param>
    /// <returns></returns>
    public bool UnRegistMsgs(MsgCallbackd callbackd, int[] msgIds)
    {
        if (callbackd == null)
            return false;
        for (int i = 0; i < msgIds.Length; i++)
        {
            UnRegistMsg(callbackd, msgIds[i]);
        }
        return true;
    }

    /// <summary>
    /// 注销一条消息
    /// </summary>
    public bool UnRegistMsg(MsgCallbackd callbackd, int msgId)
    {
        if (!MsgDic.ContainsKey(msgId) || callbackd == null)
        {
            return false;
        }
        else
        {
            //注意一条id对应多条委托情况
            MsgDic[msgId] -= callbackd;
            if (MsgDic[msgId] == null)
            {
                MsgDic.Remove(msgId);
            }
            return true;
        }
    }

    #endregion


    #region 广播分发消息
    /// <summary>
    /// 广播分发消息
    /// </summary>
    /// <param name="msg">传入的消息内容</param>
    /// <returns></returns>
    public bool PostMsg(Msg msg = null)
    {
        if (msg.msgId > 0 && MsgDic.ContainsKey(msg.msgId) && MsgDic[msg.msgId] != null)
        {
            //加入队列
            lock (todoCallBack)
            {
                //通过msgId找到对应的方法,加入队列
                todoCallBack.Enqueue(() => MsgDic[msg.msgId](msg));
                
            }

            return true;
        }

        return false;
    }

    #endregion

    /// <summary>
    /// 刷新待处理消息
    /// </summary>
    private void Update()
    {
        if (todoCallBack.Count == 0)
            return;

        lock (todoCallBack)
        {
            while (todoCallBack.Count > 0)
            {
                Action a = todoCallBack.Dequeue();
                a.Invoke();
            }

            todoCallBack.Clear();
        }
    }

}

消息体

using System.Collections;


public class Msg 
{
    /// <summary>
    /// 消息ID
    /// </summary>
    public int msgId { get; protected set; }

    /// <summary>
    /// 发送的内容
    /// </summary>
    public object sender { get; protected set; }
}

public class MsgSetting
{
    public const int IdSpan = 100;
}

public enum MgrId
{
    //分模块划分消息ID,定义id起点长度,每个模块单独管理自己id
    
    //0~99
    UIMgr=0,

    //100~199
    ResourceMgr=MsgSetting.IdSpan*2,

    //200~299
    AudioMgr=MsgSetting.IdSpan*3,
}

模块管理者

首先是管理者模板

using UnityEngine;

/// <summary>
/// 模块管理者
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class MgrSingle<T> : MonoBehaviour where T : MonoBehaviour
{
    //MgrSingle<T>告诉子类引用的形式,其中T相当于模板的类型,用where指定

    public static T Instance { get; protected set; }

    protected void Awake()
    {
        //if (Instance != null)
        //    DestroyImmediate(Instance.gameObject);

        Instance = this as T;

        OnAwake();
    }

    protected abstract void OnAwake();
}

下面演示不同模块的通讯过程,A模块(ResourceMgr)向B模块(AudioMgr)发送消息时,如果B模块想接收A模块的消息,必须向MsgCenter注册A模块的消息。
A模块:

using UnityEngine;
using System.Collections;
using System;

public class ResourcesMgrDemo : MgrSingle<MonoBehaviour>
{
    protected override void OnAwake()
    {
        MsgCenter.Instance.RegistMsg(CallBack, (int)DemoMsgId.ResourceId);
    }

    private void OnDestroy()
    {
        MsgCenter.Instance.UnRegistMsg(CallBack, (int)DemoMsgId.ResourceId);
    }

    private void CallBack(Msg msg)
    {
        if (msg == null || msg.msgId < 0)
            return;
        else
        {
            switch(msg.msgId)
            {
                case (int)DemoMsgId.AudioId:
                    break;

                case (int)DemoMsgId.ResourceId:
                    break;
            }
        }
    }

    // Use this for initialization
    void Start()
    {
        //测试Resource模块向Audio模块发送消息
        Debug.Log("ddd");
        DemoMsg msg = new DemoMsg((int)MgrId.AudioMgr, "admin1", 21, this);
        MsgCenter.Instance.PostMsg(msg);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

B模块:

using UnityEngine;
using System.Collections;

public class AudioMgrDemo : MgrSingle<MonoBehaviour>
{
    protected override void OnAwake()
    {
        MsgCenter.Instance.RegistMsg(CallBack, (int)DemoMsgId.AudioId);
    }

    private void OnDestroy()
    {
        MsgCenter.Instance.UnRegistMsg(CallBack, (int)DemoMsgId.AudioId);
    }

    private void CallBack(Msg msg)
    {
        if (msg == null || msg.msgId < 0)
            return;
        else
        {
            switch (msg.msgId)
            {
                case (int)DemoMsgId.AudioId:

                    DemoMsg audioMsg = msg as DemoMsg;
                    Debug.LogWarning("收到其它模块发送的消息");
                    Debug.LogFormat("收到AudioId,id:{0},sender:{1},name:{2},age:{3}", audioMsg.msgId, audioMsg.sender, audioMsg.m_Name, audioMsg.m_Age);

                    break;

                case (int)DemoMsgId.ResourceId:
                    break;
            }
        }
    }
}

测试过程

创建新的游戏物体并添加代码如下:

在这里插入图片描述
PS:这样做确实有不妥的地方,因为第一次使用框架,想急切感受框架的魅力,先这样操作,后面的文章我会继续升级。
在这里插入图片描述
在AudioMgr模块确实收到了消息,下面验证消息来源是不是ResourceMgr模块的发送的。
在这里插入图片描述
在这里插入图片描述
恭喜模块通信成功!

参考文章:http://gad.qq.com/article/detail/287237

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值