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  | 
