我正在参加掘金社区游戏创意投稿大赛个人赛,详情请看:游戏创意投稿大赛”
原文:Understanding node paths :: Godot Recipes (kidscancode.org)
作者:# Chris Bradfield
问题
这可能是 Godot 社区中被询问的最多的问题:无效的引用。大多数情况下,它会提示如下的错误信息。
Invalid get index ‘position’ (on base: ‘null instance’).
解决方法
关键点在于上述提示中的 “null instance”。这是这个问题的根本原因。
避免这个问题的关键在于理解 Godot 的节点路径概念。
理解节点路径
场景树由节点组成,父子节点连接在一起。节点路径是从一个节点到另一个节点的路径。
举个例子,让我们来看一个简单的“Player”场景:
这个场景的脚本在Player节点上。如果需要调用 AnimatedSprite的play(),则需要对该节点的引用:
get_node("AnimatedSprite").play()
get_node()函数的参数是一个字符串,表示到所需节点的路径。在这个例子当中,它是脚本所在节点的子节点。如果使用无效的路径,那么会得到可怕的错误:null instance
使用get_node()获取节点引用是很常见的,所以 GDScript 有一个它的简便的办法:
$AnimatedSprite.play()
Get_node返回对所需节点的引用。
让我们来看看一个更复杂的场景树:
如果 Main 上的脚本需要访问 ScoreLabel,可以这样:
get_node("HUD/ScoreLabel").text = "0"
# or using the shortcut:
$HUD/ScoreLabel.text = "0"
当使用 $ 时,Godot 编辑器会自动完成。我们还可以在场景工具栏中右键单击一个节点,然后选择“复制节点路径”。
如果要访问的节点位于树中较高的位置,该怎么办呢?我们可以使用 get_parent()或..引用父节点。在上面的示例中,从 ScoreLabel 中获取 Player 节点可以像下面这样:
get_node("../../Player")
我们分析一下。路径。./../Player 的意思是获得上一级的节点(HUD) ,然后再上一级的节点(Main) ,然后是它的子节点Player。
这看起来熟悉吗?节点路径和操作系统中的目录路径完全相同。
/表示父子关系,并且..表示”上一级”。
相对路径与绝对路径
上面的示例都使用了相对路径——这意味着它们从当前节点开始,沿着路径到达目的地。‘
节点路径也可以是绝对的,从场景的根节点开始。
例如,到Player节点的绝对路径是:
get_node("/root/Main/Player")
/root 也可以通过 get_tree().root 访问。 它不是场景的根节点。默认情况下,它是 Viewport 节点。
警告
虽然上面的示例运行正常,但是有些事情应该注意,这些事情以后可能引起问题。想象下面的情况: Player 节点有一个 health 属性,我们希望将其显示在 UI 中的 HealthBar 节点中。我们可以在Player的脚本中这样写:
func take_damage(amount):
health -= amount
get_node("../Main/UI/HealthBar").text = str(health)
虽然刚开始可能运行正常,但它很危险。这种写法有两个主要问题:
- 无法单独测试Player场景。比如说当我们在测试时如果没有UI那么会报错。
- UI 不好修改。路径和UI耦合了。要改两者要一起修改
因此,我们应该尽量避免使用这种节点路径。在上面的情况下,如果反向操作,当发生变化时,Player发出信号,UI 可以监听该信号做出反应。这样解除了二者之间的耦合,就可以分别修改和测试了。