simpleFramWork的学习记录

版权声明:转载 请说明 https://blog.csdn.net/qq2512667/article/details/83590465

simpleFramWork是在Pure MVC 框架上进行加工而成的,据说前几年都很好用。 

ConstDefin目录是定义 常量的,AppConst 主要是 定义 app的常量信息,app的一些设置, 

 public class AppConst {
        public const bool DebugMode = false;                       //调试模式-用于内部测试
        /// <summary>
        /// 如果想删掉框架自带的例子,那这个例子模式必须要
        /// 关闭,否则会出现一些错误。
        /// </summary>
        public const bool ExampleMode = true;                       //例子模式 

        /// <summary>
        /// 如果开启更新模式,前提必须启动框架自带服务器端。
        /// 否则就需要自己将StreamingAssets里面的所有内容
        /// 复制到自己的Webserver上面,并修改下面的WebUrl。
        /// </summary>
        public const bool UpdateMode = false;                       //更新模式-默认关闭 

        public const int TimerInterval = 1;
        public const int GameFrameRate = 30;                       //游戏帧频

        public const bool UsePbc = true;                           //PBC
        public const bool UseLpeg = true;                          //LPEG
        public const bool UsePbLua = true;                         //Protobuff-lua-gen
        public const bool UseCJson = true;                         //CJson
        public const bool UseSproto = true;                        //Sproto
        public const bool LuaEncode = false;                        //使用LUA编码

        public const string AppName = "SimpleFramework";           //应用程序名称
        public const string AppPrefix = AppName + "_";             //应用程序前缀
        public const string ExtName = ".assetbundle";              //素材扩展名
        public const string AssetDirname = "StreamingAssets";      //素材目录 
        public const string WebUrl = "http://172.17.145.219:7788/";      //测试更新地址

        public static string UserId = string.Empty;                 //用户ID
        public static int SocketPort = 0;                           //Socket服务器端口
        public static string SocketAddress = string.Empty;          //Socket服务器地址
    }

如果 要发布上线的话 要把UpdateMode设置为true.DebugMode设置为false。

 ManagerName定义了所有管理类的常量名

    public class ManagerName {
        public const string Lua = "LuaScriptMgr";
        public const string Game = "GameManager";
        public const string Timer = "TimeManager";
        public const string Music = "MusicManager";
        public const string Panel = "PanelManager";
        public const string Network = "NetworkManager";
        public const string Resource = "ResourceManager";
        public const string Thread = "ThreadManager";
    }

 下面是关于通知的常量名, 

public class NotiConst
{
    public const string START_UP = "StartUp";                       //启动框架
    public const string DISPATCH_MESSAGE = "DispatchMessage";       //派发信息

    public const string UPDATE_MESSAGE = "UpdateMessage";           //更新消息
    public const string UPDATE_EXTRACT = "UpdateExtract";           //更新解包
    public const string UPDATE_DOWNLOAD = "UpdateDownload";         //更新下载
    public const string UPDATE_PROGRESS = "UpdateProgress";         //更新进度
}

只需要在 一个空物体上挂载一个 GlobalGenerator类, 运行 游戏 就会去 根据 是否有GameManager类 去生成。

然后GameManager类负责加载其他的管理类。

保证GameManger类  在Star 之前 加载出来。

namespace SimpleFramework {
    /// <summary>
    /// 全局构造器,每个场景里都有,所以每个场景都会初始化一遍,也会初始化游戏管理器一次
    /// 如果游戏管理器已经存在了,就跳过了,否则创建游戏管理器,来保证游戏里只有一个GameManager
    /// </summary>
    public class GlobalGenerator : MonoBehaviour {

        void Awake() {
            InitGameMangager();
        }

        /// <summary>
        /// 实例化游戏管理器
        /// </summary>
        public void InitGameMangager() {
            string name = "GameManager";
            gameObject.AddComponent<AppView>();

            GameObject manager = GameObject.Find(name);
            if (manager == null) {
                manager = new GameObject(name);
                manager.name = name;

                AppFacade.Instance.StartUp();   //启动游戏
            }
        }
    }
}

