找回密码
 立即注册
查看: 306|回复: 0

Unity For XLua 学习笔记 2021/7/21

[复制链接]
发表于 2022-2-12 08:51 | 显示全部楼层 |阅读模式
XLua在安卓端我遇到的那些事


  • 在安卓中读写,我起初是用的c#的方式(File.WriteAllText与File.ReadAllText),死活写入不了,于是我想到我为啥要舍近求远呢,Lua不一样也能读写吗? 于是请看代码

    • 需要注意在使用Application.persistentDataPath路径用lua写入时会遇到一个错误"LuaException: xxx:36: cannot open file '......./xxx.json' (No such file or directory)" 原因我也不是很清楚,这个问题我用c#解决的(也就是判断一下平台,如果时pc就用c#的file读写,如果时安卓就用lua的读写)

--写   写完记得关闭
local filePath = Application.persistentDataPath .. "/Archive/xxxx.json"
local file2=io.output(filePath )   --不需要文件存在
    io.write(jsonData)
    io.flush()
    io.close()

--读
local file1=io.input(filePlayerDataPath)  --不需要文件存在
    local str=io.read("*a")     -- *a 意思是读取全部
    local playerDataByJson = Json.decode(str)  --用json工具类转成表


-------Application.persistentDataPath在pc用lua读写报错解决方案
if Application.platform == CS.UnityEngine.RuntimePlatform.Android then
        local file2=io.output(filePlayerDataPath)
        io.write(jsonData)
        io.flush()
        io.close()

    else
        File.WriteAllText(filePlayerDataPath,jsonData)
    end

  • 1
1
Lua基础知识


  • 数据类型

    • 简单的复杂类型 (使用没有声明过的变量,不会报错,默认值为nil)

      • nil (空)
      • number (数值类型)
      • string (lua中没有字符与字符串之分)

        • # 获取字符串的长度,英文占1个长度,汉字占3个长度
        • 多行打印

          • 转义字符 跟c#一样




str = [[ 我



酷 ]]




        • 字符串拼接 ..   (只有用了都是string拼接)

      • boolean

    • 复杂的数据类型

      • 函数 function
      • 表 table
      • 数据结构 userdata
      • 协同程序 thread(线程)


  • 运算符

    • 算术运算符 + - * / % ^(幂运算)

      • 没有自增自减 ++ --
      • 没有符合运算符  +=   -=   *=  /=  %=


print("123"+1)   打印124   为什么呢  lua会将字符串转成数值类型然后相加 还有个原因lua中拼接符号为..
而c#中 会打印1231  它会认为这个+号是字符串拼接  而非算术运算符


    • 条件运算符 >  <  >=  <=  ==  ~=(不等于)
    • 逻辑运算符 and(与)  or(或)  not(非)   支持短路

      • 它们不仅能连接boolean表达式,还能连接任意东西(如:1 and 2)。当用and连接非boolean表达式时返回and关键词右边的表达式,用or连接则返回or左边的表达式(这里潜藏一个"短路"的知识,结合下面那句,and:判断左边如果不等于nil与false,则继续判断右边,如果2边都为真返回右边的值)
      • 在lua中 只有nil 和 false 才认为时假

    • 位运算符  不支持
    • 三目运算符  不支持但能这么写

a= 3
b= 2
--如果a大于b(逻辑与有假则假),那么它会用a or b(结合在连接非boolean表达式) 所以它会返回a
--否则返回b
c= (a>b) and a or b  
print(c)

  • 条件分支语句  (lua中没有switch)
a=9
if a>3 then
    print("3")
elseif a>5 then
    print("5")
else
    print("0")
end

  • 循环语句

    • for  (如果第3个数不写,lua会自动+1)

for i=1,5 do
    print(i)  --1-5
end

for i=1,5,2 do
    print(i)  --1,3,5
end


    • while

num = 0
while num < 5 do
    print(num)
    num = num + 1
end


    • do while    (until 是结束条件而非进入条件   也就是说满足条件我就跳出循环)

repeat
    print(num)
    num = num + 1
until num > 5

  • 函数(function)  不能在函数声明之前调用

    • 无参无返回值

