Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程

来源:互联网 发布:游族网络2018校园招聘 编辑:程序博客网 时间:2024/06/07 00:19

Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程

我们在进行热更新的完整案例之前。有必要分析一下uLua的实例代码,了解一下SimpleFramework工作流程,在我们制作实例时便于理解。

1、LuaState

using UnityEngine;using System.Collections;using LuaInterface;public class HelloWorld : MonoBehaviour {// Use this for initializationvoid Start () {        LuaState l = new LuaState();        string str = "print('hello world 世界')";        l.DoString(str);}// Update is called once per framevoid Update () {}}
这个示例代码中就使用了LuaState。

2、LuaScriptMgr

using UnityEngine;using System.Collections;using LuaInterface;public class CreateGameObject02 : MonoBehaviour {    private string script = @"            luanet.load_assembly('UnityEngine')            GameObject = UnityEngine.GameObject            ParticleSystem = UnityEngine.ParticleSystem            local newGameObj = GameObject('NewObj')            newGameObj:AddComponent(ParticleSystem.GetClassType())        ";//非反射调用void Start () {        LuaScriptMgr lua = new LuaScriptMgr();        lua.Start();        lua.DoString(script);}// Update is called once per framevoid Update () {}}

这个示例代码中就使用了LuaScriptMgr。

上面的两个示例中,要注意一下的代码:
private string script = @"            luanet.load_assembly('UnityEngine')            GameObject = UnityEngine.GameObject            ParticleSystem = UnityEngine.ParticleSystem            local newGameObj = GameObject('NewObj')            newGameObj:AddComponent(ParticleSystem.GetClassType())        ";

大概工作流程就是先加载UnityEngine,然后创建一个GameObject变量,再调用AddComponent方法。其实就和Unity里面使用的差不多。很简单。不多说。

3、在Unity中访问Lua中的变量

using UnityEngine;using System.Collections;using LuaInterface;public class AccessingLuaVariables01 : MonoBehaviour {    private string script = @"            luanet.load_assembly('UnityEngine')            GameObject = luanet.import_type('UnityEngine.GameObject')            ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')            particles = {}            for i = 1, Objs2Spawn, 1 do                local newGameObj = GameObject('NewObj')            local ps = newGameObj:AddComponent(luanet.ctype(ParticleSystem))                ps:Stop()                table.insert(particles, ps)            end            var2read = 42        ";void Start () {        LuaState l = new LuaState();        l["Objs2Spawn"] = 5;            //就是这里        l.DoString(script);        print("Read from lua: " + l["var2read"].ToString());        LuaTable particles = (LuaTable)l["particles"];        foreach( ParticleSystem ps in particles.Values )        {            ps.Play();        }}void Update () {}}

4、执行Lua脚本文件,调用Lua方法,在Lua中使用协程

using UnityEngine;using System.Collections;using LuaInterface;public class ScriptsFromFile_01 : MonoBehaviour{    public TextAsset scriptFile;    // Use this for initialization    void Start()    {        LuaState l = new LuaState();        l.DoString(scriptFile.text);    }    // Update is called once per frame    void Update()    {    }}

而我们的File文件就是在同目录下的与类同名的txt文件。


注意,我们这里定义的File文件,是TextAsset类型。
public TextAsset scriptFile;

接下来就是调用Lua的方法。也很简单。

using UnityEngine;using System.Collections;using LuaInterface;public class CallLuaFunction_01 : MonoBehaviour {    private string script = @"            function luaFunc(message)                print(message)                return 42            end        ";void Start () {        LuaState l = new LuaState();        l.DoString(script);        LuaFunction f = l.GetFunction("luaFunc");        object[] r = f.Call("I called a lua function!");        print(r[0]);}void Update () {}}

协程的使用:

using UnityEngine;using System.Collections;using LuaInterface;public class LuaCoroutines : MonoBehaviour {    private string script = @"                                               function fib(n)                local a, b = 0, 1                while n > 0 do                    a, b = b, a + b                    n = n - 1                end                return a            end            function CoFunc()                print('Coroutine started')                local i = 0                for i = 0, 10, 1 do                    print(fib(i))                                        coroutine.wait(1)                end                print('Coroutine ended')            end            function myFunc()                coroutine.start(CoFunc)            end        ";    private LuaScriptMgr lua = null;void Awake ()     {        lua  = new LuaScriptMgr();        lua.Start();        lua.DoString(script);                LuaFunction f = lua.GetLuaFunction("myFunc");        f.Call();        f.Release();}void Update ()     {                lua.Update();}    void LateUpdate()    {        lua.LateUpate();    }    void FixedUpdate()    {        lua.FixedUpdate();    }}

好了。uLua的示例代码我们就分析到这里了。接下来的可以自己琢磨,对于我们的案例来说已经够了。下面我们来分析一下自带热更新的案例的工作流程。也就是我们的SimpleFramework的工作流程。


5、框架启动GlobalGenerator,生成appview和gamemanager

在这里我们首先要看一下框架的目录。
整个SimpleFramework采用的是PureMVC的框架。看下图。


GlobalGenerator.cs
using UnityEngine;using System.Collections;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();   //启动游戏            }        }    }}

这段代码就是我们热更新的入口。
这里GlobalGenerator的任务就完成了。
appview和gamemanager都是框架相关的东西。这里我们就只对GameManager进行分析。

6、GameManager中对资源的更新处理及处理Lua的View的加载和初始化

GameManager的功能就如这个标题所说。
代码中也有详细注释。
我们就不贴代码了。

我们关注一下GameManager组件下的脚本。


然后。我们要重点分析Lua文件夹下的Lua脚本。


GameManager.cs:

①加载所有Lua脚本


public LuaScriptMgr uluaMgr;        private List<string> downloadFiles = new List<string>();

②初始化

void Init() {            DontDestroyOnLoad(gameObject);  //防止销毁自己            CheckExtractResource(); //释放资源            Screen.sleepTimeout = SleepTimeout.NeverSleep;            Application.targetFrameRate = AppConst.GameFrameRate;        }
我们可以看看AppConst.cs文件,里面主要是一些配置。

using UnityEngine;using System;using System.Collections;using System.Collections.Generic;namespace SimpleFramework {    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://localhost:6688/";      //测试更新地址        public static string UserId = string.Empty;                 //用户ID        public static int SocketPort = 0;                           //Socket服务器端口        public static string SocketAddress = string.Empty;          //Socket服务器地址    }}

④资源初始化结束

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);                Debug.LogWarning("LoadLua---->>>>" + name + ".lua");            }            //------------------------------------------------------------            CallMethod("OnInitOK");   //初始化完成        }

我们看到熟悉的字眼了。
LuaManager.DoFile("Logic/Network");      //加载游戏            LuaManager.DoFile("Logic/GameManager");   //加载网络

这正是我们Lua文件夹Logic文件夹下的脚本,我们来看看这两个脚本。

Network.lua文件主要是网络相关的文件,我们就不分析了,重点看GameManager.lua。它相当于Lua脚本文件的起点。

require "3rd/pblua/login_pb"require "3rd/pbc/protobuf"local lpeg = require "lpeg"local json = require "cjson"local util = require "3rd/cjson.util"local sproto = require "3rd/sproto/sproto"local core = require "sproto.core"local print_r = require "3rd/sproto/print_r"require "Logic/luaclass"require "Logic/CtrlManager"require "Common/functions"require "Controller/PromptCtrl"

文件相关。不解释。

GameManager = {};local this = GameManager;

单例。你懂的。

function GameManager.LuaScriptPanel()return 'Prompt', 'Message';end

返回我们的UI相关类。

我们结合两个文件一起看。

function GameManager.LuaScriptPanel()return 'Prompt', 'Message';end

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);                Debug.LogWarning("LoadLua---->>>>" + name + ".lua");            }

这两段代码是相关联的。
local transform;local gameObject;PromptPanel = {};local this = PromptPanel;--启动事件--function PromptPanel.Awake(obj)gameObject = obj;transform = obj.transform;this.InitPanel();warn("Awake lua--->>"..gameObject.name);end--初始化面板--function PromptPanel.InitPanel()this.btnOpen = transform:FindChild("Open").gameObject;this.gridParent = transform:FindChild('ScrollView/Grid');end--单击事件--function PromptPanel.OnDestroy()warn("OnDestroy---->>>");end

local transform;local gameObject;MessagePanel = {};local this = MessagePanel;--启动事件--function MessagePanel.Awake(obj)gameObject = obj;transform = obj.transform;this.InitPanel();warn("Awake lua--->>"..gameObject.name);end--初始化面板--function MessagePanel.InitPanel()this.btnClose = transform:FindChild("Button").gameObject;end--单击事件--function MessagePanel.OnDestroy()warn("OnDestroy---->>>");end

这两段代码得以执行。初始化UI界面。

这里有个疑问?初始化界面是怎么得以实现的?
其实也很简单,结合工程来看:
这是初始化后得到的界面。


其实我们早就把界面打包成Prefab了。


对,就是这么来的,每个prefab对应生成AssetBundle。达到热的目的。

好多啊。写得挺乱的。将就着看吧。

===================================================================================
结束。

1 0