Unity3D框架——AMPVCS(自研)详解
  8Z8YLacFlZ6x 2023年11月02日 23 0

MVC原理的基础上扩展为AMPVC框架,直接上图上代码

Unity3D框架——AMPVCS(自研)详解_MVC

1.IElement接口

public interface IElement 
    {
        /// <summary>
        /// 发送通知
        /// </summary>
        /// <param name="type"></param>
        /// <param name="eventType"></param>
        /// <param name="p_data"></param>
        void SendNotify(Tool.Type type, Tool.EventType eventType, params object[] p_data);
        void SendNotify(Tool.Type type, params object[] p_data);
        /// <summary>
        /// 命令执行
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="p_data"></param>
        void OnExeCute(Tool.EventType eventType, params object[] p_data);
        void OnExeCute(params object[] p_data);

    }
public class Element : MonoBehaviour,IElement
    {
        public virtual void OnExeCute(Tool.EventType eventType, params object[] p_data) 
        {
        }
        public void OnExeCute(params object[] p_data)
        {   
        }
        public void SendNotify(Type type, Tool.EventType eventType, params object[] p_data)
        {
            this.RetrieveEntity(type).OnExeCute(eventType, p_data);
        }
        public void SendNotify(Type type, params object[] p_data)
        {
            this.RetrieveEntity(type).OnExeCute(p_data);
        }
    }

2.App

public class AppGame : Element
    {
        private void Awake()
        {
            #region 注册model代理
            (new TestProxy()).Register(Type.TEST_PROXY);
            #endregion


            #region --- 绑定controller
            gameObject.Bind<TestController>(Type.TEST);

            #endregion
        }

        // Start is called before the first frame update
        void Start()
        {
            Application.runInBackground = true;
            Application.targetFrameRate = -1;
           
            this.LoadInitConfig();
        }
    }
    
    public enum Type
    {
        None,
        #region View
        TEST_VIEW,

        #endregion

        #region Controller
        TEST,
        
        #endregion

        #region  model Proxy
        TEST_PROXY,
        
        #endregion
    }

    public enum SocketType
    {
        None,
        HEART, ///心跳检测

    }

    public enum EventType
    {
        None,

        #region //View 点击事件
        Click_Test_Button,
        #endregion
        #region View function type          //View
        /// <summary>
        /// 测试点击事件反馈事件
        /// </summary>
        View_Test_Click_Event,

        #endregion
        #region controller function type         //controller

        /// <summary>
        /// 框架测试
        /// </summary>
        Command_Test_Click_Event,
    }
///容器
   public static class AppIOC
    {
        /// <summary>
        /// view、controller、proxy
        /// </summary>
        private static Dictionary<Type, IElement> GameEventHandlerMap = new Dictionary<Type, IElement>();
        /// <summary>
        /// 本地配置资源
        /// </summary>
        private static Dictionary<string, IModel> configModelMap = new Dictionary<string, IModel>();
        //设备
        private static Dictionary<string, IFacility> devModeMap = new Dictionary<string, IFacility>();

        private static void AddHandler(this IElement value, Type type)
        {
            if (!GameEventHandlerMap.ContainsKey(type)) GameEventHandlerMap.Add(type, value);
        }

        private static void RemoveHandler(this IElement value, Type type)
        {
            if (GameEventHandlerMap.ContainsKey(type)) GameEventHandlerMap.Remove(type);
        }

        public static void Bind<T>(this GameObject gameObject,Type type) where T : BaseController
        {
            if (gameObject.GetComponent<T>() == null)
                gameObject.AddComponent<T>().RegisterController(type);
            else
                gameObject.GetComponent<T>().RegisterController(type);
        }

        public static void Register(this IElement value, Type type)
        {
            AddHandler(value, type);        
        }
        public static void Remove(this IElement value, Type type)
        {
            RemoveHandler(value, type);
        }

        public static IElement RetrieveEntity(this IElement value, Type type)
        {
            if (!GameEventHandlerMap.ContainsKey(type)) return null;
            return GameEventHandlerMap[type];
        }


        public static void AddConfigModel(string key,IModel value)
        {
            if (!configModelMap.ContainsKey(key))
                configModelMap.Add(key, value);
        }

        public static IModel RetrieveModel(string value)
        {
            if (!configModelMap.ContainsKey(value)) return null;
            return configModelMap[value];
        }

        //模型注册
        public static void OnRegisterFacility(this IFacility value)
        {
            if (!devModeMap.ContainsKey(value.DevID))
                devModeMap.Add(value.DevID, value);
        }

        public static void OnRemoveFacility(this IFacility value)
        {
            if (devModeMap.ContainsKey(value.DevID)) devModeMap.Remove(value.DevID);
        }
    }

