新手引导--- 2 使用技巧

新手引导--- 2 使用技巧

ahunziinwuxi

2025-01-15 发布379 浏览 · 3 点赞 · 1 收藏

本篇文章将介绍godot编辑器中一些基础的gdscript使用技巧。
不过说一千道一万,只有实践出真章,在了解其中原理之后多加练习,自然熟能生巧。

开始吧

godot编辑器的内置节点基于Node类,但godot有很多不属于Node子类的其他类。言归正传,使用gdscript在godot中进行对象访问时,使用Node类访问是最直观明了的访问方式。

Node类的访问与节点的路由寻址相关,我们可以使用一系列节点进行尝试。创建好根节点main之后,ctrl+a并选择创建Node2D子节点,命名为0。鼠标选中0节点,按ctrl+d进行快捷同级复制
image.png
也可以通过ctrl+c之后,按ctrl+v进行快捷创建连续子节点
image.png
例子中我已经给根节点main添加好脚本,接下来将演示节点访问。

访问节点时,我们如果想了解是否访问成功或了解访问的内容,就需要将访问到的信息打印到屏幕上。使用godot内置的print()函数是很好的办法,当然也可以使用与之相关的衍生函数。

extends Node2D

func _ready() -> void:
	print_tree()
	pass

以上代码将在编辑器输出信息框打印出如下内容:
image.png
其中第一行的 . 代表场景的根节点main节点上自身,因为脚本附加在main节点上。
image.png

之后打印的内容对应0-5 这6个main节点的子节点,以及它们的所有子节点名称。可以发现print_tree()将打印脚本附加的节点名称及其子节点名称。详情可以右键点击该函数 - 查找符号查看详情。

需要注意的是,这些名称不是绝对名称,如果将脚本附加在main的子节点,或对main的子节点创建一个新的脚本再使用print_tree(),则结果不一定相同。
image.png
image.png

在使用同一个脚本时,由于3节点只包括自身,所以只打印 “ . ”,而main正常打印。
image.png

如果给5节点也加载main.gd脚本,则会打印“ . ”以及它的子节点名称。可以看到一连串“5”比main节点打印的“5”少一个,这里请自行思考。
image.png

我们获取节点的名称,目的还是要通过名称访问节点的变量属性、函数以及它的子节点等信息。godot允许我们通过将节点拖拽到代码区进行节点访问,但是在跨多个脚本使用时,这种方式并不可靠。
132.gif

不过godot提供了从项目根节点寻址的方法,而所有场景节点都在项目根节点上搭建。
这个方法就是get_tree().root.get_node()
其中get_tree()可以理解为访问整个项目的目录,.root 代表访问root 节点,这个节点是godot内置的默认根节点,.get_node()代表(按名称)访问某个节点。

extends Node2D

func _ready() -> void:
	get_tree().root.print_tree()
	pass

解除其他节点的main.gd脚本后,运行以上代码,可以得到如下结果:
image.png

get_tree().root.print_tree()代表打印root节点的所有子节点名称,需要注意的是,使用load().instantiate()方法多次加载同一个场景文件时,godot引擎为保证资源的唯一性和易用性,新加载的场景的根节点名称会发生变化。

在实际使用过程中,由于所有场景节点都归于root的子节点,于是,除了根据名称访问,还能够通过节点的归属关系访问。

godot内置的get_children()方法是获取某个节点的所有下一级子节点的方法。该方法获取到的是子节点本身数据并将它们按标签存放到列表,而不仅仅是获取子节点的名称。

extends Node2D

func _ready() -> void:
	print(get_tree().root.get_children())
	pass

运行得到:
image.png
可以知道root节点的下一级子节点只有main节点。由于.get_children()方法得到的是一个数组,那么就可以通过访问数组的方法访问其中的节点。数组的查找位置从0开始,由于数组中只有main节点,所以它是第一个,也就是第0位。

extends Node2D

func _ready() -> void:
	print(get_tree().root.get_children()[0])
	pass

得到:
image.png
可以看到输出的内容两边少了[],此时该节点已经被提取访问。

其实我们可以再加一个.get_children()

extends Node2D

func _ready() -> void:
	print(get_tree().root.get_children()[0].get_children())
	pass

可以得到main节点的所有下一级子节点:
image.png
再尝试提取访问5节点,可以根据它的位置5,或者末尾-1进行访问。

extends Node2D

func _ready() -> void:
	print(get_tree().root.get_children()[0].get_children()[5])
	#print(get_tree().root.get_children()[0].get_children()[-1])
	pass

不过如果除了5之外还要访问其他节点,如果节点特别多,语句就会特别长,句式也会变得很麻烦。这时候可以尝试使用变量进行中继,或者同时使用get_node()方法混合访问。

extends Node2D

func _ready() -> void:
	var root = get_tree().root
	var main_node = get_tree().root.get_children()[0]
	print(main_node.get_children()[5])
	print(main_node.get_node("5"))
	print(root.get_node('main/5'))
	pass

以上代码会打印3条一样的信息,都表示获取到5节点,虽然get_node()对单双引号不敏感,但是在实际使用时建议使用双引号。
image.png

访问到节点之后可以获取节点属性,可以参考属性检查器中的内容。
image.png

