继续看例子
目录
13.CustomLoader:自定义加载器Loader的使用
14.Out:out修饰输入参数
15.ProtoBuffer:编码、解码protobuff消息
16.Int64:在lua中使用int64类
17.Inherit:在Lua中扩展C#对象
18.Bundle:用编辑器脚本将lua脚本打包成assetbundle以及加载使用
19.cjson:待看
20.utf8:lua中,利用utf8类对中文、日文等东方文字进行操作
21.String:在Lua中,对C#String类的操作
22.Reflection:待看, lua中的反射
23.List:操作C#List类型
24.Struct:待看
【需要修改:在TestCustomLoader中加上一个方法
void Start()
{
StartMain();
}
】
1.关键表达式:new LuaResLoader();
2.通过自定义的加载器(LuaResLoader),可以使用特定的方式(LuaResLoader.ReadResourceFile)加载lua文件
这个例子中的TestLoader.lua就是通过 Resource.Load来加载的。具体请看LuaResLoader.cs。
所以尽管没有加入搜索的目标路径(像例子02那样),也能加载 TestLoader.lua ,只要在Resources文件夹下即可。
// LuaClient 继承自 MonoBehavior, 有 Awake Start 和 Update 等函数
public class TestCustomLoader : LuaClient
{
string tips = "Test custom loader";
// 定义了一个新的加载器 LuaResLoader ,其继承自 LuaFileUtils, 重写了 ReadFile 函数。
protected override LuaFileUtils InitLoader()
{
return new LuaResLoader();
}
protected override void CallMain()
{
LuaFunction func = luaState.GetFunction("Test");
func.Call();
func.Dispose();
}
protected override void StartMain()
{
// 最终会调用 LuaFileUtils.Instance.ReadFile(fileName); 调用的是 LuaResLoader.ReadFile;
// 即会通过 Resource.Load 来调用这个 lua 脚本。
luaState.DoFile("TestLoader.lua");
CallMain();
}
// new 关键字 重写基类的方法
new void Awake()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += Logger;
#else
Application.RegisterLogCallback(Logger);
#endif
base.Awake();
}
void Start()
{
StartMain();
}
C#中碰撞检测代码:
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Camera camera = Camera.main;
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
bool flag = Physics.Raycast(ray, out hit, 5000, 1 << LayerMask.NameToLayer("Default"));
if (flag)
{
Debugger.Log("pick from c#, point: [{0}, {1}, {2}]", hit.point.x, hit.point.y, hit.point.z);
}
func.BeginPCall();
func.Push(ray);
func.PCall();
func.EndPCall();
}
state.CheckTop();
state.Collect();
}
lua中碰撞检测代码:
string script =
@"
-- 如果不加下面这句话: 会提示warning register PreLoad type UnityEngine.BoxCollider to lua 。疑问
local box = UnityEngine.BoxCollider
function TestPick(ray)
local _layer = 2 ^ LayerMask.NameToLayer('Default')
local time = os.clock()
local flag, hit = UnityEngine.Physics.Raycast(ray, nil, 5000, _layer)
--local flag, hit = UnityEngine.Physics.Raycast(ray, RaycastHit.out, 5000, _layer)
if flag then
print('pick from lua, point: '..tostring(hit.point))
end
end
";
对比Lua中和C#中实现碰撞检的输出,结果一致:
具体 lua中调用 Raycast 函数的时候在C#段如何调用的:
UnityEngine_PhysicsWrap.Raycast.try.if 中 count =4 输入参数为4 的时候 (例子09)
这里涉及到protobuf 的应用,没有接触的可以先看一下这篇文章。
两个原始proto文件为:
common.proto
person.proto
使用了 protoc-gen-lua 工具编译lua以后的文件,并且放入unity的Resources文件夹下中:
person_pb.lua.bytes
common_pb.lua.bytes
然后在C#中的执行lua脚本内容如下:
private string script = @"
-- 引入两个模块 也就是加上 由proto文件编译的lua文件
local common_pb = require 'Protol.common_pb'
local person_pb = require 'Protol.person_pb'
-- C#端 再调用的 Decoder 函数
function Decoder()
local msg = person_pb.Person()
-- data: 一个LuaByteBuffer特性的byte[]类型变量 为了传递c#与lua间的序列化后的数据
-- 从字符串解析
msg:ParseFromString(TestProtol.data)
--tostring 不会打印默认值
print('person_pb decoder:\n '..tostring(msg)..'\nage: '..msg.age..'\nemail: '..msg.email)
end
-- C#端 先调用的 Encoder 函数
function Encoder()
-- 直接看 person.proto 进行赋值就行了 不要看 person_pb.lua
-- 对 required 字段必须赋值
local msg = person_pb.Person()
msg.header.cmd = 10010
msg.header.seq = 1
msg.id = '1223372036854775807'
msg.name = 'foo'
-- 对 option 字段可以选择性赋值
-- 对 repeat 字段:数组添加
msg.array:append(1)
msg.array:append(2)
--extensions 添加
local phone = msg.Extensions[person_pb.Phone.phones]:add()
phone.num = '13788888888'
phone.type = person_pb.Phone.MOBILE
-- 调用序列化为字符串
local pb_data = msg:SerializeToString()
-- 写入静态类TestProtol中
TestProtol.data = pb_data
end
";
输出为:
其中C#中的TestProtol类暴露给Lua使用:
public static class TestProtol
{
[LuaByteBufferAttribute]
public static byte[] data;
}
lua5.1.x都是不支持int64和uint64的。Lua5.3已经支持了这两种数据类型
旧版本中使用tolua库,就可以使用int64和uint64。
例子中调用的方法:
int64.tonum2(x) tonum2会返回两个数,第二个数高位是右移32位的值,第一个数低位是剩下的值(&0xFFFFFFFF)。
int64.new(low,high) 创建一个int64的使用高位+低位的方式
int64.new(x) 创建一个int64
int64.equals(x,y)
string script =
@"
function TestInt64(x)
x = 789 + x
assert(tostring(x) == '9223372036854775807')
local low, high = int64.tonum2(x)
print('x value is: '..tostring(x)..' low is: '.. low .. ' high is: '..high.. ' type is: '.. tolua.typename(x))
// y 和 z 都是 userdata类型
// 可以像正常的数一样加减乘除、取余、取相反数、乘方等
local y = int64.new(1,2)
local z = int64.new(1,2)
if y == z then
print('int64 equals is ok, value: '..int64.tostring(y))
end
x = int64.new(123)
if int64.equals(x, 123) then
print('int64 equals to number ok')
else
print('int64 equals to number failed')
end
x = int64.new('78962871035984074')
print('int64 is: '..tostring(x))
local str = tostring(int64.new(3605690779, 30459971))
local n2 = int64.new(str)
local l, h = int64.tonum2(n2)
print(str..':'..tostring(n2)..' low:'..l..' high:'..h)
print('----------------------------uint64-----------------------------')
x = uint64.new('18446744073709551615')
print('uint64 max is: '..tostring(x))
l, h = uint64.tonum2(x)
str = tostring(uint64.new(l, h))
print(str..':'..tostring(x)..' low:'..l..' high:'..h)
return y
end
";
主要接口:
tolua.setpeerr(csobj, peer) | 设置替身 csobj: C#对象在lua中对应的userdata https://www.cnblogs.com/xsxjin/p/6854584.html |
tolua.getpeer | 获取替身 |
settab= tolua.initset(tbl) | 初始化tbl的set“访问器”,settab是一个table类型。 settab.XXX = function(self) …… end
|
gettab = tolua.initget(tbl) | 初始化tbl的get“访问器”,gettab 是一个table类型。 gettab .XXX = function(self, v) …… end |
例子中扩展了 Transform类,重写了一些方法,扩展了一个字段。
在没有扩展之前,当我们访问或设置userdata不存在的成员的时候,程序就会出错,但是在扩展之后,我们便可以扩展对象的成员。
private string script =
@" LuaTransform =
{
}
function LuaTransform.Extend(u)
print(type(u))
local t = {}
tolua.setpeer(u, t)
t.__index = t
print(type(u))
local get = tolua.initget(t)
local set = tolua.initset(t)
-- u.base是什么
local _base = u.base
local _position = u.position
--重写同名属性获取
get.position = function(self)
return _position
end
--重写同名属性设置
set.position = function(self, v)
if _position ~= v then
_position = v
_base.position = v
end
end
--重写同名函数 多打印一句话
function t:Translate(...)
print('child Translate')
_base:Translate(...)
end
return u
end
function Test(node)
-- 返回扩展过的,有替身的
local transform = LuaTransform.Extend(node)
-- 使用重写的set get函数 ,记录所需时间 与C#中对比
local t = os.clock()
for i = 1, 200000 do
transform.position = transform.position
end
print('LuaTransform get set cost', os.clock() - t)
-- 调用重写方法
transform:Translate(1,1,1)
-- 调用原有方法
local child = transform:Find('child')
print('child is: ', tostring(child))
-- 支持go.transform == transform 这样的比较
if child.parent == transform then
print('LuaTransform compare to userdata transform is ok')
end
-- 扩展了字段 没有报错
transform.xyz = 456
print('extern field xyz is: '.. transform.xyz)
end
";
对于assetbundle没有接触的可以看下这篇。
1.先运行编辑器脚本,看到在StreamingAssets的Win下是否生成了多个.unity3d的assetbundle包。
( 具体实现查看 BuildNotJitBundles 函数)
2.代码中演示了 使用协程 先将AB资源包加载内存完毕,然后再通过AB包中加载相应的lua脚本的过程。
(把断点打入 LuaInterface.LuaFileUtils.ReadZipFile 函数,查看具体如何查找和加载)
(可以测试下原始lua脚本删除也是正常运行的 Assets\LuaFramework\ToLua)
通过cjson组件读取json文件,等有遇到再看
string script =
@"
local utf8 = utf8
function Test()
local l1 = utf8.len('你好')--2
local l2 = utf8.len('こんにちは')--5
print('chinese string len is: '..l1..' japanese sting len: '..l2)
local s = '遍历字符串'
for i in utf8.byte_indices(s) do
local next = utf8.next(s, i)
print(s:sub(i, next and next -1))
end
local s1 = '天下风云出我辈'
print('风云 count is: '..utf8.count(s1, '风云'))
s1 = s1:gsub('风云', '風雲')
local function replace(s, i, j, repl_char)
if s:sub(i, j) == '辈' then
return repl_char
end
end
print(utf8.replace(s1, replace, '輩'))
end
";
string script =
@"
function Test()
local str = System.String.New('男儿当自强')
local index = str:IndexOfAny('儿自')
-- C# String类型 在lua中是 userdata类型
print('and index is: '..index)
print(str)
print('str type is: '..type(str)..'\n')
-- C#函数ToCharArray 返回char[] userdata类型
local buffer = str:ToCharArray()
print(buffer)
print('buffer type is: '..type(buffer)..' buffer[0] is ' .. buffer[0]..'\n')
-- str 转化为 lua基本类型 string
local luastr = tolua.tolstring(str)
print('lua string is: '..luastr..'type is: '..type(luastr)..'\n')
-- buffer 也可以转化为 lua基本类型 string
luastr = tolua.tolstring(buffer)
print('lua string is: '..luastr..'\n')
end
";
在lua中对C#List
//需要导出委托类型如下:
//System.Predicate
//System.Action
//System.Comparison
总结一下最重要的在lua中用C#类
1. 准备工作,使用插件自带的Wrap功能生成 lua需要调用的 C#类
(通过 配置 CustomSetting.cs, 运行编辑器脚本)
2. 同时 Bind 函数的更新(会调用 Wrap.Register)
3. 在lua中 调用其中的静态方法和成员变量的时候都是 类.成员 或 类.静态方法,而调用类中的非静态私有成员方法时则是需要这样写:类:方法,
http://doc.ulua.org/default.asp?cateID=3