function F1()
    print("函数F1")
end
F1()


    • 有参数无返回值 (不支持默认值也就是给参数赋值)

      • 当传入参数不匹配时,不会报错  只会补空nil  或者  丢弃 (传入参数多于需要参数)


function F2(a)
    print("有参数的函数F2:".. a)
end
F2(2)


    • 有参数有返回值 (支持多返回值)

      • 如果接收变量不够或接收变量过多,会直接丢弃多于的返回值 或  会给个nil值,不会报错


function F3(a)
    return a
end
temp = F3(1)
--多返回值
function F3(a)
    return a,"test",true
end
temp,temp1,temp2 = F3(1)


    • 函数的类型 就是 function
    • 函数的重载   不支持重载   默认调用最后声明的函数
    • 变长参数(...)  第一行的参数列表与第二行的表是固定写法

function F4( ... )
    arg = {...}
    for i=1,#arg do
        print(arg)
    end
end

F4(1,3,2,32)


    • 函数嵌套

function F5()
    return function()
        print("333")
    end
end
f5 = F5()
f5()


    • 闭包

function F5(x)
    return function(y)
        return x+y
    end
end
f5 = F5(10)
print(f5(5))

  • table(表) 索引从1开始

    • 数组  a = {1,3,4,1,"Test",true,nil}

      • 奇怪的现象

        • 当表的末尾 为nil时,其他任意位置为nil会影响到#获取长度(1与2位置不会影响)。栗子: a={1,2,3,nil,5,6,7,nil}   #a  输出3  | a={1,2,nil,4,5,6,nil}  #a 会输出2

      • 打印长度时空(nil)会被忽略

    • 二维数组与二维数组的遍历

a = {{1,2,3},{4,5,6}}
for i=1,#a do
        b=a
        for j=1,#b do
                print(a[j])
        end
end


    • 自定义索引

      • 获取长度时,会优先计算非自定义索引,如果自定义索引能续接非自定义索引,长度继续计算,续接不能超过1 ,也就是说索引只要按照顺序1增长都视为有效长度。如果当前表的索引按顺序进行排列(包括自定义索引),中间索引可以断隔1个长度,还能被计算(1,2,4,6   这里的长度为6  它中间会给你填个nil值)


