Skip to content

Unity3D集成使用文档(适用1.x.x版本)

vimfung edited this page Dec 4, 2017 · 1 revision

集成说明

  1. 下载源码到本地
  2. 打开Release/Unity目录。
  3. 直接双击“LuaScriptCore.unitypackage”文件,根据提示把包导入到Unity项目的Assets/Plugins目录中。
  4. 导入成功后则可以正常使用LuaScriptCore了。

关于重新编译的问题

由于Unity3D涉及多平台的发布,目前仅支持iOS、Mac OS X以及Android平台,因此在重新编译库时根据需要选择对应的平台进行重新编译。

iOS/OSX平台重新编译

  1. 打开Source/Unity3D/iOS_OSX/目录中的LuaScriptCore项目文件。
  2. 选择你想要重新编译的平台,如果是iOS则选择LuaScriptCore-Unity-iOS-output的sheme,如果是OS X则选择LuaScriptCore-Unity-OSX-output的sheme。
  3. Command + B 进行重新编译,编译后的库文件和头文件会放到Release/Unity/iOS或者Release/Unity/Editor目录下。
  4. 将编译的库拷贝到Source/Unity3D/UnityProject/Assets/Plugins/LuaScriptCore/目录下覆盖同名目录。
  5. 打开Source/Unity3D/UnityProject/目录下的Unity项目,选择项目结构列表中的Assets/Plugins/LuaScriptCore目录。
  6. 点击右键,在弹出菜单中选择Export Package...,然后选择保存项目即可导出包。

Android平台重新编译

  1. 打开Android Studio,然后导入Source/Unity3D/Android/目录下的项目。
  2. Command + F9 重新编译目录。
  3. 编译成功后,在模块的build/intermediates/bundles/release目录可以找到一个jni的文件夹。
  4. 将jni/armeabi-v7a和jni/x86两个目录拷贝到Source/Unity3D/UnityProject/Assets/Plugins/LuaScriptCore/Android目录下覆盖同名目录。
  5. 打开Source/Unity3D/UnityProject/目录下的Unity项目,选择项目结构列表中的Assets/Plugins/LuaScriptCore目录。
  6. 点击右键,在弹出菜单中选择Export Package...,然后选择保存项目即可导出包。

使用说明

初始化LuaScriptCore

LuaScriptCore中提供了LuaContext这个上下文对象类来维护整个Lua的环境,考虑到场景切换后会导致挂载脚本对象回收问题,在Unity3D中可以使用LuaContext.currentContext这个单例方法来访问LuaContext中的所有功能,无需单独初始化LuaContext对象。如:

LuaContext context = LuaContext.currentContext;

解析Lua脚本