3.IModel

public interface IModel
    {
    }
public class BaseModel : Element
    {
       
    }

4.IProxy

public interface IProxy
    {
		/// <summary>
		/// Called by the Model when the Proxy is registered
		/// </summary>
		void RegisterProxy();
		/// <summary>
		/// Called by the Model when the Proxy is removed
		/// </summary>
		void RemoveProxy();

		/// <summary>
		///  proxy model accept to from net data 
		/// </summary>
		/// <param name="values"></param>
		void AcceptNetInfo(string values);
		void AcceptNetInfo(Tool.EventType eventType, params object[] p_data);
	}
public class BaseProxy : IProxy,IElement
    {

        public BaseProxy() { }
        public BaseProxy(string value){ }

        /// <summary>
        /// 注册 Proxy
        /// </summary>
        public virtual void RegisterProxy()
        { 
        }
        /// <summary>
        /// 注销Proxy
        /// </summary>
        public virtual void RemoveProxy()
        {        
        }

        /// <summary>
        /// 接收服务数据
        /// </summary>
        /// <param name="values"></param>
        public virtual void AcceptNetInfo(string values)
        { 
        }
        public virtual void AcceptNetInfo(Tool.EventType eventType, params object[] p_data)
        {  
        }

        public void OnExeCute(Tool.EventType eventType, params object[] p_data)
        {
            AcceptNetInfo(eventType, p_data);
        }

        /// <summary>
        /// 接收到的数
        /// </summary>
        /// <param name="p_data"></param>
        public void OnExeCute(params object[] p_data)
        {
            AcceptNetInfo(p_data[0].ToString());
        }
        public void SendNotify(Tool.Type type, Tool.EventType eventType, params object[] p_data)
        {
            this.RetrieveEntity(type).OnExeCute(eventType, p_data);
        }
        public void SendNotify(Tool.Type type, params object[] p_data)
        {
            this.RetrieveEntity(type).OnExeCute(p_data);
        }

        /// <summary>
        /// 是否有数据判断
        /// </summary>
        /// <param name="rows"></param>
        /// <returns></returns>
        protected bool IsOnRow(IEnumerable<Row> rows)
        {
            int count = rows.Count(r => !r.IsEmpty());
            if (count == 0)
                return false;
            return true;
        }
    }

5.IView

(注:可以拆成View 和 Meditor)

public interface IView
    {
        /// <summary>
        /// 注册View
        /// </summary>
        void RegisterView();
        void RemoveView();
        //属性数据更新
        void OnUpdate(params object[] p_data);
    }
public class BaseView : Element,IView
    {
        /// <summary>
        /// Used for locking
        /// </summary>
        protected readonly object m_syncRoot = new object();

        protected virtual void Awake()
        {
            RegisterView();
        }

        /// <summary>
        /// 注册 View
        /// </summary>
        public virtual void RegisterView() { }

        /// <summary>
        /// 移除View
        /// </summary>
        public virtual void RemoveView(){ }
        /// <summary>
        /// 数据更新
        /// </summary>
        /// <param name="p_data"></param>
        public virtual void OnUpdate(params object[] p_data){ }

        public sealed override void OnExeCute(Tool.EventType eventType, params object[] p_data)
        {
            HandleNotification(eventType, p_data);
        }
        /// <summary>
        /// 接收从控制层传来的数据
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="p_data"></param>
        protected virtual void HandleNotification(Tool.EventType eventType, params object[] p_data)
        {
        }

    }