aa={[1]=1,2,3,[-1]=4,5}  --长度为3
aa={[4]=1,2,3,[-1]=4,[5]=5,[3]="21"}  --长度为5
aa={[4]=1,2,3,[-1]=4,[5]=5}   --长度为2
aa = {[1] = 1,[2]=2,[4] = 4,[6] = 6} --长度为6
print(#aa)


    • ipairs 迭代器遍历

      • 从1开始的顺序遍历,只要顺序没有断开都会进行遍历(不管索引的先后顺序)


a={[0]=1,2,[-1]=3,4,5,[5]=6,[4]=3}
for i,v in ipairs(a) do
        print(i .. "_" ..v)
end

-[[
输出如下
1_2
2_4
3_5
4_3
5_6
]]-


    • pairs迭代器遍历

      • 它能够将所有的键值找到


a={[0]=1,2,[-1]=3,4,5,[5]=6,[4]=3}
for k,v in pairs(a) do
        print(k .. "_" .. v)
end
-[[
输出
1_2
2_4
3_5
0_1
4_3
-1_3
5_6
]]-


    • 字典

      • 字典由key value构成
      • 访问值

        • 通过中括号     如:print(a["name"])
        • 通过 . 成员变量的形式,但不能是数值  如:print(a.name)

      • 声明


a={["name"]="小小酷",["age"]=18,["1"]=3}
print(a["name"]) --输出 :小小酷
print(a.name) --输出 :小小酷
print(a.1)  --会报错

--增
a.test="test"   --  还可以用 a["test"] = "test"
print(a.test)
--改
a.name = "xxk"
print(a["name"])
--删
a.test = nil
print(a.test)  --打印 nil



      • 遍历用paris



Student={
        age=1,
        sex=true,

        Up = function()
                print(age)  --跟Student表中age没有关系,它是一个全局变量
                Student.age = Student.age+1
                print(Student.age)
        end
}
--调用 有点类似于c#中的静态成员方法和静态成员变量
Student.Up()
--添加跟字典类似
Student.xxx = "1"
Student.Speak = function() print("我说话了") end
function Student.Speak() print("我又说话了") end

function Student:Speak()
        print(self.age .. "岁!")
end

Student:Speak()




        • "." 调用有参数必须传参数与 ":" 默认会把调用者传给第一个参数
        • self 表示第一个传入参数 如:function Student:Speak() print(self.age .. "岁!") end


    • 表的公共操作

      • table.insert(t1,t2)  将t2表插入到t1表的最后
      • table.remove(t1)  t1为操作表,第二个参数传入指定位置,否则删除最后一个
      • table.sort


aa = {5,2,9,7,6,3}
table.sort( aa )   --升序排序
for _,v in pairs(aa) do
        print(v)
end
table.sort( aa,function(a,b)  --降序排序
if(a>b) then    --可以理解为交换位置  
        return true;
end
end )
for _,v in pairs(aa) do
        print(v)
end



      • table.concat(拼接)  要传入操作表,第二个参数为连接字符(123:456   中间的":"就叫连接字符)


  • Require

    • 多脚本执行 关键字require("lua脚本名")  单引号与双引号都行,互相require会报错
    • 全局变量和本地变量   不加local的为全局变量,加local的为本地变量
    • 可以在脚本里面返回一个任意类型,然后接收使用,如果不使用返回默认会返回一个true

for i=1,2 do
        local a = "xxk"
        print(a)  -- 输出xxk
end
print(a) --输出nil
-- ////////////////////////////
print("Test")
return "TestLocal"
--上下是2个不同的脚本
print( require("Test"))


    • 脚本卸载

      • package.loaded["脚本名"]    该脚本是否被执行 。    将它赋值nil就是卸载脚本(package.loaded["Test"]=nil)

    • 大G表    写法:_G  固定写法

      • 它是一个总表,它将我们声明的所有全局的变量都存储在其中


  • 多变量赋值 a,b,c=1,2     当后的值不够会自动补空,多了会自动省略
  • 函数多返回值   return 10,20,30   用几个,就用几个变量接,返回值多了会自动省略,少了会自动赋值nil
  • 协同程序(协程)   协程的本质是一个线程,类型是:thread

    • 创建

      • 使用coroutine.create创建后返回一个线程


fun = function()
        print(123)
end

co= coroutine.create(fun)

print(co)



      • 使用coroutine.wrap创建后返回一个函数


fun = function()
        print(123)
end

co= coroutine.wrap(fun)

print(co)


    • 运行

      • 使用coroutine.create创建后用coroutine.resume运行


coroutine.resume(co)



      • 使用coroutine.wrap创建后可以像调用函数一样调用

    • 挂起

      • coroutine.yield  它可以有返回值,第一个返回值为resume的返回值(也就是是否运行成功),第二个才是yield的返回值


fun = function()
        local i = 1
        while true do
                print(i)
                i = i + 1
                coroutine.yield(i)
        end
end

co= coroutine.create(fun)
isOK,tempI = coroutine.resume(co)
print(isOK,tempI)



      • wrap  没有是否运行成功的返回值,也是可以有返回值的  跟函数的返回值获取方式一样

    • 状态   coroutine.status获取当前协程的状态

      • dead(结束)
      • suspended(暂停)
      • running(进行中)
      • coroutine.running  获取线程号


  • 元表

    • 元表的概念

      • 任何表变量都可以作为另一个表变量的元表
      • 任何表变量都可以有自己的元表
      • 当我们子表中进行一些特定操作时,会执行原表中的内容

    • 设置元表 setmetatable(子表,元表(父表))
    • 特定操作

      • __tostring  当子表被当做字符串使用时,默认调用元表中tostring方法。想获取子表中的东西可以加参数,设置原表时会默认把子表传递进来


meta = {
        __tostring = function()
                return "小小酷"
        end
}
myTable = {}
setmetatable(myTable,meta)
print(myTable)  --打印:小小酷
--*****************
meta = {
        __tostring = function(t)
                return t.name
        end
}
myTable = {
        name = "xxk"
}
setmetatable(myTable,meta)
print(myTable)  --打印:xxk



      • __call  当子表被当做一个函数来使用时,默认调用call方法。第一个参数是子表本身,第二个开始的参数才是传入参数


meta = {
        __tostring = function(t)
                return t.name
        end,
        __call = function()
                print("小小酷")
        end
}
myTable = {
        name = "xxk"
}
setmetatable(myTable,meta)
myTable()  --打印:小小酷
--***************
meta = {
        __tostring = function(t)
                return t.name
        end,
        __call = function(t,a)
                print(t)  --打印:xxk
                print(a)  --打印:1
                print("小小酷")
        end
}
myTable = {
        name = "xxk"
}
setmetatable(myTable,meta)
myTable(1)  --打印:小小酷



      • 运算符重载

        • __add  当子表使用+运算符时,默认调用_add方法。
        • 其他运算符关键词:

          • __sub(-)
          • __mul(*)
          • __div(/)
          • __mod(%)
          • __pow(^)
          • __eq(==)   --条件运算符需要2个子表的元表一致  否则为false
          • __lt(<)   --没有>  >=  ~=    可以用取反(not)
          • __le(<=)
          • __concat(..)




meta = {
        __tostring = function(t)
                return t.name
        end,
        __call = function(t,a)
                print(t)  --打印:xxk
                print(a)  --打印:1
                print("小小酷")
        end,
        __add = function(t1,t2)
                return t1.name .. t2.name
        end
}
myTable = {
        name = "xxk"
}
setmetatable(myTable,meta)
myTable2 = { name = "张三"}
print(myTable + myTable2)



      • __index和__newindex

        • __index 当子表中找不到某一个属性时,会去元表中_index指定的表去找属性,会一层一层的往上找,如果找不到返回nil。建议写在外面。用于实现继承关系



meta = {
        __index = { age=1}
}
myTable = {
}
setmetatable(myTable,meta)
print(myTable.age) --打印1
--*********************
meta = {
        age = 1
}
meta.__index = meta
myTable = {
}
setmetatable(myTable,meta)
print(myTable.age) --打印1




        • __newindex 当赋值时,如果赋值一个不存在的索引,那么会把这个值赋值到newindex所指的表中,不会修改自己
        • 获取元表 getmetatable(传入子表)
        • rawget(表,属性名)  在自身上找有没有这个变量,即使设置了index也不会去元表找
        • rawset(表,属性名,值)  只会设置自身的变量,即使设置了newindex也不会去设置元表



  • 面向对象三大特性实现

    • 封装

--元表相关的知识点
Object = {}
Object.id = 1

-- 冒号 自动将调用者作为第一个参数传入
function Object:new()
        --新建一个表用于返回值
        local obj = {}
        --将传入的表设置index元表特性,如果当前表找不到,就会向上元表中找
        self.__index = self
        --设置元表
        setmetatable(obj,self)
        --返回子表
        return obj
end

local myObj = Object:new()
print(myObj)   --打印表的地址
print(myObj.id)        --打印:1


    • 继承

function Object:SubClass(className)
        --利用大g表创建全局表
        _G[className] = {}
        --获取从大g表中获取表
        local obj = _G[className]
        --设置index
        self.__index = self
        obj.base = self  --写这句是为了在重写方法后保留父类的方法(能在子类调用父类的方法)
        --设置元表,继承关系
        setmetatable(obj,self)
end

Object:SubClass("myTable")

print(myTable.id)


    • 多态  相同行为 不同表象 就是多态

Object:SubClass("GameObject")
GameObject.posX = 0;
GameObject.posY = 0;

function GameObject:Move()
        self.posX = self.posX+1
        self.posY = self.posY+1
        print(self.posX)
        print(self.posY)
end

GameObject:SubClass("Player")
function Player:Move( )
        self.base:Move()
end

local p1 = Player:new()
p1:Move()
--*************************
GameObject:SubClass("Player")
function Player:Move()
        --为什么为引用一个对象呢?  答案就在下面这句代码中
        --首先p1与p2的Move中posX和posY实际使用的是GameObject
        --所以这里得手动把自己传进去,这才符合面向对象下编程
        self.base.Move(self)
end

local p1 = Player:new()
p1:Move() --打印:11
local p2 = Player:new()
p2:Move() --打印:22

  • 自带库

    • 时间  year(年) month(月) day(日) hour(时) min(分) sec(秒)

      • os.time()   获取当前系统时间戳 或者 传入一张表转换成时间戳


print(os.time()) --打印当前系统的时间戳
print(os.time({year = 2021,month = 3,day = 1}))  --输出:1614571200



      • os.date("*t")  返回当前时间表

    • 数学运算

      • math.abs(-11)   绝对值
      • math.deg(math.pi) 弧度转角度
      • math.cos(math.pi)  三角函数  传弧度
      • math.floor(2.6)  向下取整
      • math.ceil(5.2) 向上取整
      • math.max(1,2) 返回最大值
      • math.min(4,5) 返回最小值
      • math.modf(1.2) 小数分离  分成整数部分和小数部分   --打印:1   0.2
      • math.pow(2,5) 幂运算  打印:32
      • math.randomseed(os.time())  设置随机数种子
      • math.random(100)  获取随机数  先要设置随机数种子
      • math.sqrt(4) 开方

    • 路径

      • package.path   获取路径列表
      • package.path = package.path .. ";c:\\"      添加路径


  • 垃圾回收 collectgarbage()    lua中有自动定时进行gc的方法,在unity中热更新开发中尽量不要用自动垃圾回收

    • collectgarbage("count")  获取当前lua占用内存数 k字节   用 返回值*1024 就可以得到具体的内存占用字节数
    • collectgarbage("collect")  立即进行一次垃圾回收

  • 函数(实用方法)

    • type (获取类型) 返回值是string
    • string.format(拼接字符串) 栗子:string.format("我是小小酷,今年%d岁了",18);

      • %d : 与数字拼接
      • %a :与任何字符拼接
      • %s : 与字符配对

    • tostring (转换成string)
    • string.upper (将字符串转换成大写,不会改变原字符串)
    • string.lower(将字符串转换成小写,不会改变原字符串)
    • string.reverse (将字符串翻转,不会改变原字符串)
    • string.find (查找字符索引,索引从1开始的)
    • string.sub (截取字符串)
    • string.rep (将字符串重复n次)
    • string.gsub (字符串替换  会返回替换次数)
    • string.byte (将字符转ASCII码)
    • string.char (将ASCII码转成字符)

<hr/>AssetBundle基础


  • AB包是什么

    • 特定于 平台的资产压缩包,有点类似于压缩文件
    • ab包包含:模型、贴图、预设体、音效、材质球等等

  • AB包有什么作用

    • 相对Resources下的资源AB包更好管理资源




Resources与AB包的区别



    • 减小包体大小

      • 压缩资源
      • 减少初始包大小

    • 热更新

      • 资源热更新
      • 脚本热更新





热更新基本规则


  • 生成AB包资源文件

    • 自定义打包工具
    • 官方提供:Asset Bundle Browser   可以去Github下载:




    • AssetBundleBrowser参数相关

      • 压缩方式

        • LZMA 它压缩后包体最小 但缺点是用一个就得全部解压
        • LZ4   它压缩后包体会比LZMA大一点点  用到什么资源解压什么资源


    • AB包生成的文件(AssetBundleBrowser生成的)

      • AB包文件    资源文件
      • manifest文件

        • AB包文件信息
        • 当加载时,提供了关键信息
        • 资源信息,依赖关系,版本信息等等

      • 关键AB包(和目录名一样的包)


  • AB包资源加载   同一名字的ab包不能加载多次

    • 通过文件

      • AssetBundle.LoadFromFile(ab包完整路径)
      • AssetBundle.LoadFromFileAsync(ab包完整路径)    异步加载ab包   需要用协程加载


private IEnumerator Start()
                {
                         //通过异步加载ab包         返回一个异步请求
                         var abCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/model");
                         //等待加载完成
                         yield return abCreateRequest;
                         //通过异步加载资源   返回一个异步请求
                         var abRequest = abCreateRequest.assetBundle.LoadAssetAsync("Cube",typeof(GameObject));
                         //等待加载完成
                         yield return abRequest;
                         //根据资源生成一个GameObject
                         Instantiate(abRequest.asset);
                }


    • 通过内存
    • 通过流处理器

  • AB的卸载

    • abCreateRequest.assetBundle.Unload(false)  卸载ab包  参数是否卸载场景中用ab加载的资源
    • AssetBundle.UnloadAllAssetBundles(false)  卸载所有ab包  参数是否卸载场景中用ab加载的资源

  • AB包的依赖

    • 关于AB包的依赖:一个资源用到了别的AB包的资源,如果不加载依赖包,就会引用丢失,如果加载就正常了,只要使用前一起加载了就没有问题。当然如果项目体积过大这样加载人都傻了
    • 为了解决这个问题,可以用个ab包保存这些依赖关系(也就是利用主包,获取依赖信息)
    • 在AssetBundleBrowser

//加载主包
var mainAB = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/PC");
//从主包中加载Manifest
var manifest =  mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//获取所有的依赖并加载
manifest.GetAllDependencies("model").ToList()
        .ForEach(_ => AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + _));


    • 1

