找回密码
 立即注册
查看: 302|回复: 0

xLua热更新

[复制链接]
发表于 2021-8-13 08:47 | 显示全部楼层 |阅读模式
1、作者教程:http://www.gad.qq.com/article/detail/24967
2、GitHub地址:https://github.com/Tencent/xLua       下载之后只需要把Plugins、XLua两个文件夹导入到Unity3D的Assets目录下就可以了。可以按照XLua文件夹下的XLua教程进行学习(如下图)
[img][/img]

[img][/img]



001-利用XLua在控制台输出Hello world
  1. /*
  2. *Title:"XLua学习"项目开发
  3. */
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using UnityEngine;
  7. using XLua;                                //引入xLua命名空间
  8. public class HelloWorld : MonoBehaviour {
  9.     private LuaEnv _luaenv;                //推荐全局唯一
  10.     void Start () {
  11.         _luaenv = new LuaEnv();                //Lua运行环境
  12.         //_luaenv.DoString("print('Hello world')");                        //执行字符串形式的Lua代码
  13.         _luaenv.DoString("CS.UnityEngine.Debug.Log('Hello world')");        //调用C#的Api
  14.     }
  15.        
  16.     private void OnDestroy()
  17.     {
  18.         _luaenv.Dispose();                //释放lua运行环境
  19.     }
  20. }
复制代码
002-读取Lua文件的代码并运行在Resources文件夹下新建一个Lua文件。如:HelloWorld.lua.txt(由于用Resources.Load<AssetText>()加载的是.txt类型的文件)
  1. /*
  2. *Title:"XLua学习"项目开发
  3. *
  4. *Description:
  5. *        用于场景002
  6. *   读取Lua文件来执行Lua代码
  7. *Date:2017
  8. *
  9. *Version:0.1
  10. *
  11. *Modify Recoder:
  12. */
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. using XLua;
  17. public class HelloWorldByFile : MonoBehaviour {
  18.     LuaEnv _luaEnv;
  19.         // Use this for initialization
  20.         void Start () {
  21.         _luaEnv = new LuaEnv();
  22.         //方法1
  23.         //TextAsset ta =  Resources.Load<TextAsset>("HelloWorld.lua");//后缀自动添加.txt,因为是TextAsset类型
  24.         //_luaEnv.DoString(ta.text); //读取文本的字符串并运行
  25.         //方法2 用xLua自带的Loader加载和执行
  26.         _luaEnv.DoString("require 'HelloWorld'"); //HelloWorld相当于HelloWorld.lua.txt,XLua的Loader会自动在Resources目录下加载
  27.     }
  28.     void OnDestroy()
  29.     {
  30.         _luaEnv.Dispose();
  31.     }
  32. }
复制代码
003-自定义Loader,读取其他目录下的Lua文件
  1. /*
  2. *Title:"XLua学习"项目开发
  3. *
  4. *Description:
  5. *        自定义Loader(加载器)
  6. *
  7. *Date:2017
  8. *
  9. *Version:0.1
  10. *
  11. *Modify Recoder:
  12. */
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. using XLua;
  17. using System.IO;
  18. public class DefineLoader : MonoBehaviour {
  19.     private LuaEnv _luaEnv;
  20.         // Use this for initialization
  21.         void Start () {
  22.         _luaEnv = new LuaEnv();
  23.         _luaEnv.AddLoader(MyLoader); //增加一个Loader
  24.         _luaEnv.DoString("require 'DefineLoaderTest'");
  25.     }
  26.        
  27.     //通过require加载一个文件的时候,会访问每一个Loader(先访问自定义的Loader后内置Loader)直到返回的不为空
  28.     private byte[] MyLoader(ref string filePath)
  29.     {
  30.         Debug.Log(filePath);            //这里filePath为DefineLoaderTest
  31.         string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt"; //获取文件所在目录
  32.         //把lua文件里面的字符串转换成字节数组返回,lua文件如果有中文需要把编码改为UTF8
  33.         return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath));      
  34.     }
  35.     void OnDestroy()
  36.     {
  37.         _luaEnv.Dispose();
  38.     }
  39. }