public interface IFacility
    {

        string DevID { get;}
        /// <summary>
        /// 设备初始化
        /// </summary>
        void OnInit();
        /// <summary>
        /// 点击事件
        /// </summary>
        void OnClick();
        /// <summary>
        /// 行为
        /// </summary>
        /// <param name="value"></param>
        void OnMotion(params object[] value);

    }
public class Facility : BaseView ,IFacility
    {

        public string Id;
        public string DevID { get { return Id; } }

        [HideInInspector]
        public GameObject obj;

        protected override void Awake()
        {
            base.Awake();
        }

        protected void RegisterDevView(Facility facility)
        {
            facility.OnRegisterFacility();
        }

        public sealed override void RemoveView()
        {
            this.OnRemoveFacility();
        }

        protected virtual void Start()
        {
            obj = this.gameObject;
        }
        public virtual void OnInit()
        {
        }
        public virtual void OnClick()
        {
        }
        public virtual void OnMotion(params object[] value)
        {    
        }

        }
        //设置动画
        public void SetTrrigerAnimator(Animator _animator, string takeName, string stateName, UnityAction callback)
        {
            AnimationClip[] AnimationClips = _animator.runtimeAnimatorController.animationClips;
            float _time = 0;
            for (int i = 0; i < AnimationClips.Length; i++)
            {
                if (AnimationClips[i].name == takeName)
                {
                    _time = AnimationClips[i].length;
                }
            }
            _animator.SetTrigger(stateName);
            StartCoroutine(AnimatorPlayFinished(_time, callback));
        }

        public void SetTrrigerAnimator(Animator _animator, string takeName, UnityAction callback)
        {
            AnimationClip[] AnimationClips = _animator.runtimeAnimatorController.animationClips;
            float _time = 0;
            for (int i = 0; i < AnimationClips.Length; i++)
            {
                if (AnimationClips[i].name == takeName)
                {
                    _time = AnimationClips[i].length;
                }
            }
            _animator.SetTrigger(takeName);
            StartCoroutine(AnimatorPlayFinished(_time, callback));
        }
        private IEnumerator AnimatorPlayFinished(float time, UnityAction callback)
        {
            yield return new WaitForSeconds(time + 1);
            if (callback != null) callback.Invoke();
        }
    }

6.IController

public interface IController
    {
        /// <summary>
        /// 注册Controller
        /// </summary>
        /// <param name="type"></param>
        void RegisterController(Type type);
        void RemoveController(Type type);
    }
public class BaseController : Element,IController
    { 
        public void RegisterController(Type type)
        {
            this.Register(type);
        }
        public void RemoveController(Type type)
        {
            this.Remove(type);
        }
        public sealed override void OnExeCute(Tool.EventType eventType, params object[] p_data)
        {
            DoCommand(eventType, p_data);
        }
        protected virtual void DoCommand(Tool.EventType eventType, params object[] p_data)
        {
        }
    }

7.IServer

public interface IServer
    {
        /// <summary>
        /// 服务get请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="actionResult"></param>
        void Get(string url, Action<bool, string> actionResult);
        void Get(string url, string data, Action<bool, string> actionResult);
        /// <summary>
        /// Post请求
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <param name="actionResult"></param>
        void Post(string url,string data, Action<bool, string> actionResult);
    }
