Unity Lua 之 在 Unity 中 Lua访问C# 的new 对象,访问静态属性、方法,访问成员属性、方法

Unity Lua 之 在 Unity 中 Lua访问C# 的new 对象,访问静态属性、方法,访问成员属性、方法

 

目录

Unity Lua 之 在 Unity 中 Lua访问C# 的new 对象,访问静态属性、方法,访问成员属性、方法

一、简单介绍

二、Lua访问C# 官网相关知识

三、注意事项

四、实现步骤

五、关键代码


 

一、简单介绍

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。

xLua为Unity、 .Net、 Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用。

xLua在功能、性能、易用性都有不少突破,这几方面分别最具代表性的是:

  • 可以运行时把C#实现(方法,操作符,属性,事件等等)替换成lua实现;
  • 出色的GC优化,自定义struct,枚举在Lua和C#间传递无C# gc alloc;
  • 编辑器下无需生成代码,开发更轻量;

在Unity中使用xlua 的重要一个原因就是热更新,我们本着这个歌目的开始我们的学习。
 

二、Lua访问C# 官网相关知识

new C#对象

你在C#这样new一个对象:

var newGameObj = new UnityEngine.GameObject();

对应到Lua是这样:

local newGameObj = CS.UnityEngine.GameObject()

基本类似,除了:

1. lua里头没有new关键字;
2. 所有C#相关的都放到CS下,包括构造函数,静态成员属性、方法;

如果有多个构造函数呢?放心,xlua支持重载,比如你要调用GameObject的带一个string参数的构造函数,这么写:

local newGameObj2 = CS.UnityEngine.GameObject('helloworld')

访问C#静态属性,方法

读静态属性

CS.UnityEngine.Time.deltaTime

写静态属性

CS.UnityEngine.Time.timeScale = 0.5

调用静态方法

CS.UnityEngine.GameObject.Find('helloworld')

小技巧:如果需要经常访问的类,可以先用局部变量引用后访问,除了减少敲代码的时间,还能提高性能:

local GameObject = CS.UnityEngine.GameObject
GameObject.Find('helloworld')

访问C#成员属性,方法

读成员属性

testobj.DMF

写成员属性

testobj.DMF = 1024

调用成员方法

注意:调用成员方法,第一个参数需要传该对象,建议用冒号语法糖,如下

testobj:DMFunc()

父类属性,方法

xlua支持(通过派生类)访问基类的静态属性,静态方法,(通过派生类实例)访问基类的成员属性,成员方法

参数的输入输出属性(out,ref)

Lua调用测的参数处理规则:C#的普通参数算一个输入形参,ref修饰的算一个输入形参,out不算,然后从左往右对应lua 调用测的实参列表;

Lua调用测的返回值处理规则:C#函数的返回值(如果有的话)算一个返回值,out算一个返回值,ref算一个返回值,然后从左往右对应lua的多返回值。

重载方法

直接通过不同的参数类型进行重载函数的访问,例如:

testobj:TestFunc(100)
testobj:TestFunc('hello')

将分别访问整数参数的TestFunc和字符串参数的TestFunc。

注意:xlua只一定程度上支持重载函数的调用,因为lua的类型远远不如C#丰富,存在一对多的情况,比如C#的int,float,double都对应于lua的number,上面的例子中TestFunc如果有这些重载参数,第一行将无法区分开来,只能调用到其中一个(生成代码中排前面的那个)

操作符

支持的操作符有:+,-,*,/,==,一元-,<,<=, %,[]

参数带默认值的方法

和C#调用有默认值参数的函数一样,如果所给的实参少于形参,则会用默认值补上。

可变参数方法

对于C#的如下方法:

void VariableParamsFunc(int a, params string[] strs)

可以在lua里头这样调用:

testobj:VariableParamsFunc(5, 'hello', 'john')

使用Extension methods

在C#里定义了,lua里就能直接使用。

泛化(模版)方法

不直接支持,可以通过Extension methods功能进行封装后调用。

枚举类型

枚举值就像枚举类型下的静态属性一样。

testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)

上面的EnumTestFunc函数参数是Tutorial.TestEnum类型的。

枚举类支持__CastFrom方法,可以实现从一个整数或者字符串到枚举值的转换,例如:

CS.Tutorial.TestEnum.__CastFrom(1)
CS.Tutorial.TestEnum.__CastFrom('E1')

delegate使用(调用,+,-)

C#的delegate调用:和调用普通lua函数一样

+操作符:对应C#的+操作符,把两个调用串成一个调用链,右操作数可以是同类型的C# delegate或者是lua函数。

-操作符:和+相反,把一个delegate从调用链中移除。

Ps:delegate属性可以用一个luafunction来赋值。

event

比如testobj里头有个事件定义是这样:public event Action TestEvent;

增加事件回调

testobj:TestEvent('+', lua_event_callback)

移除事件回调

testobj:TestEvent('-', lua_event_callback)

64位整数支持

Lua53版本64位整数(long,ulong)映射到原生的64位整数,而luajit版本,相当于lua5.1的标准,本身不支持64位,xlua做了个64位支持的扩展库,C#的long和ulong都将映射到userdata:

支持在lua里头进行64位的运算,比较,打印

支持和lua number的运算,比较