原生层中(这里指C#层)要操作Lua中的变量或者方法,通常使用到的就是组织Lua脚本来进行一些列的Lua操作(LuaScriptCore屏蔽了Lua库中的C Api,目的是让代码更加接近原生,使用起来更加得心应手),然后交由Context进行脚本的解析。如:

LuaContext.currentContext.evalScript ("print('Hello World');");

注册一个原生方法给Lua调用

对于一些耗时或者Lua无法实现的功能(如:手机设备的拍照),都可以考虑交由原生层来实现,然后提供接口让Lua进行调用。如下面获取应用信息的方法:

在C#代码中定义方法

LuaContext.currentContext.registerMethod("getDeviceInfo", (arguments) => {
        Dictionary<string, LuaValue> info = new Dictionary<string, LuaValue>();
        info.Add("productName", new LuaValue(Application.productName));
        return new LuaValue(info);
});

在Lua代码中调用方法

local tbl = getDeviceInfo();

调用一个Lua方法

有时候需要通过调用Lua中的方法来取得返回值(在原生层中只能取得一个返回值),然后再做后续的处理,例如:

在Lua代码中有add方法的定义

function add (a, b)

    return a+b;

end

在C#代码中通过context调用Lua方法

LuaValue retValue = LuaContext.currentContext.callMethod ("add", 
                    new List<LuaValue> (){ new LuaValue (1000), new LuaValue (24)});
Debug.Log (string.Format ("result = {0}", retValue.toNumber ()));

模块化扩展

LuaContext所定义的方法都是全局的,有时候需要对一系列的方法进行一个包装,希望这些方法都归类在某个模块下,一来方便根据模块来划分方法的功能,二来可以避免名称的冲突。因此,可以使用LuaModule来对Lua的功能进行扩展。需要根据下面步骤实现:

  1. 新声明一个模块类继承于LuaModule类(必须继承于LuaModule类,否则无法进行模块注册)
  2. 在创建的模块类中定义需要导出到lua的类方法(即由static修饰的方法),声明方法完全跟C#的方法一样(对于不想导出到Lua的方法可以使用非public权限修饰),但需要注意的是结构体是无法作为参数或者返回值与Lua进行交互。
  3. 调用LuaContext的registerModule方法将定义的类型传入即完成功能模块的扩展。

下面例子定义了一个日志模块,如:

在C#代码中定义LuaModule的子类

public class LogModule : LuaModule
{
	public static void writeLog(String message)
	{
		Debug.Log(message);
	}
}

注册模块

LuaContext.currentContext.registerModule<LogModule> ();

在Lua代码中调用

LogModule.writeLog('Hello Lua Module!');

让Lua面向对象

Lua中没有明确的面向对象特性,LuaScriptCore提供了一个面向对象的扩展,Lua可以简单地封装类型,并且进行类型实例的使用。首先需要先注册面向对象的模块类LuaObjectClass(如果原生层有继承于LuaObjectClass类的子类需要注册时,该步骤可省略),如:

C#中

LuaContext.currentContext.registerModule<LuaObjectClass> ();

注册成功后,可以直接在Lua中定义类型,如:

Object.subclass("MyClass");

-- 重写类型的初始化方法
function MyClass:init ()
    print("MyClass instance initialize...");
end

-- 定义类型属性
MyClass.property = 0;

local instance = MyClass.create();
print (instance.property);

上述代码的subclass就是子类化对象方法,其接收一个类型名称参数,调用后会创建一个对应名称的类型。该类型拥有Object的所有特性。

对于Lua的类定义有如下设定:

  1. 所有类型的根类是Object,这个注册LuaObjectClass后会有这个类的定义.
  2. 必须使用subclass方法来进行子类化,必须传入一个有效并且不重复的类型名称参数。
  3. 必须使用类型的create方法进行类对象的实例化。
  4. 类型中的方法(即类方法)都以.号进行调用,类实例中的方法都以:号进行调用。类型和实例的属性都以.号进行访问。
  5. 每个类中都有一个叫super的属性来指代其父类型。
  6. 需要调用父类方法时,请使用"类型.super.method"方式进行调用,如:MyClass.super.test();
  7. 当类实例对象初始化时会触发init方法,销毁时会触发destroy方法,可以通过重写这些方法来进行一些额外的工作。

如果需要让原生类直接映射到Lua中,按照下面步骤实现:

  1. 定义一个新的类继承于LuaObjectClass类。
  2. 定义新类型的属性和方法(注:原生类中的属性会转换为Lua类中的setXXX和XXX方法),对于不想导出到Lua中的方法或属性可以在声明时使用非public权限来修饰。
  3. 定义类的类方法会导出给类型,定义实例方法会导出给类型的实例。
  4. 调用LuaContext的registerModule方法将定义的类型传入即完成Lua类的声明。导入时可以直接导入子类,LuaContext会检测是否有导入根类型。

如在C#中有如下类型定义

public class Person : LuaObjectClass 
{
	private string _name;
	public string name
	{
		get 
		{
			return _name;
		}
		set
		{
			_name = value;
		}
	}

	public static Person printPerson(Person p)
	{
		Debug.Log (p.name);
		return p;
	}

	public static Person createPerson()
	{
		return new Person ();
	}

	public void speak()
	{
		Debug.Log (string.Format("{0} speak", this.name));
	}
}

然后对该类型进行注册:

LuaContext.currentContext.registerModule<Person> ();

注册成功后,在lua中即可使用该类型:

local person = Person.create();
person:setName("vimfung");
person:speak();
Person.printPerson(person);

动态导入原生类型到Lua

从v1.3.1版本开始,LuaScriptCore提供了ClassImport允许动态导入原生类型到Lua的功能。目的是为了帮助在程序执行过程中需要调用非LuaObjectClass子类型的原生对象功能。若要使用ClassImport请注册模块:

LuaContext.currentContext.registerModule<LuaClassImport> ();

假设存在一个NativeData的类型,如:

public class NativeData
{
	public NativeData ()
	{
	}

	private string _dataId;

	public string dataId
	{
		get
		{
			return _dataId;
		}
		set
		{
			_dataId = value;
		}
	}

	public static Person createPerson()
	{
		return new Person ();
	}
}

然后设置允许动态导出的类型,基于安全的考虑默认是不允许导出任意类型到Lua中的,所以必须要设置哪些类型允许被导出,如:

LuaClassImport.setIncludesClasses (LuaContext.currentContext, new List<Type> (){ typeof(NativeData) });

然后在Lua中进行使用:

local Data = ClassImport('cn.vimfung.test.Person'); 
print(Data); 
local d = Data.create(); 
print(d); 
d:setDataId('xxxx'); 
print(d:dataId()); 
d:setData('xxx','testKey'); 
print(d:getData('testKey'));

关于ClassImport的几点注意事项

  1. 只能导入允许的类型。
  2. 当导入LuaObjectClass的子类型时会触发类型注册,并返回指定类型。
  3. ClassImport导入的类型为全属性全方法导出,不带有继承特性(导入LuaObjectClass子类型除外)。
Clone this wiki locally