热更新流程简述 获取对比文件:从远程服务器下载一个用于对比的文件,该文件记录了当前可用资源的版本号或哈希值等信息。
对比本地资源和远程资源:将下载的对比文件与本地保存的对比文件进行比较,以确定本地资源和远程资源之间的差异。根据比较结果,确定需要更新的资源和需要移除的资源。
资源更新和移除:下载远程服务器上与本地资源不同的更新文件,并覆盖本地对应的资源文件,或者直接将更新的资源文件添加到本地资源目录。根据对比结果,删除本地不再需要的资源文件。
更新对比文件:将下载的远程对比文件替换本地保存的对比文件,以保持本地对比文件与服务器端一致,为下一次热更新做准备。
在 Unity 中 AssetBundle 的压缩方式有不压缩、LZMA、LZ4 三种,请问 LZMA 和 LZ4 有什么区别? 🟡 Lua 面向对象的三大特性 Lua 如何实现面向对象的三大特性
封装:可以通过 table 进行实现。在 Lua 中,我们可以将对象的属性和方法放入一个 table 中,然后对该 table 进行操作,从而达到封装的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Object = {} setmetatable (Object, Object)Object.__index = Object function Object:new () local obj = {} setmetatable (obj, self ) self .__index = self return obj end function Object:toString () return tostring (self ) end object1 = Object:new() print (object1:toString())
继承:可以通过元表(metatables)和 **index 元方法来模拟。我们可以将子类的元表设置为父类,然后将父类的 **index 指向父类自身。这样,当子类对象找不到对应的属性或方法时,就会去父类中查找,从而实现继承关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function Object:subClass (className) _G [className] = {} _G [className].base = self setmetatable (_G [className], self ) self .__index = self end Object:subClass("Animal" ) function Animal:new (animalName) local obj = Animal.base.new(self ) obj.animalName = animalName return obj end function Animal:Speak () print ("动物" ..self .animalName.."开始叫" ) end
多态:在 Lua 中可以通过子类自己实现同名方法并且使用冒号 : 来调用。当调用同名方法时,Lua 会根据对象的类型来决定调用哪个方法,从而实现多态的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Animal:subClass("Dog" ) function Dog:Speak () self .base.Speak(self ) print ("狗" ..self .animalName.."开始旺旺叫" ) end dog1 = Dog:new("Spike" ) dog1:Speak() Animal:subClass("Cat" ) function Cat:Speak () self .base.Speak(self ) print ("猫" ..self .animalName.."开始喵喵叫" ) end cat1 = Cat:new("Tom" ) cat1:Speak()
🟡 Windows 和 Android 平台上的热更新实现 如果不考虑 IOS 平台,只在 Windows 和 Android 平台上发布游戏,如何在不使用第三方热更新方案的前提下实现热更新功能?
使用热更 DLL 文件,将需要更新的游戏逻辑打包成 DLL 文件。
在游戏启动时,通过代码加载这些 DLL 文件,而不是直接编译进游戏。
利用 C# 的反射功能,动态加载并执行热更 DLL 包中的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 Assembly hotfixAssembly = Assembly.LoadFile("path/to/Hotfix.dll" ); Type hotfixType = hotfixAssembly.GetType("HotfixNamespace.HotfixClass" ); object hotfixInstance = Activator.CreateInstance(hotfixType);MethodInfo method = hotfixType.GetMethod("HotfixMethod" ); method.Invoke(hotfixInstance, null );
请说出 Lua 中常用的数据类型(至少说出 6 种) Lua 中常用的数据类型包括以下几种:
nil:表示无效值或空值。 boolean:布尔类型,有两个值:true 和 false。 number:数字类型,在 Lua 5.3 之前是双精度浮点数,在 Lua 5.3 之后支持整数和浮点数。 string:字符串类型,用于存储文本。 table:表类型,用于表示关联数组,可以用作数组、字典等。 function:函数类型,可以存储并调用函数。
此外,还有两种较为高级的类型: userdata:用户数据类型,用于表示 C 数据结构。 thread:线程类型,用于表示协同程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 local a = nil local b = true local c = false local d = 123 local e = 45.67 local f = "Hello, Lua!" local g = { key1 = "value1" , key2 = "value2" }g[3 ] = "value3" local function h () print ("This is a function" ) end local i = newproxy(true )local j = coroutine .create (function () print ("This is a coroutine" ) end )print (type (a)) print (type (b)) print (type (d)) print (type (f)) print (type (g)) print (type (h)) print (type (i)) print (type (j))
Lua 中 pairs 和 ipairs 的区别 正常情况下,ipairs 和 pairs 在遍历数组时没有任何区别。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 local tbl1 = { "apple" , "pear" , "orange" , "grape" }print ("=============ipairs的执行结果=============" )for i, v in ipairs (tbl1) do print (i, '=' , v) end print ("=============pairs的执行结果==============" )for i, v in pairs (tbl1) do print (i, '=' , v) end =============ipairs 的执行结果============= 1 = apple2 = pear3 = orange4 = grape=============pairs 的执行结果============== 1 = apple2 = pear3 = orange4 = grape
当我们使用自定义的键值时,通过 pairs 和 ipairs 的输出结果会有所不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 local tbl2 = {}tbl2[1 ] = "1" tbl2[2 ] = "2" tbl2[3 ] = "3" tbl2[5 ] = "5" print ("=============ipairs的执行结果=============" )for i, v in ipairs (tbl2) do print (i, '=' , v) end print ("=============pairs的执行结果=============" )for i, v in pairs (tbl2) do print (i, '=' , v) end print ('tbl2的长度为:' , #tbl2) =============ipairs 的执行结果============= 1 = 1 2 = 2 3 = 3 =============pairs 的执行结果============= 1 = 1 2 = 2 3 = 3 5 = 5 tbl2的长度为: 3
从以上可以发现,ipairs 会依据键值从 1 开始加 1 递增遍历相应的 table 值。而 pairs 则能够遍历表中全部的键值,并且还能够返回 nil。ipairs 不能返回 nil,仅能返回数字 0,遇到 nil 则循环退出。它仅能遍历到表中出现的第一个不是整数的键值。
当我们获取 table 的长度时,无论是使用#还是 table.getn,都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度。要正确求得 table 的长度,可以参考以下代码:
1 2 3 4 5 6 7 8 9 10 function tableLength (tbl) local count = 0 for _ in pairs (tbl) do count = count + 1 end return count end local tbl2 = {1 , 2 , 3 , nil , 5 }print ("Table长度为:" , tableLength(tbl2))
Lua 中常用的元方法有哪些?至少说出 3 个原方法 Lua 中的元方法(metamethod)是一种特殊的函数,可以在特定操作发生时被调用,以实现自定义行为。以下是一些常用的元方法及其说明:
__index: 当试图访问一个表中不存在的字段时,会调用该方法。 用于实现表的继承或默认值。
__newindex: 当试图给一个表中不存在的字段赋值时,会调用该方法。 用于控制对表的更新操作。
__tostring: 当试图将一个表转换为字符串时,会调用该方法。 用于自定义表的字符串表示形式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 local metatable = {}metatable.__index = function (table, key) return "默认值" end metatable.__newindex = function (table, key, value) rawset (table , key, value) print ("设置新键值对: " .. key .. " = " .. value) end metatable.__tostring = function (table) return "这是一个自定义表" end local myTable = setmetatable ({}, metatable)print (myTable.nonExistentKey) myTable.newKey = "新值" print (myTable)
Lua 中元表的作用 在 Lua 中,元表(Metatable)是用于改变或扩展表(table)行为的一种机制。为一个表设置元表后,允许该表的行为关联元方法,从而实现定制化的操作。元表的使用可以让我们定义自定义的运算符行为、实现面向对象编程等。
元表的基本用法 元表可以通过设置特定的元方法来实现定制行为。下面是一个简单的示例,展示如何使用元表来实现两个表的相加操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 local table1 = {value = 10 }local table2 = {value = 20 }local metatable = { __add = function (t1, t2) return {value = t1.value + t2.value} end } setmetatable (table1, metatable)setmetatable (table2, metatable)local result = table1 + table2print (result.value)
Lua 中 __index 和 __newindex 有什么作用 在 Lua 中, __index 和 __newindex 是元表(metatable)中用于控制表(table)行为的重要字段。它们主要用于对表进行自定义操作,如查找和更新不存在的键值对。以下是它们的详细说明:
__index 用于查找
__index 用于查找。如果访问一个表中不存在的字段,Lua 会在元表中查找__index 方法,并调用它来提供最终结果。
1 2 3 4 5 6 7 8 9 10 11 12 local myTable = {} local myMetatable = { __index = function (table, key) return key .. " not found" end } setmetatable (myTable, myMetatable) print (myTable.name) print (myTable.age)
__newindex 用于更新
__newindex 用于更新。如果对一个表中不存在的字段进行赋值操作,Lua 会调用元表中的__newindex 方法来处理赋值操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 local myTable = {} local myMetatable = { __newindex = function (table, key, value) print ("Setting " .. key .. " to " .. value) rawset (table , key, value) end } setmetatable (myTable, myMetatable) myTable.name = "Lua" myTable.age = 25 print (myTable.name) print (myTable.age)
在上述代码中,当对 myTable 中不存在的键进行赋值时,__newindex 方法会打印赋值信息并将值设置到表中。
总结 __index 用于查找:当访问一个表中不存在的键时,由__index 提供最终结果。 __newindex 用于更新:当对一个表中不存在的键进行赋值时,由__newindex 处理赋值操作。
Unity 热更新解决方案中,Lua 和 ILRuntime 方案的本质是什么? lua 语言中的 upvalue 是什么?