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

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

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

1、LuaState

using UnityEngine;
using System.Collections;
using LuaInterface;

public class HelloWorld : MonoBehaviour {

	// Use this for initialization
	void Start () {
        LuaState l = new LuaState();
        string str = "print('hello world 世界')";
        l.DoString(str);
	}
	
	// Update is called once per frame
	void 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 frame
	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;

    // Use this for initialization
    void Start()
    {
        LuaState l = new LuaState();
        l.DoString(scriptFile.text);
    }

    // Update is called once per frame
    void Update()
    {

    }
}

而我们的File文件就是在同目录下的与类同名的txt文件。
Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程_第1张图片

注意,我们这里定义的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组件下的脚本。
Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程_第2张图片

然后。我们要重点分析Lua文件夹下的Lua脚本。
Unity热更新专题(八)uLua示例Demo简析及SimpleFramework工作流程_第3张图片

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。达到热的目的。

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

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

你可能感兴趣的:(unity,lua,热更新,游戏开发)