复制代码
004-通过C#调用Lua里面的全局变量、表(方法、变量)CSharpCallLua(lua代码):
  1. intA = 100
  2. floB = 0.52
  3. isRun = true
  4. strName = 'Happy'
  5. person = {
  6. name = 'Jackey',age = 20,3,4.5,true,"stringgg",
  7. eat = function(self,foodName) --self代表当前对象,比C#对应的对象多一个参数
  8.   print("正在吃:"..foodName)
  9. end
  10. }
  11. --[其他方式
  12. function person:eat(foodName) --用:的方式,会自动添加self
  13. print("正在吃:"..foodName)
  14. end
  15. function person.eat(self,foodName) --用.的方式,要自行添加
  16. print("正在吃:"..foodName)
  17. end
  18. --]
  19. function add(a,b) --全局函数
  20. print(a+b)
  21. return a+b,a,b
  22. end
复制代码
C#代码:
  1. /*
  2. *Title:"XLua学习"项目开发
  3. *
  4. *Description:
  5. *        C#访问Lua里面的全局变量
  6. *
  7. *Date:2017
  8. *
  9. *Version:0.1
  10. *
  11. *Modify Recoder:
  12. */
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. using XLua;
  17. using System;
  18. public class CSharpCallLua : MonoBehaviour {
  19.     private LuaEnv _env;
  20.         // Use this for initialization
  21.         void Start () {
  22.         _env = new LuaEnv();
  23.         _env.DoString("require 'CSharpCallLua'");               //加载并执行lua文件
  24.         /*获取基本变量*/
  25.         int intA = _env.Global.Get<int>("intA");                //获取Lua里面Int类型的全局变量
  26.         Debug.Log(intA);
  27.         float floB = _env.Global.Get<float>("floB");            //获取Lua里面float类型的全局变量
  28.         Debug.Log(floB);
  29.         bool isRun = _env.Global.Get<bool>("isRun");            //获取Lua里面bool类型的全局变量
  30.         Debug.Log(isRun);
  31.         string strName = _env.Global.Get<string>("strName");    //获取Lua里面string类型的全局变量
  32.         Debug.Log(strName);
  33.         /*获取table的方式一,通过类Class(Struct)*/
  34.         Person p = _env.Global.Get<Person>("person"); //值拷贝,C#修改数据并不会同步到Lua,Lua修改也不影响C#
  35.         Debug.Log(p.name);
  36.         Debug.Log(p.age);
  37.         /*获取table的方式二,通过接口interface(推荐)*/
  38.         IPerson ip = _env.Global.Get<IPerson>("person"); //传引用,在C#修改会影响Lua里面的变量
  39.         Debug.Log(ip.name);
  40.         Debug.Log(ip.age);
  41.         ip.eat("鸡腿"); //相当于ip.eat(ip,"鸡腿");
  42.         /*获取table的方式三,通过键值对Dictionary、集合List(推荐)*/
  43.         //Dictionary--只能映射table里面有键的元素
  44.         Dictionary<string, object> dict = _env.Global.Get<Dictionary<string, object>>("person");
  45.         foreach (string key in dict.Keys)
  46.         {
  47.             Debug.Log(key + '-' + dict[key]);
  48.         }
  49.         //List--只能映射table里面没有键的元素
  50.         List<object> list = _env.Global.Get<List<object>>("person");
  51.         foreach (object item in list)
  52.         {
  53.             Debug.Log(item);
  54.         }
  55.         /*通过LuaTable类(不推荐,性能比较差)*/
  56.         LuaTable tab = _env.Global.Get<LuaTable>("person");
  57.         print(tab.Get<string>("name"));
  58.         print(tab.Get<int>("age"));
  59.         print(tab.Length);
  60.         /*访问Lua中的全局函数*/
  61.         //方法一:映射到delegate
  62.         Add act1 = _env.Global.Get<Add>("add");//属于命名空间System
  63.         int resa, resb;
  64.         print(act1(1,2,out resa,out resb));
  65.         print(resa);
  66.         print(resb);
  67.         //方法二:映射到LuaFunction (不推荐)
  68.         LuaFunction lf = _env.Global.Get<LuaFunction>("add");
  69.         object[] os = lf.Call(3, 4);
  70.         foreach (object item in os)
  71.         {
  72.             print(item);
  73.         }
  74.     }
  75.     class Person
  76.     {
  77.         public string name;
  78.         public int age;
  79.     }
  80.     [CSharpCallLua] //会为接口增加一些映射使用的代码
  81.     interface IPerson
  82.     {
  83.         string name { get; set; }  //必须添加get set属性
  84.         int age { get; set; }
  85.         void eat(string foodName);
  86.     }
  87.     [CSharpCallLua]
  88.     delegate int Add(int a, int b,out int resa,out int reab); //lua全剧函数里面的第一个返回值会给C#的返回值,第二个返回值会给第一个out,第三个返回值会给第二个out
  89.     void OnDestroy()
  90.     {
  91.         _env.Dispose();
  92.     }
  93. }
