Unity XLua 官方教程学习
一、Lua 文件加载
1. 执行字符串
using UnityEngine;
using XLua; public class ByString : MonoBehaviour {
LuaEnv luaenv = null;
// Use this for initialization
void Start () {
luaenv = new LuaEnv();
// 执行代码块,输出 hello world
luaenv.DoString("print('hello world')");
} // Update is called once per frame
void Update () {
if (luaenv != null)
{
// 清楚 Lua 未手动释放的 LuaBase 对象
luaenv.Tick();
}
} void OnDestroy()
{
// 销毁
luaenv.Dispose();
}
}
其中 Dostring 函数返回值即为代码块里 return 语句的返回值。
2. 加载 Lua 文件
luaenv = new LuaEnv();
// 加载 byfile Lua 文件
luaenv.DoString("require 'byfile'");
其中 Lua 文件代码为:
print('hello world')
需要注意的是因为 Resource 只支持有限的后缀,放 Resources 下 lua 文件得加上 txt 后缀,如:byfile.lua.txt。
3. 自定义 Loader
void Start()
{
luaenv = new LuaEnv();
// 自定义 loader
luaenv.AddLoader((ref string filename) => {
// 若要加载 InMemory
if (filename == "InMemory")
{
string script = "return {ccc = 9999}";
// 将字符串转换成byte[]
return System.Text.Encoding.UTF8.GetBytes(script);
}
return null;
});
// 执行代码块,访问table中的常量ccc
luaenv.DoString("print('InMemory.ccc=', require('InMemory').ccc)");
}
通过 Addloader 可以注册个回调,该回调参数是字符串,返回一个 byte 数组。lua 代码里调用 require 时,参数就会传给回调。
注意,require 返回一个由模块常量和函数组成的table。
二、C# 访问 Lua
其中 lua 代码如下:
a =
b = 'hello world'
c = true d = {
f1 = , f2 = ,
, , ,
add = function(self, a, b)
print('d.add called')
return a + b
end
} function e()
print('i am e')
end function f(a, b)
print('a', a, 'b', b)
return , {f1 = }
end function ret_e()
print('ret_e called')
return e
end
其中包含常量,表和函数。C# 代码如下:
public class DClass
{
public int f1; // 属性与Xlua里的对应
public int f2;
} [CSharpCallLua]
public interface ItfD
{
int f1 { get; set; }
int f2 { get; set; }
int add(int a, int b);
} // 生成代码
// 若有多个参数,可用 out 属性接收剩下的返回
[CSharpCallLua]
public delegate int FDelegate(int a, string b, out DClass c); [CSharpCallLua]
public delegate Action GetE(); // Use this for initialization
void Start()
{
luaenv = new LuaEnv();
luaenv.DoString(script); // 访问全局常量
Debug.Log("_G.a = " + luaenv.Global.Get<int>("a")); //
Debug.Log("_G.b = " + luaenv.Global.Get<string>("b")); // hello world
Debug.Log("_G.c = " + luaenv.Global.Get<bool>("c")); // Ture // 访问全局的 table
// 映射到普通的class或struct
//映射到有对应字段的class,值拷贝,class字段的修改不会影响到table,反之也不会
DClass d = luaenv.Global.Get<DClass>("d");
Debug.Log("_G.d = {f1=" + d.f1 + ", f2=" + d.f2 + "}"); // 12 34 // 映射有 key 的
Dictionary<string, double> d1 = luaenv.Global.Get<Dictionary<string, double>>("d");//映射到Dictionary<string, double>,值拷贝
Debug.Log("_G.d = {f1=" + d1["f1"] + ", f2=" + d1["f2"] + "}, d.Count=" + d1.Count); // 12 34 2 // 映射没有 key 的
List<double> d2 = luaenv.Global.Get<List<double>>("d"); //映射到List<double>,值拷贝
Debug.Log("_G.d.len = " + d2.Count); // 3 // 映射到一个 interface
// 要在 interface 定义前加 [CSharpCallLua]
ItfD d3 = luaenv.Global.Get<ItfD>("d"); //映射到interface实例,by ref,这个要求interface加到生成列表,否则会返回null,建议用法
d3.f2 = ; // 外部修改会影响 Lua 内的值
Debug.Log("_G.d = {f1=" + d3.f1 + ", f2=" + d3.f2 + "}"); // 12 1000
Debug.Log("_G.d:add(1, 2)=" + d3.add(, )); // d.add called //映射到LuaTable,by ref
LuaTable d4 = luaenv.Global.Get<LuaTable>("d");
Debug.Log("_G.d = {f1=" + d4.Get<int>("f1") + ", f2=" + d4.Get<int>("f2") + "}"); // 访问一个全局的函数
// 映射到 delegate
Action e = luaenv.Global.Get<Action>("e");//映射到一个delgate,要求delegate加到生成列表,否则返回null,建议用法
e(); // i am e FDelegate f = luaenv.Global.Get<FDelegate>("f");
DClass d_ret;
// 多值返回,可用out接收多余的参数
// 输出 a 100 b John
int f_ret = f(, "John", out d_ret);//lua的多返回值映射:从左往右映射到c#的输出参数,输出参数包括返回值,out参数,ref参数
// table只含有常量f1,所以f2赋值为0
Debug.Log("ret.d = {f1=" + d_ret.f1 + ", f2=" + d_ret.f2 + "}, ret=" + f_ret); // 1024 0 1 GetE ret_e = luaenv.Global.Get<GetE>("ret_e");//delegate可以返回更复杂的类型,甚至是另外一个delegate
e = ret_e();
e(); // 映射到 LuaFunction
LuaFunction d_e = luaenv.Global.Get<LuaFunction>("e");
// Call 函数可以传任意类型,任意个数的参数
d_e.Call(); }
访问 lua 全局数据,特别是 table 以及 function,代价比较大,建议尽量少做,比如在初始化时调用获取一次后,保存下来,后续直接使用即可。
三、Lua 调用 C#
其中 C# 代码如下:
namespace Tutorial
{
[LuaCallCSharp]
public class BaseClass
{
public static void BSFunc()
{
Debug.Log("Driven Static Func, BSF = "+ BSF);
} public static int BSF = ; public void BMFunc()
{
Debug.Log("Driven Member Func, BMF = " + BMF);
} public int BMF { get; set; }
} public struct Param1
{
public int x;
public string y;
} [LuaCallCSharp]
public enum TestEnum
{
E1,
E2
} [LuaCallCSharp]
public class DrivenClass : BaseClass
{
[LuaCallCSharp]
public enum TestEnumInner
{
E3,
E4
} public void DMFunc()
{
Debug.Log("Driven Member Func, DMF = " + DMF);
} public int DMF { get; set; } public double ComplexFunc(Param1 p1, ref int p2, out string p3, Action luafunc, out Action csfunc)
{
Debug.Log("P1 = {x=" + p1.x + ",y=" + p1.y + "},p2 = "+ p2);
luafunc();
p2 = p2 * p1.x;
p3 = "hello " + p1.y;
csfunc = () =>
{
Debug.Log("csharp callback invoked!");
};
return 1.23;
} public void TestFunc(int i)
{
Debug.Log("TestFunc(int i)");
} public void TestFunc(string i)
{
Debug.Log("TestFunc(string i)");
} public static DrivenClass operator +(DrivenClass a, DrivenClass b)
{
DrivenClass ret = new DrivenClass();
ret.DMF = a.DMF + b.DMF;
return ret;
} public void DefaultValueFunc(int a = , string b = "cccc", string c = null)
{
UnityEngine.Debug.Log("DefaultValueFunc: a=" + a + ",b=" + b + ",c=" + c);
} public void VariableParamsFunc(int a, params string[] strs)
{
UnityEngine.Debug.Log("VariableParamsFunc: a =" + a);
foreach (var str in strs)
{
UnityEngine.Debug.Log("str:" + str);
}
} public TestEnum EnumTestFunc(TestEnum e)
{
Debug.Log("EnumTestFunc: e=" + e);
return TestEnum.E2;
} public Action<string> TestDelegate = (param) =>
{
Debug.Log("TestDelegate in c#:" + param);
}; public event Action TestEvent; public void CallEvent()
{
TestEvent();
} public ulong TestLong(long n)
{
return (ulong)(n + );
} class InnerCalc : ICalc
{
public int add(int a, int b)
{
return a + b;
} public int id = ;
} public ICalc GetCalc()
{
return new InnerCalc();
} public void GenericMethod<T>()
{
Debug.Log("GenericMethod<" + typeof(T) + ">");
}
} [LuaCallCSharp]
public interface ICalc
{
int add(int a, int b);
} [LuaCallCSharp]
public static class DrivenClassExtensions
{
public static int GetSomeData(this DrivenClass obj)
{
Debug.Log("GetSomeData ret = " + obj.DMF);
return obj.DMF;
} public static int GetSomeBaseData(this BaseClass obj)
{
Debug.Log("GetSomeBaseData ret = " + obj.BMF);
return obj.BMF;
} public static void GenericMethodOfString(this DrivenClass obj)
{
obj.GenericMethod<string>();
}
}
}
其中可变参数可用 params string[] strs 实现。要在 Lua 直接访问什么,记得在定义前加上 [LuaCallCSharp]
对应的 lua 代码为:
function demo()
-- new C#对象
-- 没有new,所有C#相关的都放在CS下
local newGameObj = CS.UnityEngine.GameObject()
-- 创建一个名为helloworld的物体
local newGameObj2 = CS.UnityEngine.GameObject('helloworld')
print(newGameObj, newGameObj2) --访问静态属性,方法
local GameObject = CS.UnityEngine.GameObject
print('UnityEngine.Time.deltaTime:', CS.UnityEngine.Time.deltaTime) --读静态属性
CS.UnityEngine.Time.timeScale = 0.5 --写静态属性
-- 查找物体 helloworld
print('helloworld', GameObject.Find('helloworld')) --静态方法调用 --访问成员属性,方法
local DrivenClass = CS.Tutorial.DrivenClass
local testobj = DrivenClass()
testobj.DMF = --设置成员属性
print(testobj.DMF)--读取成员属性
-- 输出 DMF=1024
testobj:DMFunc()--成员方法 使用冒号 --基类属性,方法
print(DrivenClass.BSF)--读基类静态属性 1
DrivenClass.BSF = --写基类静态属性
DrivenClass.BSFunc();--基类静态方法 2048
-- BMF 初始为0
print(testobj.BMF)--读基类成员属性 0
testobj.BMF = --写基类成员属性
testobj:BMFunc()--基类方法调用 4096 --复杂方法调用
-- 参数处理规则:C#的普通参数和ref修饰的算一个参数,out不算,从左往右顺序
-- 返回值处理规则:返回值(如果有)算第一个,out,ref修饰的参数算一个,从左往右
local ret, p2, p3, csfunc = testobj:ComplexFunc({x=, y = 'john'}, , function()
print('i am lua callback')
end)
print('ComplexFunc ret:', ret, p2, p3, csfunc)
csfunc() --重载方法调用
testobj:TestFunc()
testobj:TestFunc('hello') --操作符
local testobj2 = DrivenClass()
testobj2.DMF =
-- 输出DMF=1024+2048=3072
print('(testobj + testobj2).DMF = ', (testobj + testobj2).DMF) --默认值
testobj:DefaultValueFunc()
testobj:DefaultValueFunc(, 'hello', 'john') --可变参数
testobj:VariableParamsFunc(, 'hello', 'john') --Extension methods
print(testobj:GetSomeData())
print(testobj:GetSomeBaseData()) --访问基类的Extension methods
testobj:GenericMethodOfString() --通过Extension methods实现访问泛化方法 --枚举类型
-- 返回E2
local e = testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
-- 输出枚举类型格式为 E2:1
print(e, e == CS.Tutorial.TestEnum.E2)
-- 整数或者字符串到枚举类型的转换
print(CS.Tutorial.TestEnum.__CastFrom(), CS.Tutorial.TestEnum.__CastFrom('E1'))
print(CS.Tutorial.DrivenClass.TestEnumInner.E3)
assert(CS.Tutorial.BaseClass.TestEnumInner == nil) --委托
testobj.TestDelegate('hello') --直接调用
local function lua_delegate(str)
print('TestDelegate in lua:', str)
end
testobj.TestDelegate = lua_delegate + testobj.TestDelegate --combine,这里演示的是C#delegate作为右值,左值也支持
testobj.TestDelegate('hello')
testobj.TestDelegate = testobj.TestDelegate - lua_delegate --remove
testobj.TestDelegate('hello') --事件
local function lua_event_callback1() print('lua_event_callback1') end
local function lua_event_callback2() print('lua_event_callback2') end
-- 增加回调事件
testobj:TestEvent('+', lua_event_callback1)
testobj:CallEvent()
testobj:TestEvent('+', lua_event_callback2)
testobj:CallEvent()
-- 移除回调事件
testobj:TestEvent('-', lua_event_callback1)
testobj:CallEvent()
testobj:TestEvent('-', lua_event_callback2) --64位支持
local l = testobj:TestLong()
print(type(l), l, l + , + l) --typeof
-- 增加粒子系统
newGameObj:AddComponent(typeof(CS.UnityEngine.ParticleSystem)) --cast 强转
-- 返回 InnerCalc 类
local calc = testobj:GetCalc()
print('assess instance of InnerCalc via reflection', calc:add(, ))
assert(calc.id == )
-- 强转
cast(calc, typeof(CS.Tutorial.ICalc))
print('cast to interface ICalc', calc:add(, ))
assert(calc.id == nil)
end demo() --协程下使用
local co = coroutine.create(function()
print('------------------------------------------------------')
demo()
end)
assert(coroutine.resume(co))
其中 assert 函数用于有错误时抛出异常。
注意,C# 的 int, float, double 都对应于 lua 的 number,重载时会无法区分。
Unity XLua 官方教程学习的更多相关文章
- Unity XLua 官方案例学习
1. Helloworld using UnityEngine; using XLua; public class Helloworld : MonoBehaviour { // Use this f ...
- Note | PyTorch官方教程学习笔记
目录 1. 快速入门PYTORCH 1.1. 什么是PyTorch 1.1.1. 基础概念 1.1.2. 与NumPy之间的桥梁 1.2. Autograd: Automatic Differenti ...
- Vue-2:官方教程学习
1,先把下面这些内容都按照官方教程敲一遍,打好基础,类似于“前戏”,其作用我想爸爸就不必多说了吧(づ。◕‿‿◕。)づ. https://cn.vuejs.org/v2/guide/ 同时可以配合配套视 ...
- Unity 官方教程 学习
Interface & Essentials Using the Unity Interface 1.Interface Overview https://unity3d.com/cn/lea ...
- uni-app官方教程学习手记
本人微信公众号:前端修炼之路,欢迎关注 背景介绍 大概在今年的十月份左右,我了解到Dcloud推出了uni-app.当时下载了一个Hbuilder X,下载了官方提供的hello示例教程.经过一番努力 ...
- Unity Dotween官方案例学习
本文只涉及一些案例,具体查看 DoTween 官方文档. 一. Basics public class Basics : MonoBehaviour { public Transform redCub ...
- Unity5UGUI 官方教程学习笔记(四)UI Image
Image Source image:源图片 需要显示的图片 Color:颜色 会与图片进行颜色的混合 Material:材质 Image Type: Simple 精灵只会延伸到适合Rec ...
- Unity5UGUI 官方教程学习笔记(三)UI BUTTON
Button Interactable :为了避免与该按钮产生交互,可以设置它为false Transition: 管理按钮在正常情况 ,按下,经过时的显示状态 None 按钮整正常工作 但是在按 ...
- Unity5UGUI 官方教程学习笔记(二)Rect Transform
Rect Transform Posx Posy Posz : ui相对于父级的位置 Anchors :锚点 定义了与父体之间的位置关系 一个锚点由四个锚组成 四个锚分别代表了 ...
随机推荐
- Unity By Reflection Update Scripts
App热更新需求 我正在使用Unity 3D开发一个Android的应用,它会下载AssetBundles并加载它们的内容,但由于AssetBundles不能包含脚本,我将使用预编译的C#脚本,并使用 ...
- ip 命令的使用
网上相似的资源很多,可以参考如下资料: man ip ip help 博客链接: https://linoxide.com/linux-command/use-ip-command-linux/ ht ...
- Android开发中使用七牛云存储进行图片上传下载
Android开发中的图片存储本来就是比较耗时耗地的事情,而使用第三方的七牛云,便可以很好的解决这些后顾之忧,最近我也是在学习七牛的SDK,将使用过程在这记录下来,方便以后使用. 先说一下七牛云的存储 ...
- [LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅
[LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅 题意 比较复杂放LOJ题面好了qaq... Kiana 最近喜欢到一家非常美味的寿司餐厅用餐. 每天晚上,这家餐厅都会按顺序提供 ...
- [Python] 同时安装了python2和python3时,pip命令该如何使用?
当python2和python3同时安装windows上时,它们对应的pip都叫pip.exe,所以不能够直接使用 pip install 命令来安装软件包. 而是要使用启动器py.exe来指定pip ...
- 线程同步方式之互斥量Mutex
互斥量和临界区非常相似,只有拥有了互斥对象的线程才可以访问共享资源,而互斥对象只有一个,因此可以保证同一时刻有且仅有一个线程可以访问共享资源,达到线程同步的目的. 互斥量相对于临界区更为高级,可以对互 ...
- Spark项目之电商用户行为分析大数据平台之(五)实时数据采集
- windows下vi/vim编辑器的基本操作
windows下vi/vim编辑器的基本操作 Contents 1. 工具准备(下载gvim) 2. vi/vim基本入门 2.1. 安装 2.2. 基本使用 3. vi/vim基本命令表 1 工具准 ...
- QGis C++ 开发之创建临时图层并添加要素
开发环境:Win10 + VS2010 + Qt 4.8.6 + QGis 2.14.4 其实本文实现的功能类似于QGis中“添加文本数据图层”的一个简化版,本文不会涉及到对话框的使用 ...
- kettle(一) 安装全过程
windows 10 环境 所有资料下载 https://pan.baidu.com/s/1vYZVJ3f0QJHsCWiupSp08A 一.下载kettle pdi-ce-7.1.0.0-12.zi ...