<hr/>xLua热更新


  • xLua配置与AB包相关准备

    • 下载xlua可以去github
    • 需要导入Assets下的Plugins和XLua文件夹
    • 先点击一次XLua->clear generated code->generate code
    • 在 Project Settings->Scripting Define Symbols 写入:HOTFIX_ENABLE
    • 把下载的包里面的Tools 剪切到 项目根目录
    • 点击hotfix inject in editor
    • 测试环境可以 点击 clear generated code   在把Xlua目录中的Example文件夹删除
    • 每次更新C#代码 都必须重新生成与注入一下代码 否则会报错
    • 报try to dispose a LuaEnv with C# callback!   请把xlua.hotfix(CS.命名空间.脚本名,'Update',nil)

  • C# 调用 Lua

    • Lua解析器

      • DoString(执行lua代码)   参数 1执行lua代码 2当报错是抛出报错文件名
      • Tick(清楚没有手动释放的对象 垃圾回收)  不要每帧执行  垃圾回收很好性能

    • Lua文件加载重定向

      • AddLoader()  xlua提供的自定义加载lua文件的规则  给个加载委托,如下


...
var xluaEnv = new LuaEnv();
xluaEnv.AddLoader(Loader);
...

//fileName 是require执行的文件名
private byte[] Loader(ref string fileName)
{

     var absPath = Application.dataPath + "/Scripts/Lua/" + fileName + ".lua.txt";
     return File.ReadAllBytes(absPath);
}


    • Lua解析器管理器

      • 要保证lua全局唯一   所以使用单例模式