复制代码
005-通过lua代码访问C#
LuaCallCSharp(lua代码):
  1. CS.UnityEngine.GameObject("new by lua")                                --创建游戏物体(new对象)
  2. print(CS.UnityEngine.Time.deltaTime)                                --访问C#静态属性
  3. CS.UnityEngine.Time.timeScale = 0.5                                        --设置C#中的属性
  4. local camera = CS.UnityEngine.GameObject.Find('Main Camera')        --用局部变量保存C#中的对象
  5. camera.name = "update by lua"                                                --修改对象名称
  6. local gameObject = CS.UnityEngine.GameObject                --用局部变量进行引用,可以节省性能,以及减少编码量
  7. local light = gameObject.Find('Directional Light')
  8. light.name = 'new light name'
  9. local cameraCam = camera:GetComponent('Camera')    --获取Camera上的组件。推荐使用冒号调用成员函数,如果用点的话,第一个参数需要是当前对象        
  10. gameObject.Destroy(cameraCam)                      --移除这个组件
复制代码
C#代码:
  1. /*
  2. *Title:"XLua学习"项目开发
  3. *
  4. *Description:
  5. *        在lua里访问C#
  6. *
  7. *Date:2017
  8. *
  9. *Version:0.1
  10. *
  11. *Modify Recoder:
  12. */
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using UnityEngine;
  16. using XLua;
  17. public class LuaCallCSharp : MonoBehaviour {
  18.     private LuaEnv _env;
  19.     // Use this for initialization
  20.     void Start()
  21.     {
  22.         _env = new LuaEnv();
  23.         _env.DoString("require 'LuaCallCSharp'");               //加载并执行lua文件
  24.     }
  25.     void OnDestroy()
  26.     {
  27.         _env.Dispose();
  28.     }
  29. }
复制代码
006-lua和C#中参数的对应(ref、out等关键字) Lua调用侧的参数处理规则:C#普通参数算一个输入形参,ref修饰的算一个输入形参,out不算,然后从左往右对应lua调用侧的实参列表。
Lua调用侧的返回值处理规则:C#函数的返回值(如果有的话)算一个返回值,out 算一个返回值,ref算一个返回值,然后从左往右对应lua的多返回值。
007-特性[LuaCallCSharp]和[CSharpCallLua]
Lua获取或者调用C#的时候用[LuaCallCSharp]

在C#获取或者调用Lua的时候用[CSharpCallLua]
在枚举,委托,接口等前面加上[CSharpCallLua]或者[LuaCallCSharp]
008-lua中相当于C#中+=或-=的事件注册
例如testobj里有一个事件:public event Action TestEvent;
增加事件回调:testobj:TestEvent('+',lua_evnet_callback)
移除事件回调:testobj:TestEvent('-',lua_event_callback)

热更新大致流程

更新的东西有两部分:1、资源(Assetbundle) 2、lua代码    这两样东西放在服务器端,客户端连接服务器检查(MD5校验)是否有更新。服务器端使用一个文本文件存放所有Assetbundle和Lua的文件列表和对应的MD5值。客户端下载这个文本文件,客户端拿本地资源的MD5值对比服务器的MD5值,如果不一样则进行更新。这是其中一种方法。





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 08:54 , Processed in 0.091208 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表