要注意的是,在64扩展库中,实际上只有int64,ulong也会先强转成long再传递到lua,而对ulong的一些运算,比较,我们采取和java一样的支持方式,提供一组API,详情请看API文档。

C#复杂类型和table的自动转换

对于一个有无参构造函数的C#复杂类型,在lua侧可以直接用一个table来代替,该table对应复杂类型的public字段有相应字段即可,支持函数参数传递,属性赋值等,例如: C#下B结构体(class也支持)定义如下:

public struct A
{
    public int a;
}

public struct B
{
    public A b;
    public double c;
}

某个类有成员函数如下:

void Foo(B b)

在lua可以这么调用

obj:Foo({b = {a = 100}, c = 200})

获取类型(相当于C#的typeof)

比如要获取UnityEngine.ParticleSystem类的Type信息,可以这样

typeof(CS.UnityEngine.ParticleSystem)

“强”转

lua没类型,所以不会有强类型语言的“强转”,但有个有点像的东西:告诉xlua要用指定的生成代码去调用一个对象,这在什么情况下能用到呢?有的时候第三方库对外暴露的是一个interface或者抽象类,实现类是隐藏的,这样我们无法对实现类进行代码生成。该实现类将会被xlua识别为未生成代码而用反射来访问,如果这个调用是很频繁的话还是很影响性能的,这时我们就可以把这个interface或者抽象类加到生成代码,然后指定用该生成代码来访问:

cast(calc, typeof(CS.Tutorial.Calc))

上面就是指定用CS.Tutorial.Calc的生成代码来访问calc对象。

 

三、注意事项

1、对于Lua 要经常访问的C#类什么的,可以构建一个 局部变量,方便调用,节约效率

2、对与成员熟悉的修改,可以修改非静态的属性,静态属性的值会变为 nil(很奇怪,是真的吗,在线等确认)

 

四、实现步骤

1、新建一个文本文件 LuaCallCSharp.lua.txt

 

2、打开编写 lua 代码

 

3、新建 Unity 工程,新建一个 LuaTxt 文件夹,并把 文本文件 LuaCallCSharp.lua.txt 导入

 

4、在工程中,新建一个脚本,调用执行 lua.txt 的 内容,并且构建成员函数

 

5、把脚本挂载到场景中

 

6、运行场景,结果如下

 

五、关键代码

1、LuaCallCSharp.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public class LuaCallCSharp : MonoBehaviour {

    // Lua 环境变量
    LuaEnv luaEnv;

	// Use this for initialization
	void Start () {
        LuaInit();

        luaEnv.DoString("require'LuaCallCSharp'");

    }


    void OnDestroy() {
        LuaDispose();
    }

    /// <summary>
    /// Lua 环境构建
    /// </summary>
    private void LuaInit() {
        luaEnv = new LuaEnv();
    }

    /// <summary>
    /// Lua 环境释放
    /// </summary>
    private void LuaDispose() {
        luaEnv.Dispose();
    }

}

/// <summary>
/// Lua 调用的成员函数
/// </summary>
[LuaCallCSharp]
public class MyClass
{

    public static int TestStaticData_01 = 0;
    public static int TestStaticData_02 { get; set; }
    public int TestData { get; set; }
    public MyClass()
    {
        TestStaticData_01 = 1;
        TestStaticData_02 = 2;
        TestData = 3;
    }

    public void TestFunction_01()
    {
        Debug.Log(" C# 成员函数 TestFunction_01");
    }

    public void TestFunction_02()
    {
        Debug.Log(" C# 成员函数 TestFunction_02");
    }
}

 

2、LuaCallCSharp.lua.txt

function luaCallCSharp()

	print(">>>luaCallCSharp>>>")	

	-- new C# 对象
	local newGameObject = CS.UnityEngine.GameObject()
	local newGameObject_name = CS.UnityEngine.GameObject("LuaCallCS")
	print(newGameObject, newGameObject_name)

	--访问静态属性,方法
	local GameObject = CS.UnityEngine.GameObject
	print("UnityEngine.Time.deltaTime:",CS.UnityEngine.Time.deltaTime)  -- 读取静态属性
	CS.UnityEngine.Time.timeScale = 0.5 -- 写静态属性
	print("LuaCallCS", GameObject.Find('LuaCallCS')) --静态方法

	-- 访问成员属性,方法
	local MyClass = CS.MyClass
	local myClassObject = MyClass()	-- 相当于 C# 中 new 

	print("TestData:",myClassObject.TestData)	-- 读取成员属性
	myClassObject.TestData = 12	-- 写成员属性
	print("TestData:",myClassObject.TestData)	-- 读取成员属性

	print("TestStaticData_01:",MyClass.TestStaticData_01)	-- 读取成员静态属性
	MyClass.TestStaticData_01 = 23	-- 写成员静态属性
	print("TestStaticData_01:", myClassObject.TestStaticData_01)	-- 读取成员静态属性

	print("TestStaticData_02:",MyClass.TestStaticData_02)	-- 读取成员静态属性
	MyClass.TestStaticData_02 = 34	-- 写成员静态属性
	print("TestStaticData_02:",myClassObject.TestStaticData_02)	-- 读取成员静态属性

	myClassObject:TestFunction_01()		-- 成员函数
    myClassObject:TestFunction_02()

end

-- 执行函数
luaCallCSharp()

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仙魁XAN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值