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[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; 
}

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.先运行编辑器脚本,看到在StreamingAssetsWin下是否生成了多个.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[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
";


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

猜你喜欢

转载自blog.csdn.net/u012138730/article/details/81183094