public class HttpServer :MonoSingleton<HttpServer>, IServer
    {
        public virtual void Get(string url, Action<bool, string> actionResult)
        {  
         StartCoroutine(_Get(url, actionResult));
        }
        public virtual void Get(string url, string data, Action<bool, string> actionResult)
        {       
        }
        public virtual void Post(string url, string data, Action<bool, string> actionResult)
        {    
          StartCoroutine(_Post(url, data, actionResult));
        }
        /// <summary>
        /// GET请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="action">请求发起后处理回调结果的委托</param>
        /// <returns></returns>
        IEnumerator _Get(string url, System.Action<bool, string> actionResult)
        {
            using (UnityWebRequest quest = UnityWebRequest.Get(url))
            {
                yield return quest.SendWebRequest();
                string msg = "";
                if (quest.isNetworkError || quest.isHttpError)
                {
                    msg = quest.error;
                }
                else
                {
                    msg = quest.downloadHandler.text;
                }
                if (actionResult != null)
                {
                    actionResult.Invoke(quest.isHttpError, msg);
                }
            }
        }
        
         /// <summary>
        /// 向服务器提交post请求
        /// </summary>
        /// <param name="url">服务器请求目标地址</param>
        /// <param name="formData">form表单参数</param>
        /// <returns></returns>
        IEnumerator _Post(string url, string formData, System.Action<bool, string> actionResult)
        {

            using (UnityWebRequest quest = UnityWebRequest.Post(url, formData))
            {
                //发送数据
                setWebRequest(quest, formData);
                yield return quest.SendWebRequest();
                string text = "";
                if (!(quest.isNetworkError || quest.isHttpError))
                {
                    text = quest.downloadHandler.text;
                }
                else
                {
                    text = quest.error;
                }
                if (actionResult != null)
                {
                    actionResult.Invoke(quest.isHttpError, text);
                }
            }
        }
        
    }
