我们在进行热更新的完整案例之前。有必要分析一下uLua的实例代码,了解一下SimpleFramework工作流程,已便于在我们制作实例时更容易理解。
1、LuaState
- using UnityEngine;
- using System.Collections;
- using LuaInterface;
-
- public class HelloWorld : MonoBehaviour {
-
-
- void Start () {
- LuaState l = new LuaState();
- string str = "print('hello world 世界')";
- l.DoString(str);
- }
-
-
- void Update () {
-
- }
- }
这个示例代码中就使用了LuaState。- 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);
- }
-
-
- void 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;
-
-
- void Start()
- {
- LuaState l = new LuaState();
- l.DoString(scriptFile.text);
- }
-
-
- 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 {
-
-
-
-
- public class GlobalGenerator : MonoBehaviour {
-
- void Awake() {
- InitGameMangager();
- }
-
-
-
-
- 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;
-
-
-
-
- public const bool ExampleMode = true;
-
-
-
-
-
-
- public const bool UpdateMode = false;
-
- public const int TimerInterval = 1;
- public const int GameFrameRate = 30;
-
- public const bool UsePbc = true;
- public const bool UseLpeg = true;
- public const bool UsePbLua = true;
- public const bool UseCJson = true;
- public const bool UseSproto = true;
- public const bool LuaEncode = false;
-
- 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;
- public static int SocketPort = 0;
- public static string SocketAddress = string.Empty;
- }
- }
④资源初始化结束
- public void OnResourceInited() {
- LuaManager.Start();
- LuaManager.DoFile("Logic/Network");
- LuaManager.DoFile("Logic/GameManager");
- initialize = true;
-
- NetManager.OnInit();
-
- object[] panels = CallMethod("LuaScriptPanel");
-
- 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");
-
- 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。达到热的目的。
好多啊。写得挺乱的。将就着看吧。