news 2026/10/9 4:53:15

xLua笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
xLua笔记

部署

拷到Assets去。

Generate Code干了什么

肉眼可见的,在Asset文件夹生成了XLua/Gen文件夹,里面有一些脚本。然后对加了[CSharpCallLua]的变量寻找引用,发现它被XLua/Gen/DelegatesGensBridge引用了。也可以在这里查哪些类型加了[CSharpCallLua]。

public override Delegate GetDelegateByType(Type type) { if (type == typeof(NoParamNoReturn)) { return new NoParamNoReturn(__Gen_Delegate_Imp0); } if (type == typeof(DelegateLua)) { return new DelegateLua(__Gen_Delegate_Imp0); } if (type == typeof(MyActionIntInt)) { return new MyActionIntInt(__Gen_Delegate_Imp1); } return null; }

没加[CSharpCallLua]或没生成代码的变量被使用就报错:

xLua管理器脚本

  1. 新建LuaEnv类;
  2. 执行luaEnv.AddLoader()。输入是一个返回byte[]的函数,这个函数把一个lua脚本读取出全部字节返回。当luaEnv.DoString()执行require一个lua脚本时,它调用这个函数,把需要的lua脚本名传入,这个函数把脚本里的代码读出。这个函数里可以自定义寻找lua脚本的路径(默认从Resources找),也不一定从文件夹里找,也可以从AB包找,只要返回lua脚本的字节就行。
  3. 执行luaEnv.DoString(luaCode);执行单句lua代码,一般是"require('xxx')"执行一个lua脚本。require()脚本时需要把lua脚本加.txt后缀,因为Resources.Load不支持加载lua格式文件。
  4. 要使用Lua里的任何变量,通过luaEnv.Global获取;
