Skip to content

Unity3D集成使用文档

vimfung edited this page Apr 8, 2019 · 10 revisions

集成说明

  1. 下载LuaScriptCore_Unity_2.3.2.unitypackage
  2. 直接双击“LuaScriptCore.unitypackage”文件,根据提示把包导入到Unity项目的Assets/Plugins目录中。
  3. 导入成功后则可以正常使用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所定义的方法都是全局的,有时候需要对一系列的方法进行一个封装,希望这些方法都归类在某个模块下,一来方便根据模块来划分方法的功能,二来可以避免名称的冲突,同时也可以使用面向对象的方式在Lua中进行代码编写。因此,LuaScripCore提供了LuaExportType来让原生代码中的类型方便快速地导入到Lua中,供Lua进行调用。其实现步骤如下:

  1. 新声明一个原生类型并实现LuaExportType接口
  2. 在创建的类型中定义需要导出到Lua的方法和属性,声明方式完全跟Java的方法一样(对于不想导出到Lua的方法可以在定义时使用下划线“_”开头)。

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

/**
 * 日志模块
 * Created by vimfung on 16/9/23.
 */
public class Log : LuaExportType
{
    public string prefix;

    public void writeLog(string message)
    {
        Debug.Log(message);
    }

    private static Log _instance = new Log();
    public static Log sharedInstance()
    {
        return _instance;
    }
}

在Lua中则可进行如下调用:

local log = Log:sharedInstance();
log.prefix = "LuaScriptCore";
log:writeLog('Hello Lua Module!');

构造 & 销毁

导出到Lua的原生类型可以直接通过类型()方式来构造类型对象。如:

local obj = Object();

如果需要在实例对象构造或者销毁时做一些操作,则可以通过重写类型的initdestroy方法来实现。如:

function Object.prototype:init ()
    print ("object created!");
end

function Object.prototype:destroy()
    print ("object destroy!");
end

类型原型

Lua中引入了原型prototype实现,每个导出的原生类型带有此属性。其包含了类型的实例方法和属性定义。如果需要扩展某个类型的实例方法和属性,则可通过修改prototype来实现。例如为Object类型增加print实例方法:

function Object.prototyp:print()
    print(self);
end

对于类方法扩展,则可以直接在类型中进行声明,如:

function Object:createObject(name)
    local instance = self();
    instance.name = name;
    return instance;
end

继承

Lua中可以通过subclass直接子类化原生类型来生成一个新的类型,如:

Object:subclass("MyClass");

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

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

local instance = MyClass();
print (instance.propertyName);

上述代码的subclass就是子类化对象方法,其接收一个类型名称参数,调用后会创建一个对应名称的类型。该类型拥有Object的所有特性。 当继承类需要覆盖父级类型的某个方法时,只要直接重写一遍父级方法即可,如下代码所示:

-- 创建一个Object的类方法
function Object.classMethodName ()
    print ("Object classMethodName call");
end

-- 创建子类
Object:subclass("MyClass");

-- 覆盖父类方法
function MyClass:classMethodName ()
    print ("MyClass classMethodName call");
end

如果需要在覆盖方法中调用父级方法,可以使用类型的super属性,如:

function MyClass:classMethodName ()
    MyClass.super.classMethodName(self);
    print ("MyClass classMethodName call");
end

实例方法的覆盖方式大致相同,如:

-- 创建一个Object的实例方法
function Object.prototype:instanceMethodName ()
    print ("Object instanceMethodName call");
end

-- 创建子类
Object:subclass("MyClass");

-- 覆盖父类方法
function MyClass.prototype:instanceMethodName ()
    -- 调用父级方法
    MyClass.super.prototype.instanceMethodName(self);
    print ("MyClass instanceMethodName call");
end
Clone this wiki locally