This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
集合代理组件用于基于集合文件内容动态加载和卸载新的游戏”世界”。它们可以用来实现游戏关卡之间的切换、GUI屏幕、在关卡中加载和卸载叙事”场景”、加载/卸载迷你游戏等等。
Defold将所有游戏对象组织在集合中。一个集合可以包含游戏对象和其他集合(即子集合)。集合代理允许您将内容拆分为单独的集合,然后通过脚本动态管理这些集合的加载和卸载。
集合代理与集合工厂组件不同。集合工厂将集合的内容实例化到当前游戏世界中。集合代理在运行时创建一个新的游戏世界,因此有不同的用例。
通过右键点击游戏对象并从上下文菜单中选择Add Component ▸ Collection Proxy,将集合代理组件添加到游戏对象。
将Collection属性设置为您希望稍后动态加载到运行时中的集合的引用。该引用是静态的,确保所引用集合的所有内容最终都会出现在游戏中。
(您可以通过勾选Exclude框并使用实时更新功能在构建中排除内容,然后通过代码下载。)
当Defold引擎启动时,它会从引导集合加载并实例化所有游戏对象到运行时。然后初始化并启用游戏对象及其组件。引擎应该使用哪个引导集合是在项目设置中设置的。按照惯例,这个集合文件通常命名为”main.collection”。
为了容纳游戏对象及其组件,引擎为整个”游戏世界”分配所需的内存,引导集合的内容被实例化到这个世界中。还为任何碰撞对象和物理模拟创建了一个单独的物理世界。
由于脚本组件需要能够处理游戏中的所有对象,即使是来自引导世界之外的对象,它被赋予一个唯一的名称:您在集合文件中设置的Name属性:
如果加载的集合包含集合代理组件,那些代理引用的集合不会被自动加载。您需要通过脚本控制这些资源的加载。
通过代理动态加载集合是通过从脚本向代理组件发送名为"load"
的消息来完成的:
-- 告诉代理 "myproxy" 开始加载。
msg.post("#myproxy", "load")
代理组件将指示引擎为新世界分配空间。还会创建一个单独的运行时物理世界,并且集合"mylevel.collection"
中的所有游戏对象都被实例化。
新世界从集合文件中的Name属性获取其名称,在本示例中设置为"mylevel"
。名称必须是唯一的。如果在集合文件中设置的Name已被用于已加载的世界,引擎将发出名称冲突错误:
ERROR:GAMEOBJECT: The collection 'default' could not be created since there is already a socket with the same name.
WARNING:RESOURCE: Unable to create resource: build/default/mylevel.collectionc
ERROR:GAMESYS: The collection /mylevel.collectionc could not be loaded.
当引擎完成加载集合后,集合代理组件将向发送"load"
消息的脚本发送一个名为"proxy_loaded"
的消息。然后脚本可以初始化并启用集合作为对该消息的响应:
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_loaded") then
-- 新世界已加载。初始化并启用它。
msg.post(sender, "init")
msg.post(sender, "enable")
...
end
end
"load"
"proxy_loaded"
的消息。"async_load"
"proxy_loaded"
的消息。"init"
init()
函数。"enable"
在集合文件属性中设置的Name用于定位已加载世界中的游戏对象和组件。例如,如果您在引导集合中创建了一个加载器对象,您可能需要从任何已加载的集合中与它通信:
-- 告诉加载器加载下一关:
msg.post("main:/loader#script", "load_level", { level_id = 2 })
如果您需要从加载器与已加载集合中的游戏对象通信,您可以使用对象的完整URL发送消息:
msg.post("mylevel:/myobject", "hello")
无法从集合外部直接访问已加载集合中的游戏对象:
local position = go.get_position("mylevel:/myobject")
-- loader.script:42: function called can only access instances within the same collection.
要卸载已加载的集合,您发送与加载步骤相反的消息:
-- 卸载关卡
msg.post("#myproxy", "disable")
msg.post("#myproxy", "final")
msg.post("#myproxy", "unload")
"disable"
"final"
final()
函数。"unload"
如果您不需要更细粒度的控制,可以直接发送"unload"
消息,而无需先禁用和完成集合。代理将在卸载之前自动禁用并完成集合。
当集合代理完成卸载集合后,它将向发送"unload"
消息的脚本发送一个"proxy_unloaded"
消息:
function on_message(self, message_id, message, sender)
if message_id == hash("proxy_unloaded") then
-- 好的,世界已卸载...
...
end
end
集合代理更新可以通过改变_时间步_来进行缩放。这意味着即使游戏以稳定的60 FPS运行,代理也可以以更高或更低的速度更新,影响诸如:
update()
的dt
您还可以设置更新模式,这允许您控制缩放是否应该离散执行(仅在缩放因子低于1.0时才有意义)或连续执行。
您通过向代理发送set_time_step
消息来控制缩放因子和缩放模式:
-- 以五分之一速度更新已加载的世界。
msg.post("#myproxy", "set_time_step", {factor = 0.2, mode = 1})
为了了解更改时间步时发生的情况,我们可以创建一个对象,在其脚本组件中放置以下代码,并将其放在我们正在更改时间步的集合中:
function update(self, dt)
print("update() with timestep (dt) " .. dt)
end
时间步为0.2时,我们在控制台中得到以下结果:
INFO:DLIB: SSDP started (ssdp://192.168.0.102:54967, http://0.0.0.0:62162)
INFO:ENGINE: Defold Engine 1.2.37 (6b3ae27)
INFO:ENGINE: Loading data from: build/default
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0
DEBUG:SCRIPT: update() with timestep (dt) 0.016666667535901
update()
仍然每秒调用60次,但dt
的值发生了变化。我们看到只有1/5(0.2)的update()
调用会有1/60(对应60 FPS)的dt
——其余为零。所有物理模拟也将根据该dt
更新,并且仅在五分之一的帧中前进。
您可以使用集合时间步功能来暂停游戏,例如在显示弹出窗口或窗口失去焦点时。使用msg.post("#myproxy", "set_time_step", {factor = 0, mode = 0})
暂停,使用msg.post("#myproxy", "set_time_step", {factor = 1, mode = 1})
恢复。
有关更多详细信息,请参见set_time_step
。
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB