acecase 发表于 2021-10-16 07:33

ToLua使用笔记(中)

继续看例子
目录
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:待看
13.CustomLoader:自定义加载器Loader的使用

【需要修改:在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();    }14.Out:out修饰输入参数

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)
15.ProtoBuffer:编码、解码protobuff消息

这里涉及到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: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{        public static byte[] data; }16.Int64:在lua中使用int64类

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      ";17.Inherit:在Lua中扩展C#对象

主要接口:
tolua.setpeerr(csobj, peer)设置替身
csobj: C#对象在lua中对应的userdata
peer:一个lua table
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      ";18.Bundle:用编辑器脚本将lua脚本打包成assetbundle以及加载使用

对于assetbundle没有接触的可以看下这篇。
1.先运行编辑器脚本,看到在StreamingAssets的Win下是否生成了多个.unity3d的assetbundle包。
( 具体实现查看 BuildNotJitBundles 函数)


2.代码中演示了 使用协程先将AB资源包加载内存完毕,然后再通过AB包中加载相应的lua脚本的过程。
(把断点打入LuaInterface.LuaFileUtils.ReadZipFile函数,查看具体如何查找和加载)
(可以测试下原始lua脚本删除也是正常运行的Assets\LuaFramework\ToLua)
19.cjson:待看

通过cjson组件读取json文件,等有遇到再看
20.utf8:lua中,利用utf8类对中文、日文等东方文字进行操作

    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";21.String:在Lua中,对C#String类的操作

    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 is ' .. buffer..'\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";



22.Reflection:待看, lua中的反射

23.List:操作C#List<T>类型

在lua中对C#List<int> 的操作。
//需要导出委托类型如下:
//System.Predicate<int>
//System.Action<int>
//System.Comparison<int>
24.Struct:待看

总结一下最重要的在lua中用C#类
1. 准备工作,使用插件自带的Wrap功能生成 lua需要调用的 C#类
   (通过 配置 CustomSetting.cs, 运行编辑器脚本)
2. 同时 Bind 函数的更新(会调用 Wrap.Register)
3. 在lua中 调用其中的静态方法和成员变量的时候都是 类.成员或类.静态方法,而调用类中的非静态私有成员方法时则是需要这样写:类:方法,

http://doc.ulua.org/default.asp?cateID=3
页: [1]
查看完整版本: ToLua使用笔记(中)