public class XLuaEnvMgr : Singleton<XLuaEnvMgr>
    {
        private XLuaEnvMgr()
        {
        }

        private LuaEnv mXLuaEnv = null;

        /// <summary>
        /// 获取Lua环境
        /// </summary>
        public LuaEnv XLuaEnv
        {
            get
            {
                mXLuaEnv ??= new LuaEnv();
                mXLuaEnv.AddLoader(Loader);
                return mXLuaEnv;
            }
        }

        /// <summary>
        /// 得到Lua中的_G
        /// </summary>
        public LuaTable Global => XLuaEnv.Global;

        private byte[] Loader(ref string fileName)
        {
            var absPath = Application.dataPath + "/Scripts/Lua/" + fileName + ".lua.txt";
            if (File.Exists(absPath)) return File.ReadAllBytes(absPath);
            else throw new Exception($"当前路径{absPath}不存在:{fileName}");
        }
}


    • 全局变量获取 (局部变量没办法直接获取)

      • 使用_G去获取与改变全局变量


XLuaEnvMgr.Instance.Global.Get<int>("testNumber").Log();
XLuaEnvMgr.Instance.Global.Set("testNumber",33);



      • 注意:直接使用require xlua会自动使用加载器去加载


-- Main
print("hello world")
require("Test2")
--Test2
print("Test2.lua")
testNumber =1
testString ="xxk"
testBool = true

