游戏框架搭建(二)

发布于 2020-05-20  13 次阅读


前言

第一篇做了导出工具和一些常用代码库的分离。

正文

这篇讲单例模式、消息机制和MonoBehaviour的简化

单例设计模式

单例必不可少。
单例模式就是保证一个类只有一个实例的一种实现方法。通俗来讲就是有且只有一个实例。
这是是泛型单例模板,Singleton和MonoSingleton

namespace SQFramework
{
    public interface ISingleton
    {
        void OnSingletonInit();
    }
    public class Singleton<T> : ISingleton where T : Singleton<T>
    {
        protected static T mInstance = null;
        static object mLock = new object(); 
        public static T Instance
        {
            get
            {
                lock (mLock)
                {
                    if (mInstance == null)
                    {
                        mInstance = SingletonCreator.CreateSingleton<T>();
                    }
                } 
                return mInstance;
            }
        }
        public virtual void Dispose()
        {
            mInstance = null;
        }
        public void OnSingletonInit()
        { 
        }
    }
    public static class SingletonCreator
    {
        public static T CreateSingleton<T>() where T : class, ISingleton
        {
            // 获取私有构造函数
            var ctors = typeof(T).GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic);
            // 获取无参构造函数
            var ctor = System.Array.Find(ctors, c => c.GetParameters().Length == 0);
            if (ctor == null)
            {
                throw new System.Exception("Non-Public Constructor() not found! in " + typeof(T));
            }
            // 通过构造函数,常见实例
            var retInstance = ctor.Invoke(null) as T;
            retInstance.OnSingletonInit();
            return retInstance;
        }
    }  
    public abstract class MonoSingleton<T> : MonoBehaviour where T : MonoSingleton<T>
    {
        protected static T instance = null;

        public static T Instance()
        {
            if (instance == null)
            {
                instance = FindObjectOfType<T>();

                if (FindObjectsOfType<T>().Length > 1)
                {
                    Debug.LogError("More than 1!");
                    return instance;
                }
                if (instance == null)
                {
                    string instanceName = typeof(T).Name;
                    Debug.Log("Instance Name: " + instanceName);
                    GameObject instanceGO = GameObject.Find(instanceName);

                    if (instanceGO == null)
                        instanceGO = new GameObject(instanceName);
                    instance = instanceGO.AddComponent<T>();
                    DontDestroyOnLoad(instanceGO);  //保证实例不会被释放
                    Debug.Log("Add New Singleton " + instance.name + " in Game!");
                }
                else
                {
                    Debug.Log("Already exist: " + instance.name);
                }
            } 
            return instance;
        }
        protected virtual void OnDestroy()
        {
            instance = null;
        }
    }
}

简易的消息机制

这里有个传送门: C#简易消息机制

MonoBehaviour简化

为什么要简化MonoBehaviour? 封装一些方法提高效率。

public partial class MonoBehaviourSimplify : MonoBehaviour
{

    public void Show()
    {
        GameObjectSimplify.Show(gameObject);
    }

    public void Hide()
    {
        GameObjectSimplify.Hide(gameObject);
    }

    public void Identity()
    {
        TransformSimplify.Identity(transform);
    }

    public void Delay(float seconds, Action onFinished)
    {
        StartCoroutine(DelayCoroutine(seconds, onFinished));
    }

    private static IEnumerator DelayCoroutine(float seconds, Action onFinished)
    {
        yield return new WaitForSeconds(seconds);

        onFinished();
    } 
}

消息机制继承到MonoBehaviourSimplify

 public abstract partial class MonoBehaviourSimplify 
    {
        List<MsgRecord> mMsgRecorder = new List<MsgRecord>();
        private class MsgRecord
        {
            private static readonly Stack<MsgRecord> mMsgRecordPool = new Stack<MsgRecord>();

            public static MsgRecord Allocate(string msgName, Action<object> onMsgReceived)
            {
                MsgRecord retMsgRecord = null;

                retMsgRecord = mMsgRecordPool.Count > 0 ? mMsgRecordPool.Pop() : new MsgRecord();

                retMsgRecord.Name = msgName;
                retMsgRecord.OnMsgReceived = onMsgReceived; 

                return retMsgRecord;
            }

            public void Recycle()
            {
                Name = null;
                OnMsgReceived = null;

                mMsgRecordPool.Push(this);
            }

            public string Name;

            public Action<object> OnMsgReceived;
        }
        protected void RegisterMsg(string msgName, Action<object> onMsgReceived)
        {
            MsgDispatcher.Register(msgName, onMsgReceived);

            mMsgRecorder.Add(MsgRecord.Allocate(msgName, onMsgReceived));
        }

        protected void UnRegisterMsg(string msgName)
        {
            var selectedRecords = mMsgRecorder.FindAll(recorder => recorder.Name == msgName);

            selectedRecords.ForEach(selectRecord =>
            {
                MsgDispatcher.UnRegister(selectRecord.Name, selectRecord.OnMsgReceived);
                mMsgRecorder.Remove(selectRecord);
                selectRecord.Recycle();
            });

            selectedRecords.Clear();
        }

        protected void UnRegisterMsg(string msgName, Action<object> onMsgReceived)
        {
            var selectedRecords = mMsgRecorder.FindAll(recorder => recorder.Name == msgName && recorder.OnMsgReceived == onMsgReceived);

            selectedRecords.ForEach(selectRecord =>
            {
                MsgDispatcher.UnRegister(selectRecord.Name, selectRecord.OnMsgReceived);
                mMsgRecorder.Remove(selectRecord);
                selectRecord.Recycle();
            });

            selectedRecords.Clear();
        }

        private void OnDestroy()
        {
            OnBeforeDestroy();

            foreach (var msgRecord in mMsgRecorder)
            {
                MsgDispatcher.UnRegister(msgRecord.Name, msgRecord.OnMsgReceived);
                msgRecord.Recycle();
            }

            mMsgRecorder.Clear();
        }
        protected abstract void OnBeforeDestroy();
    }
   public class MonoExample : MonoBehaviourSimplify
    {  
        private void Start()
        { 
            RegisterMsg("Do", DoSomething); 
            RegisterMsg("DO1", _ => { }); 
            UnRegisterMsg("Do",DoSomething);
        }
        void DoSomething(object data)
        { 
            Debug.LogFormat("Received Do msg:{0}", data);
        }
        protected override void OnBeforeDestroy()
        {

        }
    }

总结

到这里我们就实现了简单的框架,继承MonoBehaviourSimplify不仅实现单例,还继承了消息机制。


不积跬步,无以至千里;不积小流,无以成江海。