GameManager  根据 不同平台 ,设置不同文件目录,先释放下资源再去开启线程去下载读取 ,解包,加载资源,

解包,释放资源完成后,会再开一个协程,会根据是否是更新模式 进行 加载。

如果更新模式就会直接去 初始化 资源

如果是 更新模式,会到服务器上进行匹配更新 加载,再去 初始化 资源, 其他的管理类都是由GameManager去生成的, 最后再去 执行lua的Network  GameManager代码,初始化网络, 然后调用LuaScriptPanel 方法。

这个方法会 放回要加载的名字,只要把需要更新的名字放LuaScriptPanel 里边就 可以让它去u加载 view层了,

View层加载好了之后,再调用 lua 里面 GameManager 里的OnInitOK 函数,

这个函数 先去建立Socket链接,最后再去更新控制层(contorl)。 

控制层里Awake就去 调用Unity里的PanelManager 里的CreatePanel方法

该方法有两个参数,第一个是名字,第二个是回调函数,  回调函数 带一个obj参数, 这个参数可以在lua那边进行操作,

做一些更新操作

     public void CreatePanel(string name, LuaFunction func = null) {
            string assetName = name + "Panel";
            GameObject prefab = ResManager.LoadAsset(name, assetName);
            if (Parent.FindChild(name) != null || prefab == null) {
                return;
            }
            GameObject go = Instantiate(prefab) as GameObject;
            go.name = assetName;
            go.layer = LayerMask.NameToLayer("Default");
            go.transform.SetParent(Parent);
            go.transform.localScale = Vector3.one;
            go.transform.localPosition = Vector3.zero;
            go.AddComponent<LuaBehaviour>();

            if (func != null) func.Call(go);
            Debug.LogWarning("CreatePanel::>> " + name + " " + prefab);
        }

 根据 打包 好的prefab进行 生成   每次生成都会添加一个LuaBehaviour脚本,这个脚本是lua用来和Unity进行互相调用的,

可以条用里面的 添加鼠标点击事件,删除 事件 ,执行lua方法

namespace SimpleFramework.Manager {
    public class GameManager : LuaBehaviour {
        public LuaScriptMgr uluaMgr;
        private List<string> downloadFiles = new List<string>();
      