--打印  hello world与Test2.lua


    • 全局函数获取

--lua代码
--无参无返
test1 = function()  
    print("无参无返")
end
--有参有反
test2=function(a)
    print("有参有反")
    return a+1
end
--多反
test3=function()
    print("多反")
    return 1,"2",1.3,true
end
--变长参数
test4 = function(...)
    print("变长参数")
    local arg = {...}
    for i, v in pairs(arg) do
        print(k,v)
    end
end



      • 获取与修改都可以用下面的方法,当类型不确定是可以用object来装


XLuaEnvMgr.Instance.Global.Get<Action>("test1");
LuaFunction lf = XLuaEnvMgr.Instance.Global.Get<LuaFunction>("test1");


    • 映射到List和Dictionary
    • 映射到类

      • 跟litjson使用差不多   变量名一样   私有和保护无法赋值
      • 不需要全部定义  没定义的就不获取

    • 映射到接口  接口中不能写字段  所以用属性实现
    • 映射到LuaTable

  • Lua 调用 C#


    • 枚举
    • 数组、List、Dictionary
    • 函数(扩展方法)
    • 函数(ref和out)
    • 函数(重载)
    • 委托和事件
    • 特殊问题(二维数组遍历)
    • 特殊问题(null和nil比较)
    • 特殊问题(让系统类型能被Lua访问)
    • 协程
    • 泛型函数

  • xlua 热补丁

    • 第一个热补丁
    • 多函数替换
    • 协程函数替换
    • 索引器和属性替换
    • 事件替换
    • 泛型类替换

  • 代码的更新

    • c#代码

