如何让场景中组节点完成的功能在场景切换后不发生变化?

How to make the functions done for group nodes in a scene not change after changing scene?

我已经将节点放在一个组中。我在场景脚本上放了一个函数来更改组中的节点。在那个函数中,我让节点可以自由排队等等。但是当我改变场景并回到之前的场景时,queued free 又回来了,它不再是 queued free 了。如何让它在换场景后不改变?

为什么会丢失信息

当您使用 change_scene or change_scene_to 更改当前场景时,将卸载当前场景,并加载并实例化新场景。

也许有助于概念化场景的实例与存储中的场景不同。所以发生的事情就像在编辑器中打开一个文件,修改而不是保存它。


好吧,如果你真的想走那条路,这是一个解决方案:你可以保存场景。

先创建一个PackedScene,例如:

var packed_scene := PackedScene.new()

然后告诉它打包场景的根节点,例如:

packed_scene.pack(self)

注:任意Nodes that don't have their owner property set to the Node you passed here will be ignored. And no, add_child不设置owner属性.

如果你一直在关注,你知道你可以给PackedScenechange_scene_to...但是当场景改变时你如何保持它?

有几种方法。问题是:如果我们可以保留信息,我们可能不需要保存场景。


自动加载东西

即使您更改场景,您在项目设置中添加到自动加载(单例)的脚本和场景也会保留(除非您明确删除它们)。

因此,保存信息的一种非常简单的方法是创建一个包含一些变量的脚本,您可以在项目的任何位置写入和读取这些变量。你可以用自动加载来做到这一点。


在资源中保留东西

Godot 缓存资源。当你在多个地方加载相同的资源时,你实际上得到的是同一个对象。

嗯,你知道你可以创建自定义 Resource class. To do that, on the context menu of the FileSystem panel select "New Script", and in the script make a class that extends Resource, and give it a class_name

然后您可以从 FielSystem 面板的上下文菜单中创建 Resource 的资源,方法是选择“新建资源”并在询问时选择 Resource class。

无论你在哪里加载其中一个,你都会得到相同的对象。是的,即使是在另一个场景中。所以你可以给你的 Resource class 添加变量,在一个场景中写入它们,在另一个场景中读取它们。

我解释一个更具体的例子elsewhere.


把东西放在储物柜里

您可以写入文件并从文件中读取。例如你可以这样做:

# save
var file = File.new()
file.open("user://a.sav", File.WRITE)
file.store_pascal_string(var2str(data))
file.close()

# load
file.open("user://a.sav", File.READ)
data = str2var(file.get_pascal_string())
file.close()

或者,如果您要存储的是 Resource(无论是 PackedScene 还是其他 Resource class,包括自定义的),您可以使用 ResourceSaver and ResourceLoader:

# save
ResourceSaver.save("user://a.tres", resource)

# load
resource = ResourceSaver.load("user://a.tres")

当然你也可以用load, or preload. You may also be interested in Background Loading加载资源。


顺便说一句,如果您要保存玩家进度,将所有玩家进度数据放在一个对象中是有意义的。而且,如果您要拥有所有数据,您会将所有玩家进度数据保存在一个地方,那么它应该在任何时候都可以访问的地方并且即使在您改变场景时也会保持不变,因此:将玩家自动加载中的进度数据。奖励:您也可以将保存和加载到文件的功能放在那里。


不换场景

既然改变场景会带来问题 - 请考虑另一种解决方案:不要。

您可以加​​载一个场景:

var packed_scene := load("res://scene.tscn") as PackedScene

然后创建一个实例:

var scene := packed_scene.instance()

然后将其添加到您当前的场景树中:

add_child(scene)

没错,就是Node!这也意味着您可以……

scene.queue_free()

或者您可以简单地使用 remove_child 将其删除,但不会释放它,因此您可以稍后将其添加回来。

因此您可以控制加载或卸载的内容以及时间。这对于保留东西很有用(例如 UI、玩家角色等)。 按照我在这里描述的方式进行操作的一个缺点是 get_tree().current_scene would not be useful to you anymore. See also Change scenes manually