using XLua; public class XLuaManager:MySingleton<XLuaManager>{ public string luaPath{ get{ return string.Concat(Application.dataPath,"/LuaScripts/"); } } const string luaABName="lua"; luaEnv; public void Init(){ if(luaEnv!=null){ return; } luaEnv=new LuaEnv(); luaEnv.AddLoader(ProjectLoader); luaEnv.AddLoader(ProjectLoaderAB); } byte[] ProjectLoader(ref string filePath){ string path=string.Concat(luaPath,filePath,".lua"); if(File.Exists(path)){ return File.ReadAllBytes(path); } else{ #if UNITY_EDITOR Debug.Log(path+"找不到"); #endif return null; } } byte[] ProjectLoaderAB(ref string filePath){ #if UNITY_EDITOR Debug.Log("在AB包里找"+filePath); #endif TextAsset luaScript=MyABManager.Instance.LoadRes<TextAsset>(luaABName,filePath+".lua"); if(luaScript!=null){ return luaScript.bytes; } else{ #if UNITY_EDITOR Debug.Log(filePath+"在AB包里找不到"+filePath); #endif return null; } } public void FreeEnv(){ luaEnv.Dispose(); luaEnv=null; } public void DoLuaFile(string fileName){ string str=string.Format("require('{0}')",fileName); RunLua(str); } public object[] RunLua(string code){ return luaEnv.DoString(code); } public LuaTable Global{ get{ return luaEnv.Global; } } }

要获取table,在C#里定义一个有table同名成员的结构体或类。要获取函数,在C#里定义一个参数列表和返回类型相同的委托。在Global.Get<xxx>里填自定义的类型。

XLuaManager.Instance.Global.Get<xxx>("yyy");

Lua调用C#

静态方法用.,实例的方法用:

local obj=CS.UnityEngine.GameObject.Find("xxx") obj.transform:FindChild(0)

C#里一大堆方便语法不能用,需要用相应的函数。

没有泛型<>,要用传入type的重载;

C# new语法在xlua用命名空间.类(参数)

创建数组

CS.System.Array.CreateInstance(typeof(CS.System.Int32),长度);

创建列表

先得到List,再传入类型参数

local List_String=CS.System.Collections.Generic.List(CS.System.String) local list=List_String()

创建字典用

local Dic1=CS.System.Collections.Generic.Dictionary(CS.System.String,CS.xxx) local dic1=Dic1()

读取C#的字典元素可以用[],读取Lua创建的字典元素用

dic:get_Item(xxx)

写入字典元素用

dic:set_Item(xxx)

区别就是数组用CS.System一大串就直接创建了,List和Dictionary用CS.System一大串先得到类型xxx,再用xxx()创建实例。

二维数组读取元素需要用GetValue(x,y);

对象==null需要用.Equals(nil);

+=需要用xxx=xxx+yyy;

out和ref参数是多返回值;

委托第一次要用=赋值,后面加函数;

事件用myEvent("+",xxx)加函数;

总结:没有new,部分类型(Lua创建的字典、二维数组)没有[],没有+=,没有++,没有<>。需要掌握相应的替代语法。

LuaBehavior干了什么

LuaBehavior可能是例子里最重要的一个脚本。

Awake里新建一个表,记为成员scriptEnv,又新建一个表meta,设为scriptEnv的元表。meta的__index设为全局表。scriptEnv设置成员self为自己这个C#对象。

然后为scriptEnv注入GameObject成员。

然后执行对应的lua脚本,在scriptEnv表里。

然后获得lua表的各生命周期函数,有则在C#生命周期函数里执行。

它新建了一个表,把luaScript里的代码限制在一个lua表里执行。那么lua那边就不用新建表,把成员都写在里面,然后让LuaBehavior去找这个表了。

热补丁

  1. Project Settings的Scripting Define Symbol加上HOTFIX_ENABLE;
  2. 执行"XLua/Hotfix Inject In Editor";
  3. 需要补丁的类加[Hotfix];
  4. lua脚本写xlua.hotfix(类,方法,lua函数);
  5. xlua.private_accessible(类)允许访问私有成员;
  6. luaEnv.Dispose()前lua执行xlua.hotfix(类,方法,nil)

xLua热补丁报错在Lua里找不到xLua变量

原因:在lua脚本里把xlua打成了xLua。

热补丁协程报错This type must add to CSharpCallLua: System.Collections.IEnumerator

Lua和C#交互底层(用我自己的话说)

lua访问C#的对象时,在lua环境都是用一个userdata,它有一个ID,还有元表,用这个ID去C#环境的一个字典(应该是Dictionary<int,object>类型)得到对象。lua通过gameObject1.transform第一次访问这个transform时,字典里没有这个transform,先通过lua环境代表gameObject1的userdata的id去查字典得到C#的gameObject1,点出它的transform,把这个transform加一个ID添加进字典,然后lua环境生成ID是它的userdata。

如果后续不再用这个transform,这个userdata和它在C#字典的条目都会被释放掉。

问题

'AppDomain' does not contain a definition for 'DefineDynamicAssembly':找不到AppDomain下的DefineDynamicAssembly方法

解决方法:把报错扔给百度查,得到下面的文章。

C#反射中使用到Emit时,发现AppDomain.CurrentDomain.DefineDynamicAssembly()方法并不存在 - 名字已被使用N次 - 博客园 (cnblogs.com)

里面让把AppDomain.CurrentDomain替换成AssemblyBuilder,照做,解决。原因应该是微软把这个方法移动地方了,且改成了静态方法。

百度查DefineDynamicAssembly,能看到官方文档里有两个类里出现这个方法。

AppDomain的适用版本:

AssemblyBuilder的适用版本:

创建运行环境报错xlua assembly:<unknown assembly> type:<unknown type> member:(null)

原因:没把Plugin文件夹拷过来

Lua里调用C#的委托报错InvalidOperationException: not a generic method definition

C#代码

Lua代码

报错:not a generic method definition

C#里添加并执行委托没错,Lua直接执行Func1()也没错。如果改成一个根本不存在的成员:

报错会不一样:

说明xLua是能找到这个成员的,但是不允许把函数赋给它。打印MyStaticDelegate,是nil,类型也是nil。给它赋一个整数,不报错,打印,还是nil,执行,报错说不能执行nil。

这是C#里定义的一个类:

在lua里遍历它:

结果:

发现它含有NPC里的静态成员,但是静态字符串name和静态委托MyStaticDelegate不见了,但是有一个UnderlyingSystemType,类型是NPC。

然后试图把NPC实例化一个对象,对这个对象遍历:

得到报错:ob是NPC类型,不是table,不能遍历:

遍历了一下CS,以为会有很多东西:

结果:

连我定义的NPC类也没有。

解决方法:在C#定义的无参无返回值委托、传入自身的委托前面加[CSharpCallLua],不管是在Lua使用C#委托,还是C#委托接收Lua函数,都要加。有参且不为表自身的委托(如传入字符串、整数)可以不加。

不要用print(CS.成员)验证一个成员存不存在,就算不存在,也会添加这个成员,类型是table。下图:print CS里一个根本不存在的成员,发现它有值,而且遍历显示这个成员已经被创建出来了:

Lua添加按钮回调报错:LuaException: c# exception:System.InvalidOperationException: not a generic method definition

原因:AddListener的输入类型UnityAction没加CSharpCallLua特性!

解决方法:加上下面一段代码,xLua重新生成。

public static class CSLuaTypes{//记录C#和Lua会调用对方的类型 [CSharpCallLua] public static List<Type> cSharpCallLuaTypes=new List<Type>(){ typeof(UnityAction), typeof(UnityAction<float>), typeof(UnityAction<bool>) }; [LuaCallCSharp] public static List<Type> LuaCallCSharpTypes=new List<Type>(){ }; }

生成代码后报错The type 'XXX' may not be used as a type argument

把出错代码全注释了。为了防止下次生成再这样,不要清除代码,把Gen文件夹移出项目。

AB包打包报错XLua\Gen\UnityEngine_LightWrap.cs:error CS1061:'Light' does not contain a definition for shadowAngle

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/9 4:52:42

网盘直链解析快速上手:八大网盘免费拿到真实下载地址

网盘直链解析快速上手&#xff1a;八大网盘免费拿到真实下载地址 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 &#xff0c;支持 百度网盘 / 阿里云盘 / 中国移动云盘 / 天翼云…

作者头像 李华
网站建设 2026/10/9 4:50:56

sbox InteropGen 的 .def 绑定描述文件格式全解析

【免费下载链接】sbox-public s&box is a modern game engine, built on Valves Source 2 and the latest .NET technology, it provides a modern intuitive editor for creating games 项目地址&#xff1a; https://gitcode.com/gh_mirrors/sbo/sbox-public 点击查看 免…

作者头像 李华
网站建设 2026/10/9 4:46:10

JSP驾校管理系统源码详解:从环境搭建到预约开发

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/9 4:46:08

Android Studio五子棋开发:自定义View、触摸事件与人机对战完整指南

简介&#xff1a;Android Studio五子棋项目是一份面向Android初学者的完整源码与工程文件&#xff0c;涵盖从界面布局到游戏规则实现的典型开发链路。项目基于Android Studio IDE构建&#xff0c;包含MainActivity、棋盘逻辑、胜负判断与落子校验等核心模块&#xff0c;适合用于…

作者头像 李华