点开下拉按钮之后,一般情况下可以根据属性名称,通过get()方法获取属性值。属性的名称可以通过拖拽获取。
000.gif

也可以通过文档查找。
000.gif

选中先前的代码,按ctrl+ k注释/取消注释。添加代码并打印。

extends Node2D

func _ready() -> void:
	var root = get_tree().root
	var main_node = get_tree().root.get_children()[0]
	#print(main_node.get_children()[5])
	#print(main_node.get_node("5"))
	#print(root.get_node('main/5'))
	var node_5 = main_node.get_node("5")
	print(node_5.get("position"))
	pass

得到5节点相对其父节点main的位置。
image.png

如果想打印5节点相对root的位置,请使用global_position
简洁的打印全局位置属性的语法是:print(node_5.global_position)。这同样对position属性适用。

设置属性值可以通过set()方法,如设置position属性:set("position", Vector2(100,100))Vector2(100,100)代表设置的目标值,position属性的数据类型为Vector2,因此设置的目标值的数据类型也应一致。
简洁的语法是:.position = Vector2(100,100)。如果要单独设置x值或y值,可以使用.position.x = 100.position.y = 100进行单独设置。

一些可能有用的例子

get_children()[0]的功能也可以通过get_child(0)实现。

获取上一级节点可以使用get_parent(),如果访问结果不为空,这个方法同样可以多次使用,访问上上一级、上上上一级、上上上上一级……。

数据类型
godot中的数据类型有很多,比如上文中提到的[],这是数组结构常用的标志符号。有时候调试需要根据数据类型进行调整,godot中有typeof()方法可以返回类型值,但并不直接返回类型名称,可以通过type_string()将其转化为类型名称。

例举一个使用方法:type_string(typeof(1))
输出int

输出与调试器
image.png

输出显示打印的内容,与print()方法及其衍生或引用方法联动。print()方法可以插入到代码中打印文本,可以通过观察该文本是否成功被打印,推断代码是否执行到这一行。类似的可以通过打断点实现(下图中红点),只要在代码左侧点击即可断点/取消断点。
image.png
不过,print()方法还可以打印句柄或变量,以此观察代码运行过程中的步骤或数据是否正常。

调试器中包含godot内置的报错打印以及一些功能检查工具。
image.png
如果项目不需要,除了打印错误,其他功能其实很多时候用不上。

脚本中的self
脚本中的self对所有引用该脚本的节点来说都代表“自身”的意思。将main.gd脚本绑定到几个节点,尝试运行。
image.png
得到:
image.png
由于3个节点同步调用一个脚本,由于资源优先级不同,打印的次序可能会不同,本文不做介绍。

注册树
当godot项目成功运行时,都会在tree中注册默认主场景作为当前聚焦的场景。相关的方法可见get_tree().current_scene
此外,tree中还会同时注册一些内置函数,供运行过程使用,如延时函数create_timer()。为方便演示,给main添加一个Button控件,并连接点击信号。
image.png

示例代码如下:

extends Node2D

var root
func _ready() -> void:
	root = get_tree().root
	pass

func _on_button_pressed() -> void:
	#打印当前场景
	print(get_tree().current_scene)
	#等待0.5秒后执行接下来的代码
	get_tree().create_timer(0.5).timeout
	#获取main场景的资源,并存到new_变量中
	var new_ = load("res://main.tscn").instantiate()
	#root节点中加入new_,也就是main场景
	root.add_child(new_)
	#打印root节点的所有下一级子节点
	print(root.get_children())
	pass

调整按钮的大小和位置,运行结果如下:
image.png

每次点击按钮,都会打印两行信息,连续点击则连续打印。
image.png
可以发现,实际已经添加了其他节点,但get_tree().current_scene一直是main节点。

如果我们想要切换当前节点,就需要关闭main节点,或跳转到其他节点。但是使用get_tree().current_scene.queue_free()移除current_scene之后,项目并不会自动切换主场景。
如果再次调用get_tree().current_scene.queue_free(),则会因为current_scene已经被移除,无法访问,弹出错误。因此在移除current_scene之后应使用新场景补充。
image.png

由于脚本直接绑定在场景根节点,也可以使用self.queue_free()移除自身的方式避开以上情况,不过需要注意移除默认主场景之后如果不重新设置current_scene,则current_scene变为空<Object#null>
image.png
image.png
可以看到打印内容中名字为main的节点在不断出现,但其后的标识已经改变。

社区示例
以上内容例举了一些基本的使用技巧,此外可以在godot社区中进行学习。godot开源项目中还包含许多基础的样例,可以进行下载借鉴。同时,godot社区中还有一些资源可以进行参考使用,在学习使用过程中也可以通过视频学习加深印象。
godot官方文档(中文)
godot官方样例
资源库网站
教程和资源

总结

本文所展示的内容并不多,仅作为入门使用参考,在实际项目中,往往需要考虑许多影响因素。但万变不离其中,godot的节点控制路由访问,以及可视化编辑控件的界面是它的重要特点,根据这些特点进行探索,或许会有助于熟悉和使用。

本文到此结束。

请前往 登录/注册 即可发表您的看法…