一、AssetBundle
AB包是特定于平台的资产压缩包,类似于压缩文件
相对于RESOURCES下的资源,AB包更加灵活轻量化,用于减小包体大小和热更新
可以在unity2019环境中直接下载Asset Bundle Browser
可以在其中设置关联
AB包生成的文件
AB包文件:资源文件
manifest文件:AB包文件信息;当加载时,提供了关键信息,资源信息,依赖关系,版本信息等等
关键AB包(和目录名一样的包 )
AB包资源加载
void Start(){
//加载AB包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/"+"model");
//加载AB包中的资源
//只用名字加载那么会出现同名同类型资源混乱
GameObject obj = ab.LoadAsset<GameObject>("Cube");
}
AB包依赖
关于AB包的依赖一一个资源身 上用到了别的AB包中的资源这个时候如果只加载自己的AB包,通过它创建对象会出现资源丢失的情况,这种时候需要把依赖包-起加载了才能正常
可以考虑利用主包获取信息
//加载AB包
AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/"+"model");
//加载主包和其中的固定文件
AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath +"/"+"PC");
AssetBundleManifest abManifest=abMain.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
AB包资源加载管理器
public class ABMgr : SingletonAutoMono<ABMgr>
{
//主包
private AssetBundle mainAB = null;
//主包依赖获取配置文件
private AssetBundleManifest manifest = null;
//选择存储 AB包的容器
//AB包不能够重复加载 否则会报错
//字典知识 用来存储 AB包对象
private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
private string PathUrl
{
get
{
return Application.streamingAssetsPath + "/";
}
}
private string MainName
{
get
{
#if UNITY_IOS
return "IOS";
#elif UNITY_ANDROID
return "Android";
#else
return "PC";
#endif
}
}
private void LoadMainAB()
{
if( mainAB == null )
{
mainAB = AssetBundle.LoadFromFile( PathUrl + MainName);
manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
}
}
private void LoadDependencies(string abName)
{
//加载主包
LoadMainAB();
//获取依赖包
string[] strs = manifest.GetAllDependencies(abName);
for (int i = 0; i < strs.Length; i++)
{
if (!abDic.ContainsKey(strs[i]))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
abDic.Add(strs[i], ab);
}
}
}
public T LoadRes<T>(string abName, string resName) where T:Object
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if ( !abDic.ContainsKey(abName) )
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//得到加载出来的资源
T obj = abDic[abName].LoadAsset<T>(resName);
//如果是GameObject 因为GameObject 100%都是需要实例化的
//所以我们直接实例化
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
public Object LoadRes(string abName, string resName, System.Type type)
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if (!abDic.ContainsKey(abName))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//得到加载出来的资源
Object obj = abDic[abName].LoadAsset(resName, type);
//如果是GameObject 因为GameObject 100%都是需要实例化的
//所以我们直接实例化
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
public Object LoadRes(string abName, string resName)
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if (!abDic.ContainsKey(abName))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//得到加载出来的资源
Object obj = abDic[abName].LoadAsset(resName);
//如果是GameObject 因为GameObject 100%都是需要实例化的
//所以我们直接实例化
if (obj is GameObject)
return Instantiate(obj);
else
return obj;
}
public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T:Object
{
StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));
}
//正儿八经的 协程函数
private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if (!abDic.ContainsKey(abName))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//异步加载包中资源
AssetBundleRequest abq = abDic[abName].LoadAssetAsync<T>(resName);
yield return abq;
if (abq.asset is GameObject)
callBack(Instantiate(abq.asset) as T);
else
callBack(abq.asset as T);
}
public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack)
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if (!abDic.ContainsKey(abName))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//异步加载包中资源
AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName, type);
yield return abq;
if (abq.asset is GameObject)
callBack(Instantiate(abq.asset));
else
callBack(abq.asset);
}
public void LoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
}
private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack)
{
//加载依赖包
LoadDependencies(abName);
//加载目标包
if (!abDic.ContainsKey(abName))
{
AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
abDic.Add(abName, ab);
}
//异步加载包中资源
AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName);
yield return abq;
if (abq.asset is GameObject)
callBack(Instantiate(abq.asset));
else
callBack(abq.asset);
}
//卸载AB包的方法
public void UnLoadAB(string name)
{
if( abDic.ContainsKey(name) )
{
abDic[name].Unload(false);
abDic.Remove(name);
}
}
//清空AB包的方法
public void ClearAB()
{
AssetBundle.UnloadAllAssetBundles(false);
abDic.Clear();
//卸载主包
mainAB = null;
}
}
二、lua基础语法
第一个lua程序
print("你好世界");
--单行注释
--lua语句可以省略分号
--[[
多行数据
]]
--[[
多行数据
]]--
--[[
还是多行数据
--]]
lua的变量(lua中所有的变量声明都不需要申明类型,会自动的判断类型)
简单变量类型:nil number string boolean
nil 相当于空的概念
number 所有的数值都是number(lua中的一个变量可以随便赋值)
string 字符串类型,字符串的声明需要用单双引号包裹,lua中无char类型
boolean 真或假
可以通过type获得变量类型,其返回值是string类型
注意:lua中使用没有声明过的变量不会报错,其值是空
其他数据类型:function table userdata thread
字符串操作
s="5464565655"
print(#s)
--获取字符串长度
--中文字符在lua中占三个长度
--多行打印
--lua中支持转义字符
print("123\n123")
s =[[hello
world
]]
--字符串拼接
print("1323".."65456")
注意lua字符串索引开始都是从1开始的,而不是从0开始
运算符
算术运算符:+-*/%^
与c#中基本相同,但是需要注意lua中无++ -- += *= %= -=
(字符串可以进行算数运算符的惭怍 会自动转成number)
lua中^是幂运算
条件运算符:> < <= == ~=
~= Lua中的不等于 相当于C#中的!=
逻辑运算符
&& || (c#)
and or (lua)
not 取反
lua中and和or支持短路原则
位运算符(不支持)
三目运算符(不支持)
条件分支语句
print("条件分支语句")
-- if 条件 then ... end
if a > 6 then
print("666")
elseif a == 999 then
print("123")
else
print("555")
end
在lua中没有switch语句
循环语句
num = 0
--while
while num <555 do
print(num)
num =num +1
end
--do while
repeat
print(num)
until num>555
--满足条件跳出,不同于C#中的进入条件
--for语句
for i =1,5 do
print(i)
end
for i =1,5,2 do
print(i)
end
函数
function 函数名()
end
不同于c#,函数在声明之前,不能调用
无参无返回值
F2 = function()
print("F1hanshu")
end
F2()
有参有返回值
F2 = function(a)
print(a)
end
F2(1)
F2()
--不传参数,默认为空
如果传入的参数和函数参数个数不匹配,不会报错,只会补nil或者丢弃参数
F2 = function(a)
return a ,"123",false
end
tt = F2(a)
多返回值时,在前面申明多个变量来截取,变量不够会接取对应位置的返回值
函数的类型
F2 = function()
print("F1hanshu")
end
F2()
print(type(F2))
函数的重载
LUA中不支持函数的重载
变长参数
F2 = function(...)
print("F1hanshu")
end
F2()
变长参数使用 先用一个表存起来 再来使用
函数嵌套
F2 = function()
F6 =function()
print(666);
end
return F9
print("F1hanshu")
end
f9 =F2()
f9()
table表实现数组
所有的复杂类型本质上都是Table
数组:
a ={1,2,3,true,nil,"9916"}
print(a[1])
--lua中的索引从1开始
获取数组长度
--#是通用的获取长度的关键字
--在打印长度时,nil和其数组后面的数据将会被省略
自定义索引:
aa ={[0]=1,2,3,[-5]=4,5}
print(aa[-5])
print(#aa)
--输出为4 3
迭代器遍历
主要是用于遍历表
#得到的长度,其实是不准确的 一般不会使用#来遍历表
aa ={[0]=1,2,3,[-5]=4,5}
--ipairs
for i ,k in ipairs(aa) do
print(i..k)
end
ipairs遍历还是从1开始遍历,小于等于0的值得不到,只能找到连续连续索引的键值
aa ={[0]=1,2,3,[-5]=4,5}
--pairs
for i ,v in pairs(aa) do
print(i..v)
end
--能把所有键都找到 通过键找到值
table表现字典
--字典的声明
a = {["name"]="Name",["anme"]=5}
print(a["name"])
--还可以类似.成员变量的形式得到值,但是不能是数字
print(a.name)
--字典新增
a["newnew"]=666
--模拟字典 遍历一定要使用pairs
for k,v in pairs(a) do
--可以穿多个参数 一样可以打印出来
print(k,v)
end
for _,v in pairs(a) do
--遍历值
print(v)
end
table实现类
lua中默认没有面向对象,需要自己去实现
Student ={
age =1,
sex=true,
Up=function function_name( )
-- body
print("函数")
end
}
print(Student.age)
Student.Up()
lua中.和:的区别在于,:调用方法时,会默认把调用者作为第一个参数传入方法中
表的公共操作
a = {{age =1 ,name ="123"},{age =2 ,name="456"}}
b={name ="54645",sex=false}
--插入
table.insert(a,b);
--在a表中加入b
--删除指定元素
--移除最后一个索引的内容
table.remove(a)
--排序算法
t={5,9,54,5,7}
table.sort(t)
多脚本执行
全局变量与本地变量
--全局变量与本地变量
a = 1
b = 1
--以上都是全局变量
for i=1,2 do
c=1
end
--c还是全局变量
--本地变量的关键字是 local
fun =function()
tt="123123"
end
fun()
print(tt)--能正常输出,是全局变量
多脚本执行
全局变量,只要执行过后,可以在任何脚本中进行调用
脚本卸载
如果是require("")加载执行的脚本,加载一次过后不会再执行
可以利用package.loaded["脚本名"]来判断脚本是否被执行
大G表
是一个总表,将我们声明的全部全局变量都储存在其中,本地变量不会存储
LUA的特殊用法
多变量赋值
l,g,c = 1 ,2 ,true
l,g,c=1,2
--多变量赋值后面的值不够会自动补空,多了会自动省略
多返回值
function Test()
return 10,20,30
end
a,b,c =Test()
and 与 or
在lua中只有 nil 和 false才会被认为是假
lua模拟三目运算符
local res = (x>y) and x or b
协同程序
--coroutine.create()
fun = function()
print(123)
end
--协程本质上是一个线程对象
lu=coroutine.create(fun)
--coroutine.wrap()
ji = coroutine.wrap(fun)
--协程运行
coroutine.resume(lu)
ji()
--协程的挂起
fun2=function()
while true do
print(123)
--挂起函数
coroutine.yield()
end
end
peng =coroutine.create(fun2)
coroutine.resume(peng)
元表
任何表对象都可以作为另一个表变量的元表
当对子表中进行特定操作时,会执行元表中的内容
mega = {
--当子表要被当作字符串使用时,会默认调用元表中的tostring方法
__tostring =function(t)
return t.name
end,
--当子表被当作一个函数使用时,会默认调用__call中的内容
__call =function(a,b)
print(a)
print(b)
--默认第一个参数是调用自己
end
}
myMega = {
name = "666"
}
--设置元表函数
--第一个为子表,第二个为夫表
setmetatable(myMega,mega)
print(myMega)
LUA自带库
--系统时间
print(os.time())
print(os.time({year=2014,month=8,day=14}))
local nowTime =os.data("*t")
--可以得到更多的信息
--数学运算
print(math.abs(-1555))
--弧度转角度
print(math.deg(math.pi))
--向下取整
print(math.floor(-1555))
--最小值
print(math.min(-1555,999))
--小数分离
print(math.modf(1.5555))
--随机数
math.randomseed(os.time())
print(math.random(100))
--路径
print(package.path)
--打印LUA脚本加载路径
垃圾回收
--垃圾回收
lu={id=1,idd=2}
collectgarbage("count")
--获取当前lua占用内存数,返回千字节单位
--进行垃圾回收
collectgarbage("collect")
print(collectgarbage("count"))--lua的垃圾回收机制和c#中类似,取消羁绊便成为垃圾
--lua中有自动计时垃圾回收的方法,但不推荐在项目中使用