        /// <summary>
        /// 初始化游戏管理器
        /// </summary>
        void Awake() {
            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        void Init() {
            DontDestroyOnLoad(gameObject);  //防止销毁自己

            CheckExtractResource(); //释放资源
            Screen.sleepTimeout = SleepTimeout.NeverSleep;
            Application.targetFrameRate = AppConst.GameFrameRate;
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void CheckExtractResource() {
            bool isExists = Directory.Exists(Util.DataPath) &&
              Directory.Exists(Util.DataPath + "lua/") && File.Exists(Util.DataPath + "files.txt");
            if (isExists || AppConst.DebugMode) {
                StartCoroutine(OnUpdateResource());
                return;   //文件已经解压过了,自己可添加检查文件列表逻辑
            }
            StartCoroutine(OnExtractResource());    //启动释放协成 
        }

        IEnumerator OnExtractResource() {
            string dataPath = Util.DataPath;  //数据目录
            string resPath = Util.AppContentPath(); //游戏包资源目录

            if (Directory.Exists(dataPath)) Directory.Delete(dataPath, true);
            Directory.CreateDirectory(dataPath);

            string infile = resPath + "files.txt";
            string outfile = dataPath + "files.txt";
            if (File.Exists(outfile)) File.Delete(outfile);

            string message = "正在解包文件:>files.txt";
            Debug.Log(infile);
            Debug.Log(outfile);
            if (Application.platform == RuntimePlatform.Android) {
                WWW www = new WWW(infile);
                yield return www;

                if (www.isDone) {
                    File.WriteAllBytes(outfile, www.bytes);
                }
                yield return 0;
            } else File.Copy(infile, outfile, true);
            yield return new WaitForEndOfFrame();

            //释放所有文件到数据目录
            string[] files = File.ReadAllLines(outfile);
            foreach (var file in files) {
                string[] fs = file.Split('|');
                infile = resPath + fs[0];  //
                outfile = dataPath + fs[0];

                message = "正在解包文件:>" + fs[0];
                Debug.Log("正在解包文件:>" + infile);
                facade.SendNotification(NotiConst.UPDATE_MESSAGE, message);

                string dir = Path.GetDirectoryName(outfile);
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);

                if (Application.platform == RuntimePlatform.Android) {
                    WWW www = new WWW(infile);
                    yield return www;

                    if (www.isDone) {
                        File.WriteAllBytes(outfile, www.bytes);
                    }
                    yield return 0;
                } else {
                    if (File.Exists(outfile)) {
                        File.Delete(outfile);
                    }
                    File.Copy(infile, outfile, true);
                }
                yield return new WaitForEndOfFrame();
            }
            message = "解包完成!!!";
            facade.SendNotification(NotiConst.UPDATE_MESSAGE, message);
            yield return new WaitForSeconds(0.1f);

            message = string.Empty;
            //释放完成,开始启动更新资源
            StartCoroutine(OnUpdateResource());
        }

        /// <summary>
        /// 启动更新下载,这里只是个思路演示,此处可启动线程下载更新
        /// </summary>
        IEnumerator OnUpdateResource() {
            if (!AppConst.UpdateMode) {
                OnResourceInited();
                yield break;
            }
            string dataPath = Util.DataPath;  //数据目录
            string url = AppConst.WebUrl;
            string message = string.Empty;
            string random = DateTime.Now.ToString("yyyymmddhhmmss");
            string listUrl = url + "files.txt?v=" + random;
            Debug.LogWarning("LoadUpdate---->>>" + listUrl);

            WWW www = new WWW(listUrl); yield return www;
            if (www.error != null) {
                OnUpdateFailed(string.Empty);
                yield break;
            }
            if (!Directory.Exists(dataPath)) {
                Directory.CreateDirectory(dataPath);
            }
            File.WriteAllBytes(dataPath + "files.txt", www.bytes);
            string filesText = www.text;
            string[] files = filesText.Split('\n');

            for (int i = 0; i < files.Length; i++) {
                if (string.IsNullOrEmpty(files[i])) continue;
                string[] keyValue = files[i].Split('|');
                string f = keyValue[0];
                string localfile = (dataPath + f).Trim();
                string path = Path.GetDirectoryName(localfile);
                if (!Directory.Exists(path)) {
                    Directory.CreateDirectory(path);
                }
                string fileUrl = url + f + "?v=" + random;
                bool canUpdate = !File.Exists(localfile);
                if (!canUpdate) {
                    string remoteMd5 = keyValue[1].Trim();
                    string localMd5 = Util.md5file(localfile);
                    canUpdate = !remoteMd5.Equals(localMd5);
                    if (canUpdate) File.Delete(localfile);
                }
                if (canUpdate) {   //本地缺少文件
                    Debug.Log(fileUrl);
                    message = "downloading>>" + fileUrl;
                    facade.SendNotification(NotiConst.UPDATE_MESSAGE, message);
                    /*
                    www = new WWW(fileUrl); yield return www;
                    if (www.error != null) {
                        OnUpdateFailed(path);   //
                        yield break;
                    }
                    File.WriteAllBytes(localfile, www.bytes);
                     */
                    //这里都是资源文件,用线程下载
                    BeginDownload(fileUrl, localfile);
                    while (!(IsDownOK(localfile))) { yield return new WaitForEndOfFrame(); }
                }
            }
            yield return new WaitForEndOfFrame();

            message = "更新完成!!";
            facade.SendNotification(NotiConst.UPDATE_MESSAGE, message);

            OnResourceInited();
        }

        void OnUpdateFailed(string file) {
            string message = "更新失败!>" + file;
            facade.SendNotification(NotiConst.UPDATE_MESSAGE, message);
        }

        /// <summary>
        /// 是否下载完成
        /// </summary>
        bool IsDownOK(string file) {
            return downloadFiles.Contains(file);
        }

        /// <summary>
        /// 线程下载
        /// </summary>
        void BeginDownload(string url, string file) {     //线程下载
            object[] param = new object[2] { url, file };

            ThreadEvent ev = new ThreadEvent();
            ev.Key = NotiConst.UPDATE_DOWNLOAD;
            ev.evParams.AddRange(param);
            ThreadManager.AddEvent(ev, OnThreadCompleted);   //线程下载
        }

        /// <summary>
        /// 线程完成
        /// </summary>
        /// <param name="data"></param>
        void OnThreadCompleted(NotiData data) {
            switch (data.evName) {
                case NotiConst.UPDATE_EXTRACT:  //解压一个完成
                //
                break;
                case NotiConst.UPDATE_DOWNLOAD: //下载一个完成
                downloadFiles.Add(data.evParam.ToString());
                break;
            }
        }

        /// <summary>
        /// 资源初始化结束
        /// </summary>
        public void OnResourceInited() {
            LuaManager.Start();
            LuaManager.DoFile("Logic/Network");      //加载游戏
            LuaManager.DoFile("Logic/GameManager");   //加载网络
            initialize = true;  

            NetManager.OnInit();    //初始化网络

            object[] panels = CallMethod("LuaScriptPanel");
            //---------------------Lua面板---------------------------
            foreach (object o in panels) {
                string name = o.ToString().Trim();
                if (string.IsNullOrEmpty(name)) continue;
                name += "Panel";    //添加

                LuaManager.DoFile("View/" + name); //加载View
                Debug.LogWarning("LoadLua---->>>>" + name + ".lua");
            }
            //------------------------------------------------------------
            CallMethod("OnInitOK");   //初始化完成
        }

        void Update() {
            if (LuaManager != null && initialize) {
                LuaManager.Update();
            }
        }

        void LateUpdate() {
            if (LuaManager != null && initialize) {
                LuaManager.LateUpate();
            }
        }

        void FixedUpdate() {
            if (LuaManager != null && initialize) {
                LuaManager.FixedUpdate();
            }
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        void OnDestroy() {
            if (NetManager != null) {
                NetManager.Unload();
            }
            if (LuaManager != null) {
                LuaManager.Destroy();
                LuaManager = null;
            }
            Debug.Log("~GameManager was destroyed");
        }
    }
}

lua里 一般热跟新只要处理3个东西,一个就是Logic里的GmaeManager.lua,一个是View层里的要显示更新的xxxPanel ,另一个就是Controller里的xxxPanel控制层了。

