Menu
CoddyTech

节点作为组件

本课属于 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() 添加的组件无需清理。

challenge icon

挑战

简单

用组件节点构建一个机器人。

  • 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())
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: GDScript 在线编译器