public class SocketClient : Element
    {
        public static SocketClient Instance;
        /// <summary>
        /// Saved WebSocket instance
        /// </summary>
        protected static WebSocket webSocket;
        public static WebSocket WebSocket
        {
            get
            {
                return webSocket;
            }
        }
        public static bool IsOnScoket = false;
        private Coroutine _pingCor, _clientPing, _serverPing;
        private bool lockReconnect = false; //表示是否在连接过程中
        private string heart = "{\"type\": \"WEB_HEART\"}";

        private float timer = 5;

        private void Awake()
        {
            if (Instance == null)
            {
                Instance = this;
                DontDestroyOnLoad(this.gameObject);
            }
            else if (Instance != this)
            {
                Destroy(this.gameObject);
                return;
            }
        }
        private void Update()
        {
            if (IsOnScoket)
            {
                IsOnScoket = false;
                OnConnect();
            }
        }
        private void OnApplicationQuit()
        {
            OnClose();
        }



        public void OnConnect()
        {
            try
            {
                webSocket = new WebSocket(new System.Uri(ConfigManager.serverUrl));
#if !UNITY_WEBGL
            //this.webSocket.StartPingThread = true;
            webSocket.StartPingThread = true;
#endif
                AddHandle();
                // Start connecting to the server
                webSocket.Open();
            }
            catch (Exception e)
            {
                Debug.Log("WebSocket连接异常:" + e.Message);
                ReConnect();
            }

        }


        void OnClose()
        {
            if (webSocket != null)
            {
                webSocket.Close();
                webSocket = null;
            }
        }

        public void OnSend(string data)
        {
            if (webSocket == null || string.IsNullOrEmpty(data)) return;
            if (webSocket.IsOpen) webSocket.Send(data);
        }

        void AddHandle()
        {
            RemoveHandle();
            // Subscribe to the WS events
            webSocket.OnOpen += OnOpen;
            webSocket.OnMessage += OnMessageReceived;
            webSocket.OnClosed += OnClosed;
            webSocket.OnError += OnError;
        }

        void RemoveHandle()
        {
            webSocket.OnOpen -= OnOpen;
            webSocket.OnMessage -= OnMessageReceived;
            webSocket.OnClosed -= OnClosed;
            webSocket.OnError -= OnError;
        }

        /// <summary>
        /// 重连
        /// </summary>
        void ReConnect()
        {
            if (this.lockReconnect)
                return;
            this.lockReconnect = true;
            StartCoroutine(SetReConnect());
        }

        //心跳检测
        private void HeartCheck()
        {
            if (_clientPing != null)
            {
                StopCoroutine(_clientPing);
                _clientPing = null;
            }
            if (_serverPing != null)
            {
                StopCoroutine(_serverPing);
                _serverPing = null;
            }
            _clientPing = StartCoroutine(ClientPing());
        }

        //重连WebSocket
        private IEnumerator SetReConnect()
        {
            Debug.Log("正在重连websocket");
            yield return new WaitForSeconds(timer);
            OnConnect();
            lockReconnect = false;
        }

        // 这里发送一个心跳,后端收到后,返回一个心跳消息
        // onmessage拿到返回的心跳就说明连接正常
        private IEnumerator ClientPing()
        {
            yield return new WaitForSeconds(timer);
            this.OnSend(heart);
            _serverPing = StartCoroutine(ServerPing());
        }

        // 如果超过一定时间还没重置,说明后端主动断开了
        // 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
        private IEnumerator ServerPing()
        {
            yield return new WaitForSeconds(timer);
            webSocket.Close();
        }

        //发送心跳
        private IEnumerator HeartPing()
        {
            while (true)
            {
                yield return new WaitForSeconds(timer);
                this.OnSend(heart);
            }
        }


        #region 回调

        void OnOpen(WebSocket ws)
        {

            //SendNotify(Tool.Type.SOCKET_PROXY,Tool.EventType.Proxy_Socket_Connected_Event ,ws.Context);
            //停止发送心跳
            if (_pingCor != null)
            {
                StopCoroutine(_pingCor);
                _pingCor = null;
            }
            //发送心跳
            _pingCor = StartCoroutine(HeartPing());
            // 心跳检测重置
            HeartCheck();
        }

        public void OnMessageReceived(WebSocket ws, string message)
        {
            if (message.Equals("") || message == null) return;
            SendNotify(Tool.Type.SOCKET_PROXY,message);
            // 拿到任何消息都说明当前连接是正常的
            HeartCheck();  // 如果获取到消息,心跳检测重置
        }

        void OnClosed(WebSocket ws, System.UInt16 code, string message)
        {
            SendNotify(Tool.Type.SOCKET_PROXY, Tool.EventType.Proxy_Socket_Closed_Event,message);
            webSocket = null;
            ReConnect();
        }

        void OnError(WebSocket ws, string error)
        {
            if (error != null)
                Debug.Log("websocket连接异常:" + error);
            webSocket = null;
            ReConnect();

        }
        #endregion
    }

8.Manager

  • 配置管理类
public static class ConfigManager
    {
        public static void LoadInitConfig(this IElement element)
        {
            #region //初始化本地配置文件增加处,若有需要的存储,则创建对应Model存入APPIOC.configModelMap容器
               
        }
    }
  • 工具管理类
