AB包
作用:
- 比Resources更好管理资源
- Resources:打包时定死只读,无法修改
- AB包:存储位置自定,压缩方式自定,后期可以动态更新
- 减少包体大小
- 压缩资源
- 减少初始包体大小
- 热更新
生成的文件:
- AB包文件
- 资源文件
- manifest
- AB包文件信息
- 加载时,提供了关键信息,资源信息,以来关系,版本信息等
- 关键AB包(主包,和目录名一样的包)
Compression压缩方式:
- Nocompression
- 不压缩,解压快,包大
- LZMA
- 压缩最小,解压慢
- 用一个资源要解压所有
- LZ4
- 压缩相对LZMA大一点点
- 建议使用,用什么解压什么,内存占用低
加载资源:(不可重复加载包体)
先加载AB包本体,再加载资源
- 同步加载
- 加载AB包:AssetBundle.LoadFromFile
- 从AB包加载资源:ab.LoadAsset
- 异步加载(返回的是Request)
- 加载AB包:AssetBundle.LoadFromFileAsync(abName)
- 从AB包加载资源:ab.LoadAssetAsync
卸载AB包:(传参若为ture,则会同时卸载通过此包加载的资源)
- AssetBundle.UnloadAllAssetBundles(false);
- ab.Unload(false);
依赖:
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/cube");
GameObject obj = Instantiate(ab.LoadAsset<GameObject>("Cube"));
// 加载了一个Cube,但是其材质球在别的AB包中,不加载对应包会导致材质 异常
//得到所有依赖Cube的AB包并加载,正常加载Cube材质
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/PC");
AssetBundleManifest manifest = abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
string[] str = manifest.GetAllDependencies("cube");
foreach (string i in str)
{
AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + i);
}
Lua
- 4种简单的变量类型
- nil
- number
- string
- boolean
- 4种复杂的变量类型
- function 函数
- table 表
- userdata 数据结构
- thread 协同程序
- 字符串操作
- 获取字符串长度 #s
- 一个汉字占3个长度
- 字符串拼接 s1 .. s2
- 格式化占位符 string.format(“%d,123”)
- 转字符串 tostring(a)
- 大小写转换 string.upper/lower
- 翻转 string.reverse
- 字符串索引查找 string.find(str,”abc”)
- 可以查找字符串
- 截取 string.sub(str,3,4)
- 修改 string.gsub(str,”before”,”after”)
- 获取字符串长度 #s
- 运算符
- 算数运算符
- 不支持 += ++等
- 支持幂运算符 ^
- 条件运算符
- 不等于 ~=
- 逻辑运算符
- and
- or
- not
- 位运算符,三目运算符
- 不支持
- 但是三目运算符可以用另一种方式实现
- ans = ( x > y ) and x or y
- 算数运算符
- 条件分支语句
- 单分支:if 条件 then …… end
- 双分支:if 条件 then …. else ….. end
- 多分支:if 条件 then …. elseif 条件 then ….. end
- 循环语句
- while 条件 do …… end
- repeat ….. until
- for i = 1,5 do …. end
- 默认自增1,想要自定可以在5后传入第三个参数
- 函数
- 两种声明方式
- 直接声明 funtion func()…. end
- 可以作为变量 func = function()….. end
- 对于有参函数,传入的参数与要求不匹配,不会报错,只会补空nil或者丢弃
- 可以返回多个参数,用多个变量接收(直接用逗号隔开)
- lua不支持重载,默认调用最后一个声明的函数
- 变长参数 function func( … ) arg = { … }
- 参数为…,需要声明一个表接收
- 嵌套函数
- 闭包
- function f1(x)
return function (y)
return x + y
end
end
f2 = f1(1);
print(f2(2));
- function f1(x)
- 两种声明方式
- table表
- 数组
- 当数组中有nil时,会影响#获取数组长度(只能获取nil前面元素的个数)
- 迭代器ipairs和pairs
- ipairs只能遍历从1开始连续的元素
- pairs可以遍历数组中所有的元素
- for i,k in pairs(a) do
print(i .. ” ” .. k)
- for i,k in pairs(a) do
- 字典
- 添加
- 直接在字典里声明 a = {[“name”] = “Shen” , [“age”] = 19}
- 通过键新增 a[“sex”] = true
- 删除
- a[“name”] = nil
- 访问
- a.name
- a[“name”]
- 如果要遍历必须用pairs不能用ipairs
- 添加
- 类
- Student =
{
name = “shen”,
Func = function (t)
print(t.name)
end
} - 其中在表的内部函数中调用表中属性,也要加上表名
- lua中点和冒号的区别
- Student.Func(Student)
- Student:Func(),冒号会默认把调用者作为第一参数传入方法
- 冒号除了调用,还可以配合self声明
- Student:Func()
print(self.name)
end
- Student:Func()
- 冒号除了调用,还可以配合self声明
- Student =
- table表的公共操作
- table.insert( t1, t2 ) 将t2插入t1
- table.remove( t1 ) 移除t1中的尾部元素,也可以传入第二参数指定下标
- table.sort( t1 ) 升序排序
- 降序排序table.sort(t1,function(a,b)
if a > b then
return true
end
end)
- 降序排序table.sort(t1,function(a,b)
- 数组
- Local 本地变量
- require(”脚本名”) 多脚本执行,可以用变量接收,接收到的值为脚本中return的值
- package.loaded[“脚本名”] 返回true则该脚本已加载,若要卸载可以手动置false
- 大G表 _G 是一个总表(table),会将所有全局变量存入,local本地变量不会存入
- lua中只有nil和false才是假,0不是
- 协程
- 两种创建方式
- coroutine.create ( func ) type : thread
- 若yield中有返回值,可以用两个变量接收,第一变量为bool
- coroutine.warp ( func ) type : function
- 若yield中有返回值,用一个变量接收,原来的bool没了
- coroutine.create ( func ) type : thread
- 两种运行方式(对应上方两种创建方式)
- coroutine.resume ( myCoroutine )
- myCoroutine ( )
- 挂起
- coroutine.yield ( ) 可以传参作为返回值
- 状态
- coroutine.status ( 协程对象 )
- dead 结束
- suspended 暂停
- running 进行中
- coroutine.status ( 协程对象 )
- 得到正在运行的协程号
- coroutine.running ( )
- 两种创建方式
- 元表
- 设置元表函数
- setmetatable(子表,元表(父表))
- __tostring
- 当子表被作为字符串使用时,默认调用元表的__tostring方法
- __call
- 子表被作为方法使用时,默认调用元表的__call方法
- 元表中方法的第一参数为子表本身,第二参数才是传入参数
- __add,__sub,__mul,__div,__mod…….
- 运算符重载,对应 + – * / %
- __index
- 当你尝试访问一个表中不存在的键(例如
t.key)时,Lua 会做以下操作:- 检查该表是否有元表(metatable)
- 如果有元表,检查元表中是否有
__index字段 - 根据
__index的类型,执行不同逻辑:- 若
__index是一个表,Lua 会去这个表中查找该键 - 若
__index是一个函数,Lua 会调用该函数,传入原表和要访问的键
- 若
- 例:meta.__index = meta (写在表外部初始化)
- 当你尝试访问一个表中不存在的键(例如
- __newindex(与__index相似,由访问变为了赋值)
- 当你尝试给表中一个不存在的字段赋值时,Lua 会先检查该表是否有元表(metatable),并且元表中是否定义了 __newindex 方法:
- 如果存在 __newindex 方法,Lua 会调用这个方法,而不是直接在原表中添加新字段
- 如果不存在 __newindex 方法,Lua 会直接在原表中添加这个新字段
- 当你尝试给表中一个不存在的字段赋值时,Lua 会先检查该表是否有元表(metatable),并且元表中是否定义了 __newindex 方法:
- getmetatable ( 子表 )
- 得到元表的方法
- rawget ( 表, “属性” )
- 忽略元表 __index 的影响,获取此表中属性
- rawset ( 表, “属性”, 值 )
- 忽略元表 __newindex 的影响,赋值此表中属性
- 设置元表函数
- 面向对象
- 封装local Object = {}
Object.id = 1
function Object:new()
local obj = {}
self.__index = self;
setmetatable(obj,self)
return obj
end - 继承function Object:subClass(className)
_G[className] = {}
local obj = _G[className]
self.__index = self
setmetatable(obj, self)
end - 多态– 在继承方法中加入base属性为自己的父表
function Object:subClass(className)
_G[className] = {}
local obj = _G[className]
obj.base = self
self.__index = self
setmetatable(obj, self)
end— 声明子类
Object:subClass(“GameObject”)
GameObject:subClass(“Player”)
Player.posX = 0
Player.posY = 0p1 = Player:new();
p2 = Player:new();— 多态实现
function GameObject:Move()
self.posX = self.posX + 1
self.posY = self.posY + 1
print(self.posX)
print(self.posY)
endfunction Player:Move()
self.base.Move(self)
endp1:Move()
p2:Move()
- 封装local Object = {}
- Lua元表深拷贝的实现function clone(object)
local table_dic = {}local function _copy(object)
if type(object) ~= “table” then
return object
endif(table_dic[object] ~= nil) then
return table_dic[object]
endlocal new_table = {}
table_dic[new_table] = new_table
for key, value in pairs(object) do
new_table[_copy(key)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
return _copy(object)
end - 自带库
- math.abs
- math.deg
- math.cos
- math.floor / ceil
- math.max / min
- math.modf ( 1.2 )
- 两个变量接收 将数分为小数和整数部分
- math.sqrt
- 随机数
- math.randomseed( os.time() )
- math.random ( 100 )
- 垃圾回收
- collectgarbage ( “count” )
- 返回当前lua占用内存数,单位为K字节
- collectgarbage ( “collect” )
- 手动垃圾回收
- Tip:Unity热更新开发中尽量不要用自动垃圾回收,最好手动回收
- collectgarbage ( “count” )
C#调用Lua
- 调用前在编辑器中 Generate Code
- AB包打包前 Clear Generate Code
- Lua解析器
- Lua env = new LuaEvn( )
- 通常保持唯一性
- env.DoString( “print(‘Hello World’)” )
- 执行Lua语言
- 通常是env.DoString( “require( ‘ScriptName’ )” )
- 其中寻找脚本路径默认是在Resources下,并且要在Lua脚本后缀加上txt
- env.Tick( )
- 垃圾回收,通常在帧更新定时或者切换场景时执行
- env.Dispose( )
- 销毁解析器
- env.AddLoader( MyCustomLoader )
- private bite[ ] MyCustomLoader( ref string fileName )
- 由此函数通过File.ReadAllBytes(path)返回想要读取lua文件的地址
- 若地址无效则会从默认Resources中寻找lua资源
- 其中fileName为lua的文件名
- 可以添加多个,执行require时依次寻找
- private bite[ ] MyCustomLoader( ref string fileName )
- AB包加载lua文件
- lua文件必须加上.txt,在ab打包时不支持lua类型文件
- LoadAsset时文件名必须带上.lua因为.lua是文件的一部分不是后缀,不能省略
- 全局变量的获取
- 从
大G表(C#中的env.Global)获取lua中的变量 - LuaMgr.Instance.Global.
Get<int>(“Name”) 获取变量 - LuaMgr.Instance.Global.
Set(“Name”,10) 设置变量,改变引用
- 从
- 全局函数的获取
- 无参无返回
- 自定义委托 public delegate void CustomCall( )
- 不需要加特性,xLua已经处理过
- UnityAction
- Action
- 自定义委托 public delegate void CustomCall( )
- 有参有返回
- 自定义委托 public delegate int CustomCall(int a)
- 需要加上特性[CSharpCallLua]
- C#自带,类型 Func<int,int>(参数为一个int,返回值int)
- 自定义委托 public delegate int CustomCall(int a)
- 多返回值
- 自定义委托 public delegate int CustomCall(int a , out b , out c , out d)
- 需要加上特性[CSharpCallLua]
- 用out或者ref皆可
- 其中委托类型为第一个返回值
- 自定义委托 public delegate int CustomCall(int a , out b , out c , out d)
- 变长参数
- 自定义委托 public delegate void CustomCall(string a, params object[ ] args)
- 需要加上特性[CSharpCallLua]
- 其中object也可以改为指定类型,提高性能
- 自定义委托 public delegate void CustomCall(string a, params object[ ] args)
- 无参无返回
- List和Dictionary映射table
- 与上方一样,泛型类型为List<T>和Dictionary<T,T>
- 当有多种类型时就用object
- Class类映射table
- 自定义一个类去接收table类,同样使用Get<T>,类中属性名字要和lua中保持一致
- 浅拷贝
- Interface接口映射table
- 需要加上特性[CSharpCallLua]
- 接口只允许存在成员属性,不允许存在成员变量
- 深拷贝
- LuaTable映射table
- xLua自带的LuaTable类
- 获取后相当于一个小的大G表,继续使用Get<T>获取table里的变量
- Set为改引用
- 用完一定要table.Dispose( )
- 总结CSharpCallLua特性使用场景
- 自定义委托
- 接口
- Lua env = new LuaEvn( )
Lua调用C#
- 尽量在所有要调用的类加上[LuaCallCSharp]提升访问性能(不加也不会报错)
- 调用C#类
- CS.命名空间.类名
- 例 local obj = CS.UnityEngine.GameObject( )
- 因为Lua没有new,所以直接加上括号就是新建对象
- 为了方便使用并且节约性能,定义全局变量存储C#中的类,相当于别名using
- 例 GameObject = CS.UnityEngine.GameObject
- 调用成员方法
- 静态方法不用使用:
- 其余必须使用冒号:
- obj:AddComponent( typeof( CS.MyClass ) )
- 因为lua不支持泛型,所以使用AddComponent的重载传入Type
- 调用枚举Enum
- 使用起来跟类一样,只不过不用new
- 也可以使用下标或者字符串转换
- 枚举.__CastFrom( 下标/字符串 )
- 调用数组,List,Dictionary
- 数组
- 只能用Length获取长度,不能用#
- 下标规则为C#从0开始
- 在lua中创建数组
- array = CS.System.Array.CreateInstance(typeof(CS.System.Int32), 10)
- List
- 用Count获取长度
- 在lua中创建List
- List_String = CS.System.Collections.Genetic.List(CS.System.String)MyList = List_String( )
- 此时的List是需要new的
- Dictionary
- 在lua中创建Dictionary
- Dictionary_String_Vector3 = CS.System.Collections.Dictionary(CS.System.String, CS.UnityEngine.Vector3)MyDic = Dictionary_String_Vector3( )
- 在lua中的字典,当value为结构体类型时,不能直接使用dic[key],
- dic:get_Item(key)
- dic:set_Item(key)
- 在lua中创建Dictionary
- 数组
- 调用拓展方法
- 需要给静态工具类加上特性[LuaCallCSharp]
- ref,out
- ref
- 以多返回值形式返回给lua,需要多个变量接收
- 如果存在返回值,则是第一个值
- 需要填入参数占位
- out
- 以多返回值形式返回给lua,需要多个变量接收
- 如果存在返回值,则是第一个值
- 不需要填入参数占位
- ref
- 调用重载函数
- Lua虽然支持调用C#中的重载函数,但是本身不支持重载函数
- 因为Lua中只有Number类型,所以尽量避免使用精度重载的函数,会发生错误
- 如果非要使用精度重载函数,可以使用xLua提供的反射
- 调用委托和事件
- 委托
- 第一次往委托里添加函数,不能直接+,因为是nil,所以第一次要先=
- del = nil 清空
- del()调用
- 事件
- 事件的订阅有点像成员方法,obj:eventAction(“+”, func)
- 清空和调用都要在C#中封装方法调用
- 委托
- 使用二维数组
- Lua不支持直接array[1][1]访问数组
- 要使用方法array:GetValue(1, 1)
- nil和null区别
- unity中的判空不能直接 if obj == nil,而是obj:Equals(nil)
- 也可以在Unity中封装一个静态方法IsNull( this Object obj )
- 也可以在Lua中封装一个方法funtion IsNull( obj )
- 解决[LuaCallCSharp]和[CSharpCallLua]无法设置在系统类的问题
- public static class Tool // 静态类
{
[CSharpCallLua] // 特性
public static List<Type> list = new List<Type>() // 静态list
{
typeof(UnityAction<float>)
};
} - local slider = sliderObj:GetComponent(“UITest”).slider
slider.onValueChanged:AddListener(function (value) // 这里是把lua的方法融合到了C#方法里,所以需要CSharpCallLua,不需要LuaCallCSharp是因为已经内置了
print(value)
end)
- public static class Tool // 静态类
- lua中调用C#协程
- GameObject = CS.UnityEngine.GameObject
WaitForSeconds = CS.UnityEngine.WaitForSeconds
local util = require(“xlua/util”) // 注意这里要手动把util放在Resources并删除txt后缀
print(util)local obj = GameObject(“Coroutine”)
mono = obj:AddComponent(typeof(CS.LuaCallCSharp))function Func()
i = 0
while true do
i = i + 1
print(i)
coroutine.yield(WaitForSeconds(1))
end
endmono:StartCoroutine(util.cs_generator(Func)) // 使用util工具进行协程调用
- GameObject = CS.UnityEngine.GameObject
- 调用泛型函数
- lua只支持有参数,有约束且约束只能继承类的泛型函数
- 剩下的只能得到通用函数使用xlua.get_generic_method(根据打包方式不同会有所限制)

评论(0)
暂无评论