UH2S2L18——特殊问题
UH2S2L18——特殊问题
二维数组遍历
先在C#脚本内声明如下内容
1 | public class Lesson8 |
获取长度
二维数组的获取某个列或者行的长度是通过GetLength()
来获取的,Lua中也可以调用该方法
1 | local obj = CS.Lesson8() |
获取元素
虽然在C#中二维数组可以使用[数字, 数字]
来获取某行某列的值
但是Lua中不支持这种语法,且 [数字][数字]
也是不可行的,都会报错
不过,除了通过索引器去获取值,C#还提供了GetValue
这个成员方法,可以通过它来获取元素
1 | print(obj.array:GetValue(0, 0)) |
null和nil比较
C#中的null
和Lua中的nil
不能直接比较,因此有三种方法来解决这个问题
- Equals判空:
对象.Equals(nil)
,前提是对象是C#中的object
而非Lua中的对象,否则会报错 - 全局方法判空:自行声明一个
IsNull
方法,先判断是不是nil
在用对象.Equals(nil)
判断 - 拓展方法判空:在C#中拓展一个判空方法,让Lua调用
Equals判空
假设一个情景,我们需要往场景对象上添加一个脚本,如果存在就不加,如果不存在再加
1 | -- 往场景对象上添加一个脚本 如果存在就不加 如果不存在再加 |
然而,对象上并没有添加组件,检查输出也发现并没有进入判空逻辑
这是因为,Lua中的****nil
不等同于C#的****null
,他们两个不能直接使用 ==
来比较
因此我们需要使用C#的****object
提供的****Equals
方法,传入****nil
,使用这种方法来判空
1 | local obj = GameObject("测试加脚本") |
全局方法判空
但是以上的方法也有问题,如果rig
是Lua里的对象而非C#的对象,则很有可能报错,因为不能调用object
提供的Equals
因此,我们可以写一个全局的判空函数,写到Main脚本内,这样即可到处调用该函数用于判空
1 | print("主Lua脚本启动") |
1 | local obj = GameObject("测试加脚本") |
C#脚本拓展方法判空
还有第三种方法,就是在为Unity的Object
拓展一个判空方法
1 | //为Object 拓展一个方法 |
1 | local obj = GameObject("测试加脚本") |
让系统类型和Lua能互相访问
解决方法就是:
声明静态类,再声明静态Type
类型列表,为其添加 [CSharpCallLua]
或者 [LuaCallCSharp]
,将想要生成代码的类的类型添加到列表即可
自己声明的委托或者接口要映射Lua中的方法或者表,需要添加[CSharpCallLua]
在类里声明拓展方法时,装载拓展方法的类需要添加[LuaCallCSharp]
,当然所有会被Lua调用的自定义类都可以添加该特性,可以优化性能
但是系统类和第三方库代码(例如UGUI)时,我们是无法添加这两个特性的,这可能会导致出现问题
假设我们要通过Lua代码来监听UI界面上一个Slider的改变
1 | GameObject = CS.UnityEngine.GameObject |
以上代码直接运行就会报错,因为xLua会要求我们对UnityAction
添加[CSharpCallLua]
特性(Unity自己声明的委托)
但是这是Unity内部的代码,我们无法为其添加特性
我们需要去声明一个静态类,在里面声明类型为Type
的列表,添加 [CSharpCallLua]
特性
声明时直接添加要调用Lua方法或者表的类型(如果有泛型参数则必须要提前填入),之后执行XLua的Generate Code
这样XLua就会根据我们列表里添加的类型,自动生成对应代码,而不需要我们手动添加特性
本例我们需要监听silder的值,因此会用到UnityAction<float>
这个委托,在声明时添加
1 | public static class Lesson10 |
此时拖动silder,逻辑正常执行
可见,这是一种非常好用的方法,它不仅可以为我们不能修改代码的系统类和第三方库类,
以前自己声明的委托和接口也可以获取其类型然后添加到列表内,这样我们不必再自行添加特性
1 | public static class Lesson10 |