【技术点】Unity的热更新sLua

发表于2016-10-01
评论0 6.6k浏览
需求环境
  在【解决方案系列】中,我们需要考虑到我们能预估的项目问题,在现有的工作习惯中,赶工期是常见的一种现象,而这种现象的后果,就导致了测试的不完全,线上项目bug的频繁出现。
  为了对线上的BUG进行Fix,我们就需要一定的技术手段,甚至通过游戏初期架构去解决这个影响游戏质量的重要问题。
  这是一篇【技术点】文章,同时吸取了之前一篇的文章,我们就不进行复杂的项目架构,只对技术点进行简单的介绍,其他有关但又与主题无关的内容,我们就浅浅跳过。

逻辑热更新
  在以往的Unity版本中,有多种热更新的方案留存于世,从之前的uLua到C# Ligh,再到后来的Tolua,Slua等等,甚至早起的PlayMaker都能解决逻辑热更新的问题。
  而本篇,基于作者项目在使用的情况,我们将会使用Slua作为我们【解决方案】系列的逻辑热更新方案。
  而多种热更新语言的比较,大家可自行谷歌,也可通过该篇进行一定了解:http://blog.csdn.net/langresser_king/article/details/45112519

插件信息
1、插件网站:http://www.slua.net/
2、插件GitHub:https://github.com/pangweiwei/slua/wiki
  在插件的GitHub中,有中文的帮助,我们只用简单的将插件导入到工程中,就可以开始使用了。为了让调试变得方便,我们需要进行一些小改动。

使用方法
  在查看此节前,确保你已经查看了该插件的基础信息。
sLua加载:
  在原生下载的sLua插件中,作者把Lua文件放在Resource目录中,并去掉了后缀名,在我使用的过程中,没有后缀名的文件无法被Vs有效识别,为了方便的调试,我们就需要进行一些准备工作。
  sLua已经考虑到了这种情况,所以他提供了方便的接口,供给我们进行更改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
///
 
 
    /// 从resouce目录加载Lua脚本,并初始化
    ///
    ///Resouce下的目录
    ///是否强制读取
    public SLua.LuaTable RsLoad(string _rsPath)
    {
        Log("加载:" + _rsPath);
 
        if (mluasvr.inited == false)
        {
            Log("还未初始化,等待初始化后加载:" + _rsPath);
            waitLoadLua= _rsPath;
            return null;
        }
 
        if (luaDict.ContainsKey(_rsPath))
            return luaDict[_rsPath];
 
        //设置执行脚本
        //LuaState ls_state = new LuaState();
 
        //设置脚本启动代理
        LuaState.loaderDelegate= ((string fn) =>
        {
            //获取Lua文件执行目录
            string file_path = Directory.GetCurrentDirectory() + "/Assets/Resources/" + fn;
 
            file_path= file_path.Replace('/', '\');
            file_path= file_path.Replace('.', '\');
 
 
            Log("准备加载脚本:" + file_path);
 
            var file = File.ReadAllBytes(file_path + ".lua");
 
            if (file == null)
                LogError("加载Lua脚本失败,不存在的Lua脚本");
            else
                Log("加载脚本成功.文件大小:" + file.Length);
 
            return file;
        });
 
        //通过刚才设置的代理方法加载,就会从Res目录下读取带.lua的文件了
        var self = (LuaTable)mluasvr.start(_rsPath);
        if (self != null)
        {
            luaDict.Add(_rsPath, self);
            return self;
        }
 
        LogError("脚本初始化错误,脚本:" + _rsPath);
 
        return null;
    }

  有了上面这一段代码后,我们就可以直接从Resource目录下调用带有.lua后缀名的lua文件。

热调试:
  在我们调试Lua文件时,我们不希望频繁重启客户端,因为Unity编译一次需要很久时间,所以如果可以动态的将已经加载好的Lua文件重新加载,我们就进行快速Lua逻辑调试。
  在上面的代码中,为了确保效率,我们将Lua对象放到了LuaDict中,避免了重复调用,而函数本身是可以重新加载Lua文件的,所以我们只需要把Lua文件从Dict中清除就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
///
 
 
  /// 移除脚本,移除后,会重新加载,这样就可以热更新了。
  /// 平时用缓存里的,性能就没那么差了
  ///
  public void UnstallLuaScripts()
  {
      luaDict.Clear();
  }
 
  ///
  /// 卸载指定脚本
  ///
  ///脚本目录+名字
  public void UnstallLuaScript(string _name)
  {
      if (luaDict.ContainsKey(_name))
          luaDict.Remove(_name);
  }

 该有一些其他初始化的过程,不过都是些逻辑问题,大家可以在DJLuaManager.cs文件中插件相关代码。

测试:
  有了上面简单的加载代码后,我们就可以测试Lua脚本了。在工程的10-1sLuaTest 场景中,我们能找到测试工具TestTool,上面挂在了脚本Behavior3JSTest.cs ,这是我自己用来测试Lua代码的小脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using UnityEngine;
using System.Collections;
 
public class Behavior3JSTest : MonoBehaviour
{
 
    public bool 加载 = true;
    public string loadFunction;
    //"/DJLua/Behavior3Js/main"
    public bool 运行一次 = false;
    public string runFunction;
    //testbt
    public bool 循环执行 = false;
    public string loopFunction;
 
    void Update()
    {
        if (加载 == true)
        {
            加载 = false;
            DoSomething();
        }
 
        if (运行一次 == true)
        {
            runOnce();
            运行一次 = false;
        }
 
        if (循环执行 == true)
        {
            runex();
        }
    }
 
    void DoSomething()
    {
        DJLuaManager.GetInstance().UnstallLuaScripts();
        DJLuaManager.GetInstance().RsLoad(loadFunction);
 
    }
 
    void runOnce()
    {
        DJLuaManager.GetInstance().ExecuteFunc(loadFunction, runFunction);
    }
 
    void runex()
    {
        DJLuaManager.GetInstance().ExecuteFunc(loadFunction, loopFunction);
    }
}

  每次加载的时候会卸载之前的脚本,而每次点击运行一次的时候,就会执行指定的函数。而在界面上,则有方便调试的窗口供给我们输入内容。


  当我们输入了正确的信息后,就可以得到反馈的结果。


  而当我们修改了Lua代码后,只用点击加载,不用重启客户端,就可以看到执行的效果。
  当然,还有一个小小的Lua代码,文件名字叫sLuaTest.lua:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--
-- User: John
-- Date: 2016年10月1日 星期六 农历九月初一
-- Des: lua的测试脚本
 
local mClass = { }
 
function main()
    Debug.Log("我被加载了");
    return mClass
end
 
-- 节点被单击
function mClass:testClick()
    Debug.Log("我被点击了")
end

结束语
  这就是sLua在Unity3d中的快速搭建,因为是【技术点】文章,稍微介绍下,相信大家通过文档能快速搭建出自己的项目。
  而对于Lua的熟悉,可以使用《Lua 语言 15 分钟快速入门》来解决前期问题。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引