节点作为组件
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 42 课,共 65 课。
Node 可以有子节点。Godot 通过这种方式构建游戏对象:英雄节点会为每种能力添加一个子节点,例如生命值或移动。每个子节点都是一个组件:一个只负责一项工作的轻量节点。
# health.gd
class_name Health
extends Node
var hp := 10
func _ready() -> void:
print("Health ready")
# hero.gd
class_name Hero
extends Node
func _init() -> void:
var health := Health.new()
health.name = "Health"
add_child(health)
func _ready() -> void:
print("Hero ready, hp: ", $Health.hp)add_child()会将一个节点添加为子节点。为每个组件设置一个name:get_node("Health")或其简写形式$Health可以按名称查找子节点。没有名称,或名称与同级节点重复的节点,会获得一个自动生成的名称,例如@Node@4。
节点进入场景树(游戏正在运行的节点树)时,会运行它的 _ready()。main.gd 位于树中,因此将英雄添加到其中会启动两个 _ready() 方法,先启动子节点的方法:
# main.gd
var hero := Hero.new()
add_child(hero) # Health 先就绪,然后 Hero 就绪,hp:10
print(hero.get_child_count()) # 1父节点可以通过 get_children() 获取其组件(这是一个数组,顺序与添加顺序相同),也可以使用 get_child_count() 和 has_node("Health")。游戏结束时,树中的节点会随树一起释放,因此通过 add_child() 添加的组件无需清理。
挑战
简单用组件节点构建一个机器人。
Part继承自Node。它的构造函数接收部件名称和功率值:它会存储功率,并将节点的name设为部件名称。当部件进入场景树时,它的_ready()会打印Laser attached。Robot继承自Node。add_part(part_name, power)会将一个新的Part添加为子节点。如果机器人已经有一个名称相同的子节点,它会打印Laser is already attached,且不会创建任何内容。total_power()会返回所有部件的功率总和。
提供的代码会将机器人添加到场景树,读取后续命令的数量(add Laser 5、power),并在最后打印部件数量。对于 add Laser 5、add Wheels 2、power、add Laser 9、add Arm 3、power,会打印:
Laser attached
Wheels attached
Total power: 7
Laser is already attached
Arm attached
Total power: 10
Parts: 3你的代码应写在 part.gd 和 robot.gd 中。main.gd 包含提供的输入/输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样
var robot := Robot.new()
add_child(robot)
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
if parts[0] == "add":
robot.add_part(parts[1], int(parts[2]))
else:
print("Total power: ", robot.total_power())
print("Parts: ", robot.get_child_count())
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器