  public void OnResourceInited() {
            LuaManager.Start();
            LuaManager.DoFile("Logic/Network");      //加载游戏
            LuaManager.DoFile("Logic/GameManager");   //加载网络
            initialize = true;  

            NetManager.OnInit();    //初始化网络

            object[] panels = CallMethod("LuaScriptPanel");
            //---------------------Lua面板---------------------------
            foreach (object o in panels) {
                string name = o.ToString().Trim();
                if (string.IsNullOrEmpty(name)) continue;
                name += "Panel";    //添加

                LuaManager.DoFile("View/" + name); //加载View
                Debug.LogWarning("LoadLua---->>>>" + name + ".lua");
            }
            //------------------------------------------------------------
            CallMethod("OnInitOK");   //初始化完成
        }

function GameManager.LuaScriptPanel() 

    return 'Bottom','XXX','XXXX'
end

会被最先执行, 上面的foreach会根据返回的名字 进行加载 View层 里的lua代码,加载结束后,调用OnInitOK

function GameManager.OnInitOK()
    AppConst.SocketPort = 2012;
    AppConst.SocketAddress = "127.0.0.1";
    NetManager:SendConnect()
    
    BottomCtrl.Awake()
    XXXCtrl.Awake()
    XXXXCtrl.Awake()
end

function BottomCtrl.Awake()
    PanelManager:CreatePanel('Bottom',this.OnCreate)
end

--会去调用Unity中的PanelManager里的CreatePanel方法,最后再执行回调函数。

猜你喜欢

转载自blog.csdn.net/qq2512667/article/details/83590465