场景唯一节点

前言

在脚本中使用 get_node() 来引用节点在某些情况下可能比较脆弱。如果你把 UI 场景里的某个按钮移到了别的面板里,那么这个按钮的节点路径就会发生改变,而如果脚本中正好使用了写死的节点路径来调用 get_node(),那这样一来这个脚本就无法再找到这个按钮了。

类似这种情况,可以将节点设为场景唯一节点,这样该节点的路径发生变化时就不必再更新脚本了。

创建与使用

在场景树面板中,右键单击节点并在上下文菜单中选择作为唯一名称访问

../../_images/unique_name.webp

勾选后,场景树中该节点的名称旁边就会显示一个百分号(%):

../../_images/percent.webp

现在你就可以在脚本中使用这个节点了。例如先打一个 % 符号,在后面跟上节点的名称,这样就可以使用 get_node() 方法来引用这个节点:

GDScriptC#

  1. get_node("%RedButton").text = "Hello"
  2. %RedButton.text = "Hello" # Shorter syntax
  1. GetNode<Button>("%RedButton").Text = "Hello";

同场景限制

场景唯一节点只能获取同一场景中的节点。我们可以举些例子来演示一下,比如这个示例场景是在 Player 场景中实例化了一个 Sword 场景:

../../_images/unique_name_scene_instance_example.webp

以下是在 Player 脚本中调用 get_node() 的结果:

  • get_node("%Eyes") 会返回 Eyes 节点。

  • get_node("%Hilt") 会返回 null

以下是在 Sword 脚本中调用 get_node() 的结果:

  • get_node("%Eyes") 会返回 null

  • get_node("%Hilt") 会返回 Hilt 节点。

如果脚本能够获取到另一个场景中的节点,那么就可以调用该节点的 get_node() 来获取该节点所在场景中的场景唯一节点。你也可以在节点路径中做类似的操作,从而避免多次调用 get_node()。以下两种方法均可从 Player 脚本中利用场景唯一节点来获取 Hilt 节点:

  • get_node("Hand/Sword").get_node("%Hilt") 会返回 Hilt 节点。

  • get_node("Hand/Sword/%Hilt") 也会返回 Hilt 节点。

场景唯一名称不止可以用在节点路径的末尾,也可以用在路径的中间来实现跳转。例如 Player 场景中的 Sword 节点就是一个场景唯一节点,因此可以这样写:

  • get_node("%Sword/%Hilt") 会返回 Hilt 节点。

替代方案

使用场景唯一节点可以很方便地在场景中进行跳转。但是有些情况下其他写法会更好一些。

使用分组可以从任意节点定位到某个节点(或一组节点),无需考虑所处的场景。

单例(自动加载)是一种始终存在的节点,任何节点都可以直接访问,无需考虑所处的场景。适合需要全局共享数据或功能的时候使用。

Node.find_child() 可以根据名称来查找节点,无需知道完整路径。这种做法看上去和场景唯一节点类似,并且可以查找到嵌套场景里的节点,也不需要在场景编辑器里标记节点。但是这个方法相对较慢。Godot 会缓存场景唯一节点,所以获取的时候比较快,而调用 find_child() 时则需要查找每一个后代节点(子节点、孙节点等)。