//单例类
public class MonoSingleton<T> : MonoBehaviour where T :MonoSingleton<T>
{
    #region --单例模式
    private static T _instance;
	public static T Instance
	{
        get
		   {
            if(MonoSingleton<T>._instance == null)
			   MonoSingleton<T>._instance = (T)UnityEngine.Object.FindObjectOfType(typeof(T));
			   return _instance;
		  }
	}
    void Awake()
	 {
		MonoSingleton<T>._instance = (T)this;
        Init();
    }
    #endregion
    protected virtual void Init()
    {
    }
}
public class ExcelManager
    {
        private static ExcelManager _instance;
        public static ExcelManager Instance
        {
            get
            {
                if (_instance == null) _instance = new ExcelManager();
                return _instance;
            }
        }

        public enum ExcelBookIndex
        {
            None = -1,
        }

        //Excel读取
        public static void OnLoadXlsx(string path,System.Action<Dictionary<int, IEnumerable<Row>>> action)//xxx.xlsx
        {
          
            System.Action<bool, string, byte[]> actionAccept = (IsOn, values, bytes) =>
            {
                LogLevel.Debug.Log("IsOn = {0} + ", IsOn);
                if (IsOn) LogLevel.Debug.Log("{0}={1}", "error", values);
                else LoadGuideData(bytes,action);
            };
            LogLevel.Debug.Log("path = {0}", path);
            Net.HttpLoad.Instance.Get(path, actionAccept);
        }
        static void LoadGuideData(byte[] bytes, System.Action<Dictionary<int, IEnumerable<Row>>> action)
        {
            Debug.Log("bytes.Length = " + bytes.Length);
            //bytes就是加载Excel中文件内容流
            if (bytes.Length == 0)
                return;
            //通过插件的WorkBook类转换得到一个列表,这个列表的大小就表示的是Excel中表的个数。
            var book = new WorkBook(bytes);
            if (book.Count == 0)
                return;
            Dictionary<int, IEnumerable<Row>> simulationDic = new Dictionary<int, IEnumerable<Row>>();

            for (int i = 0; i < book.Count; i++)
            {
                simulationDic.Add(i, book[i]);
            }

            if (action != null) action.Invoke(simulationDic);
     
        }
        
        ///文本文档
        public static void OnLoadText(string path,System.Action<Dictionary<int, IEnumerable<Row>>> action)
        {
        }
        
    }
  • 事件监听

https://blog.51cto.com/myselfdream/2956754

  • 日志管理
public enum LogLevel
    {
        Debug,
        Info,
        Warning,
        Exception,
        Error
    }

    public static class LogManager
    {
        public static void Log (this LogLevel level, string templte, params object[] args)
        {
            string msg = args == null || args.Length == 0 ? templte : string.Format(templte, args);
            msg = $"[{level}] Frame={Time.frameCount} Time={Time.time} -- {msg}";
            switch (level)
            {
                case LogLevel.Debug:
                case LogLevel.Info:
                    Debug.Log(msg);
                    break;
                case LogLevel.Warning:
                    Debug.LogWarning(msg);
                    break;
                case LogLevel.Exception:
                    Debug.LogException(new System.Exception(msg));
                    break;
                case LogLevel.Error:
                    Debug.LogError(msg);
                    break;
            }
        }
    }

9.Test测试脚本

public class TestModel
    {
        public string TestName { get; set; }
    }

    public class TestProxy : BaseProxy
    {

        private TestModel testModel;
        public TestProxy()
        {
            testModel = new TestModel();
        }
        public TestProxy(string value) : base(value)
        {
        }

        public void OnUpdate(string value)
        {
            testModel.TestName = value;
        }

        public TestModel getTestModel()
        {
            return testModel;
        }
    }

    public class TestView:BaseView{
         protected void Start(){
               SendNotify(Type.TEST, Tool.EventType.Command_Test_Click_Event, "xxx");
         }
        
          protected override void HandleNotification(EventType eventType, params object[] p_data){
             switch (eventType)
             {
             
                case EventType.View_Test_Click_Event:
                     Debug.Log(p_data[0].ToString());
                     break;
             }
          }
        
    }



    public class TestController :BaseController
    {
        private TestProxy testProxy;
        protected override void Awake()
        {
            testProxy = (TestProxy)this.RetrieveEntity(Type.TEST_PROXY);
        }

        protected override void DoCommand(Tool.EventType eventType, params object[] p_data)
        {
            switch (eventType)
            {
                case Tool.EventType.Command_Test_Click_Event:
                    UnityAction<string> call = p_data[0] as UnityAction<string>;

                    //保存数据
                    testProxy.OnUpdate("run");
                    
                    //返回数据
                    call(testProxy.getTestModel().TestName);
                    SendNotify(Type.TEST_VIEW,Tool.EventType.View_Test_Click_Event, testProxy.getTestModel());

                    break;

            }
        }
    }


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

8Z8YLacFlZ6x