• [unity]lua热更新——个人复习笔记【侵删/有不足之处欢迎斧正】


    一、AssetBundle

    AB包是特定于平台的资产压缩包,类似于压缩文件

    相对于RESOURCES下的资源,AB包更加灵活轻量化,用于减小包体大小和热更新

    可以在unity2019环境中直接下载Asset Bundle Browser

    可以在其中设置关联

    AB包生成的文件

    AB包文件:资源文件
    manifest文件:AB包文件信息;当加载时,提供了关键信息,资源信息,依赖关系,版本信息等等
    关键AB包(和目录名一样的包 )

    AB包资源加载

    1. void Start(){
    2. //加载AB包
    3. AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/"+"model");
    4. //加载AB包中的资源
    5. //只用名字加载那么会出现同名同类型资源混乱
    6. GameObject obj = ab.LoadAsset("Cube");
    7. }

    AB包依赖

    关于AB包的依赖一一个资源身 上用到了别的AB包中的资源这个时候如果只加载自己的AB包,通过它创建对象会出现资源丢失的情况,这种时候需要把依赖包-起加载了才能正常

    可以考虑利用主包获取信息

    1. //加载AB包
    2. AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath+"/"+"model");
    3. //加载主包和其中的固定文件
    4. AssetBundle abMain = AssetBundle.LoadFromFile(Application.streamingAssetsPath +"/"+"PC");
    5. AssetBundleManifest abManifest=abMain.LoadAsset("AssetBundleManifest");

    AB包资源加载管理器

    1. public class ABMgr : SingletonAutoMono<ABMgr>
    2. {
    3. //主包
    4. private AssetBundle mainAB = null;
    5. //主包依赖获取配置文件
    6. private AssetBundleManifest manifest = null;
    7. //选择存储 AB包的容器
    8. //AB包不能够重复加载 否则会报错
    9. //字典知识 用来存储 AB包对象
    10. private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();
    11. private string PathUrl
    12. {
    13. get
    14. {
    15. return Application.streamingAssetsPath + "/";
    16. }
    17. }
    18. private string MainName
    19. {
    20. get
    21. {
    22. #if UNITY_IOS
    23. return "IOS";
    24. #elif UNITY_ANDROID
    25. return "Android";
    26. #else
    27. return "PC";
    28. #endif
    29. }
    30. }
    31. private void LoadMainAB()
    32. {
    33. if( mainAB == null )
    34. {
    35. mainAB = AssetBundle.LoadFromFile( PathUrl + MainName);
    36. manifest = mainAB.LoadAsset("AssetBundleManifest");
    37. }
    38. }
    39. private void LoadDependencies(string abName)
    40. {
    41. //加载主包
    42. LoadMainAB();
    43. //获取依赖包
    44. string[] strs = manifest.GetAllDependencies(abName);
    45. for (int i = 0; i < strs.Length; i++)
    46. {
    47. if (!abDic.ContainsKey(strs[i]))
    48. {
    49. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);
    50. abDic.Add(strs[i], ab);
    51. }
    52. }
    53. }
    54. public T LoadRes<T>(string abName, string resName) where T:Object
    55. {
    56. //加载依赖包
    57. LoadDependencies(abName);
    58. //加载目标包
    59. if ( !abDic.ContainsKey(abName) )
    60. {
    61. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    62. abDic.Add(abName, ab);
    63. }
    64. //得到加载出来的资源
    65. T obj = abDic[abName].LoadAsset(resName);
    66. //如果是GameObject 因为GameObject 100%都是需要实例化的
    67. //所以我们直接实例化
    68. if (obj is GameObject)
    69. return Instantiate(obj);
    70. else
    71. return obj;
    72. }
    73. public Object LoadRes(string abName, string resName, System.Type type)
    74. {
    75. //加载依赖包
    76. LoadDependencies(abName);
    77. //加载目标包
    78. if (!abDic.ContainsKey(abName))
    79. {
    80. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    81. abDic.Add(abName, ab);
    82. }
    83. //得到加载出来的资源
    84. Object obj = abDic[abName].LoadAsset(resName, type);
    85. //如果是GameObject 因为GameObject 100%都是需要实例化的
    86. //所以我们直接实例化
    87. if (obj is GameObject)
    88. return Instantiate(obj);
    89. else
    90. return obj;
    91. }
    92. public Object LoadRes(string abName, string resName)
    93. {
    94. //加载依赖包
    95. LoadDependencies(abName);
    96. //加载目标包
    97. if (!abDic.ContainsKey(abName))
    98. {
    99. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    100. abDic.Add(abName, ab);
    101. }
    102. //得到加载出来的资源
    103. Object obj = abDic[abName].LoadAsset(resName);
    104. //如果是GameObject 因为GameObject 100%都是需要实例化的
    105. //所以我们直接实例化
    106. if (obj is GameObject)
    107. return Instantiate(obj);
    108. else
    109. return obj;
    110. }
    111. public void LoadResAsync<T>(string abName, string resName, UnityAction callBack) where T:Object
    112. {
    113. StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
    114. }
    115. //正儿八经的 协程函数
    116. private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction callBack) where T : Object
    117. {
    118. //加载依赖包
    119. LoadDependencies(abName);
    120. //加载目标包
    121. if (!abDic.ContainsKey(abName))
    122. {
    123. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    124. abDic.Add(abName, ab);
    125. }
    126. //异步加载包中资源
    127. AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName);
    128. yield return abq;
    129. if (abq.asset is GameObject)
    130. callBack(Instantiate(abq.asset) as T);
    131. else
    132. callBack(abq.asset as T);
    133. }
    134. public void LoadResAsync(string abName, string resName, System.Type type, UnityAction callBack)
    135. {
    136. StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));
    137. }
    138. private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction callBack)
    139. {
    140. //加载依赖包
    141. LoadDependencies(abName);
    142. //加载目标包
    143. if (!abDic.ContainsKey(abName))
    144. {
    145. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    146. abDic.Add(abName, ab);
    147. }
    148. //异步加载包中资源
    149. AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName, type);
    150. yield return abq;
    151. if (abq.asset is GameObject)
    152. callBack(Instantiate(abq.asset));
    153. else
    154. callBack(abq.asset);
    155. }
    156. public void LoadResAsync(string abName, string resName, UnityAction callBack)
    157. {
    158. StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));
    159. }
    160. private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction callBack)
    161. {
    162. //加载依赖包
    163. LoadDependencies(abName);
    164. //加载目标包
    165. if (!abDic.ContainsKey(abName))
    166. {
    167. AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);
    168. abDic.Add(abName, ab);
    169. }
    170. //异步加载包中资源
    171. AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName);
    172. yield return abq;
    173. if (abq.asset is GameObject)
    174. callBack(Instantiate(abq.asset));
    175. else
    176. callBack(abq.asset);
    177. }
    178. //卸载AB包的方法
    179. public void UnLoadAB(string name)
    180. {
    181. if( abDic.ContainsKey(name) )
    182. {
    183. abDic[name].Unload(false);
    184. abDic.Remove(name);
    185. }
    186. }
    187. //清空AB包的方法
    188. public void ClearAB()
    189. {
    190. AssetBundle.UnloadAllAssetBundles(false);
    191. abDic.Clear();
    192. //卸载主包
    193. mainAB = null;
    194. }
    195. }
    196. 二、lua基础语法

      第一个lua程序

      1. print("你好世界");
      2. --单行注释
      3. --lua语句可以省略分号
      4. --[[
      5. 多行数据
      6. ]]
      7. --[[
      8. 多行数据
      9. ]]--
      10. --[[
      11. 还是多行数据
      12. --]]

      lua的变量(lua中所有的变量声明都不需要申明类型,会自动的判断类型)

      简单变量类型:nil number string boolean

      nil 相当于空的概念

      number 所有的数值都是number(lua中的一个变量可以随便赋值)

      string 字符串类型,字符串的声明需要用单双引号包裹,lua中无char类型

      boolean 真或假

      可以通过type获得变量类型,其返回值是string类型

      注意:lua中使用没有声明过的变量不会报错,其值是空

      其他数据类型:function table userdata thread

      字符串操作

      1. s="5464565655"
      2. print(#s)
      3. --获取字符串长度
      4. --中文字符在lua中占三个长度
      1. --多行打印
      2. --lua中支持转义字符
      3. print("123\n123")
      4. s =[[hello
      5. world
      6. ]]
      1. --字符串拼接
      2. print("1323".."65456")

      注意lua字符串索引开始都是从1开始的,而不是从0开始

       运算符

      算术运算符:+-*/%^

      与c#中基本相同,但是需要注意lua中无++ -- += *= %= -=

      (字符串可以进行算数运算符的惭怍 会自动转成number)

      lua中^是幂运算

      条件运算符:> < <= == ~=

      ~= Lua中的不等于 相当于C#中的!=

      逻辑运算符

      &&  ||  (c#)

      and or  (lua)

      not  取反

      lua中and和or支持短路原则

      位运算符(不支持)

      三目运算符(不支持)

      条件分支语句

      1. print("条件分支语句")
      2. -- if 条件 then ... end
      3. if a > 6 then
      4. print("666")
      5. elseif a == 999 then
      6. print("123")
      7. else
      8. print("555")
      9. end

      在lua中没有switch语句

      循环语句

      1. num = 0
      2. --while
      3. while num <555 do
      4. print(num)
      5. num =num +1
      6. end
      7. --do while
      8. repeat
      9. print(num)
      10. until num>555
      11. --满足条件跳出,不同于C#中的进入条件
      12. --for语句
      13. for i =1,5 do
      14. print(i)
      15. end
      16. for i =1,5,2 do
      17. print(i)
      18. end

      函数

      function 函数名()

      end

      不同于c#,函数在声明之前,不能调用

      无参无返回值

      1. F2 = function()
      2. print("F1hanshu")
      3. end
      4. F2()

      有参有返回值

      1. F2 = function(a)
      2. print(a)
      3. end
      4. F2(1)
      5. F2()
      6. --不传参数,默认为空

      如果传入的参数和函数参数个数不匹配,不会报错,只会补nil或者丢弃参数

      1. F2 = function(a)
      2. return a ,"123",false
      3. end
      4. tt = F2(a)

      多返回值时,在前面申明多个变量来截取,变量不够会接取对应位置的返回值

      函数的类型

      1. F2 = function()
      2. print("F1hanshu")
      3. end
      4. F2()
      5. print(type(F2))

      函数的重载

      LUA中不支持函数的重载

      变长参数

      1. F2 = function(...)
      2. print("F1hanshu")
      3. end
      4. F2()

      变长参数使用 先用一个表存起来 再来使用

      函数嵌套

      1. F2 = function()
      2. F6 =function()
      3. print(666);
      4. end
      5. return F9
      6. print("F1hanshu")
      7. end
      8. f9 =F2()
      9. f9()

      table表实现数组

      所有的复杂类型本质上都是Table

      数组:

      1. a ={1,2,3,true,nil,"9916"}
      2. print(a[1])
      3. --lua中的索引从1开始

      获取数组长度

      1. --#是通用的获取长度的关键字
      2. --在打印长度时,nil和其数组后面的数据将会被省略

      自定义索引:

      1. aa ={[0]=1,2,3,[-5]=4,5}
      2. print(aa[-5])
      3. print(#aa)
      4. --输出为4 3

       迭代器遍历

      主要是用于遍历表

      #得到的长度,其实是不准确的 一般不会使用#来遍历表

      1. aa ={[0]=1,2,3,[-5]=4,5}
      2. --ipairs
      3. for i ,k in ipairs(aa) do
      4. print(i..k)
      5. end

      ipairs遍历还是从1开始遍历,小于等于0的值得不到,只能找到连续连续索引的键值

      1. aa ={[0]=1,2,3,[-5]=4,5}
      2. --pairs
      3. for i ,v in pairs(aa) do
      4. print(i..v)
      5. end
      6. --能把所有键都找到 通过键找到值

      table表现字典

      1. --字典的声明
      2. a = {["name"]="Name",["anme"]=5}
      3. print(a["name"])
      4. --还可以类似.成员变量的形式得到值,但是不能是数字
      5. print(a.name)
      6. --字典新增
      7. a["newnew"]=666
      8. --模拟字典 遍历一定要使用pairs
      9. for k,v in pairs(a) do
      10. --可以穿多个参数 一样可以打印出来
      11. print(k,v)
      12. end
      13. for _,v in pairs(a) do
      14. --遍历值
      15. print(v)
      16. end

      table实现类

      lua中默认没有面向对象,需要自己去实现

      1. Student ={
      2. age =1,
      3. sex=true,
      4. Up=function function_name( )
      5. -- body
      6. print("函数")
      7. end
      8. }
      9. print(Student.age)
      10. Student.Up()

      lua中.和:的区别在于,:调用方法时,会默认把调用者作为第一个参数传入方法中

      表的公共操作

      1. a = {{age =1 ,name ="123"},{age =2 ,name="456"}}
      2. b={name ="54645",sex=false}
      3. --插入
      4. table.insert(a,b);
      5. --在a表中加入b
      6. --删除指定元素
      7. --移除最后一个索引的内容
      8. table.remove(a)
      9. --排序算法
      10. t={5,9,54,5,7}
      11. table.sort(t)

      多脚本执行

      全局变量与本地变量

      1. --全局变量与本地变量
      2. a = 1
      3. b = 1
      4. --以上都是全局变量
      5. for i=1,2 do
      6. c=1
      7. end
      8. --c还是全局变量
      9. --本地变量的关键字是 local
      10. fun =function()
      11. tt="123123"
      12. end
      13. fun()
      14. print(tt)--能正常输出,是全局变量

      多脚本执行

      全局变量,只要执行过后,可以在任何脚本中进行调用

      脚本卸载

      如果是require("")加载执行的脚本,加载一次过后不会再执行

      可以利用package.loaded["脚本名"]来判断脚本是否被执行

      大G表

      是一个总表,将我们声明的全部全局变量都储存在其中,本地变量不会存储

      LUA的特殊用法

      多变量赋值

      1. l,g,c = 1 ,2 ,true
      2. l,g,c=1,2
      3. --多变量赋值后面的值不够会自动补空,多了会自动省略

      多返回值

      1. function Test()
      2. return 10,20,30
      3. end
      4. a,b,c =Test()

      and 与 or

      在lua中只有 nil 和 false才会被认为是假

      lua模拟三目运算符

      local res = (x>y) and x or b

      协同程序

      1. --coroutine.create()
      2. fun = function()
      3. print(123)
      4. end
      5. --协程本质上是一个线程对象
      6. lu=coroutine.create(fun)
      7. --coroutine.wrap()
      8. ji = coroutine.wrap(fun)
      9. --协程运行
      10. coroutine.resume(lu)
      11. ji()
      12. --协程的挂起
      13. fun2=function()
      14. while true do
      15. print(123)
      16. --挂起函数
      17. coroutine.yield()
      18. end
      19. end
      20. peng =coroutine.create(fun2)
      21. coroutine.resume(peng)

      元表

      任何表对象都可以作为另一个表变量的元表

      当对子表中进行特定操作时,会执行元表中的内容

      1. mega = {
      2. --当子表要被当作字符串使用时,会默认调用元表中的tostring方法
      3. __tostring =function(t)
      4. return t.name
      5. end,
      6. --当子表被当作一个函数使用时,会默认调用__call中的内容
      7. __call =function(a,b)
      8. print(a)
      9. print(b)
      10. --默认第一个参数是调用自己
      11. end
      12. }
      13. myMega = {
      14. name = "666"
      15. }
      16. --设置元表函数
      17. --第一个为子表,第二个为夫表
      18. setmetatable(myMega,mega)
      19. print(myMega)

      LUA自带库

      1. --系统时间
      2. print(os.time())
      3. print(os.time({year=2014,month=8,day=14}))
      4. local nowTime =os.data("*t")
      5. --可以得到更多的信息
      6. --数学运算
      7. print(math.abs(-1555))
      8. --弧度转角度
      9. print(math.deg(math.pi))
      10. --向下取整
      11. print(math.floor(-1555))
      12. --最小值
      13. print(math.min(-1555,999))
      14. --小数分离
      15. print(math.modf(1.5555))
      16. --随机数
      17. math.randomseed(os.time())
      18. print(math.random(100))
      19. --路径
      20. print(package.path)
      21. --打印LUA脚本加载路径

      垃圾回收

      1. --垃圾回收
      2. lu={id=1,idd=2}
      3. collectgarbage("count")
      4. --获取当前lua占用内存数,返回千字节单位
      5. --进行垃圾回收
      6. collectgarbage("collect")
      7. print(collectgarbage("count"))--lua的垃圾回收机制和c#中类似,取消羁绊便成为垃圾
      8. --lua中有自动计时垃圾回收的方法,但不推荐在项目中使用

    197. 相关阅读:
      upload-labs关卡9(基于win特性data流绕过)通关思路
      Ajax的简单使用
      Python程序设计实例 | 爬取机场航班信息
      AdaBoost:提升机器学习的力量
      Golang笔记|Atomic
      linux-log系统日志输出等级
      阿里无影云电脑 试用评测
      想做扫码看图效果,你需要学会这一招
      WebGL编程指南-23 光照原理、漫反射光计算、漫反射光照射下的立方体
      《Java基础知识》Java 浅拷贝与深拷贝2
    198. 原文地址:https://blog.csdn.net/m0_73952999/article/details/136274174