[XLua.Hotfix]
        public class Cube : UnityEngine.MonoBehaviour
        {
                private UnityEngine.Rigidbody mRB;

                private void Start()
                {
                        mRB = GetComponent<UnityEngine.Rigidbody>();
                        XLuaEnvMgr.Instance.XLuaEnv.DoString("require 'Test'");

                }

                [XLua.LuaCallCSharp]
                private void Update()
                {
                        if (UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.W))
                        {
                                mRB.AddForce(UnityEngine.Vector3.up * 300);
                        }
                }
        }

//其中的XLuaEnvMgr是一个单例   XLuaEnv是一个属性  我在这个属性get中创建了LuaEnv 并 实现了Loader
private LuaEnv mXLuaEnv = null;

        /// <summary>
        /// 获取Lua环境
        /// </summary>
        public LuaEnv XLuaEnv
        {
            get
            {
               //如果为空则赋值
                mXLuaEnv ??= new LuaEnv();

                mXLuaEnv.AddLoader(Loader);
                return mXLuaEnv;
            }
        }
      
        //ref
        private byte[] Loader(ref string fileName)
        {
            //Loader的路径
            var absPath = Application.dataPath + "/Scripts/Lua/" + fileName + ".lua.txt";
            return File.ReadAllBytes(absPath);
        }


        private void OnDisable()
        {
            XLuaEnv.DoString("require 'LuaDispose'");
        }

        private void OnDestroy()
        {
            mXLuaEnv?.Dispose();
        }


    • lua代码

xlua.hotfix(CS.命名空间.脚本名,'Update',function(self)  
    if CS.UnityEngine.Input.GetKeyDown(CS.UnityEngine.KeyCode.D) then
        self.mRB:AddForce(CS.UnityEngine.Vector3.up * 300)
    end
end)

  • 注册事件 带参数时需要加个静态的类型列表并使用特性CSharpCallLua 需要放到Editor目录下,如下
public static class CSharpCallLua
        {
                [XLua.CSharpCallLua]
        public static List<Type> csharpCallLuaList = new List<Type>()
        {
                typeof(UnityEngine.Events.UnityAction<bool>)
        };
        }

  • 1
  • 1

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-6-3 23:17 , Processed in 1.179291 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表