虚方法简介
本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 31 课,共 65 课。
Python 有一些特殊方法,例如 __init__ 和 __str__,语言会为你调用它们。Godot 中与之对应的是虚方法:方法名固定,以下划线开头,由你在类中定义,Godot 会在适当的时候调用它。你已经用过两个:
- 当
new()创建对象时,会运行_init(),并传入提供给new()的参数。 - 当节点进入场景树时,会运行
_ready()。main.gd就是从这里开始运行的。
其他方法还包括 _to_string(),它会在打印对象时被调用;还有让 for 循环遍历对象的迭代器方法(这两种方法会在接下来的两节课中介绍),以及 _notification(),它会接收来自引擎的事件。其中一个事件是 NOTIFICATION_PREDELETE,它会在对象被删除前立即触发:
# torch.gd
class_name Torch
extends RefCounted
var label: String
func _init(new_label: String = "Torch") -> void:
label = new_label
print(label, " lit")
func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE:
print(label, " burned out")# main.gd
var torch := Torch.new("Hall torch") # Hall torch 点亮了
torch = null # Hall torch 烧坏了一旦没有变量再引用 RefCounted 对象,它就会被删除,因此 torch = null 会立即发送通知。_init() 中的默认值使 new() 的参数变为可选参数:Torch.new() 会创建一个名为 Torch 的火炬。
Python 也使用魔术方法来实现运算符,例如用 __add__ 表示 +,用 __eq__ 表示 ==。GDScript 不支持运算符重载:potion_a + potion_b 会报错。你可以改为编写一个方法:
# potion.gd
class_name Potion
extends RefCounted
var power: int
func _init(start_power: int) -> void:
power = start_power
func combined(other: Potion) -> Potion:
return Potion.new(power + other.power)potion_a.combined(potion_b)会返回一个新药水,并且不会改变两个原药水。两个对象之间的==会检查两边是否是同一个对象,而不是检查它们的值是否相同:Potion.new(5) == Potion.new(5)的结果是false。如果你需要比较值,可以编写equals(other)这样的方法。
挑战
简单在 counter.gd 中编写 Counter 类:
_init(start = 0, step_size = 1)将起始值存入value,将步长存入step。签名中已经设置了默认值,因此Counter.new()、Counter.new(5)和Counter.new(5, 2)都可以使用。tick()将step加到value上。plus(other)用来替代+运算符,GDScript 不允许你定义这个运算符:它会返回一个新的Counter,其值为两个计数器的值之和,步长则为当前计数器的步长。两个计数器都不会改变。equals(other)在两个计数器的值相同时返回true。
提供的代码会读取两行来创建计数器 a 和 b(空行、START 或 START STEP),然后读取一行,指定对 a 和 b 执行 tick 的次数。它会输出两个计数器、它们的和、它们的值是否相等,以及 a == b 是否成立。对于 5、2 3 和 3 1 这几行输入,它会输出:
a: 8 (step 1)
b: 5 (step 3)
a plus b: 13 (step 1)
same value: false
same object: false请将代码写在 counter.gd 中。main.gd 包含提供的输入/输出代码,不能编辑。
亲手试试
extends Node
func _ready():
# 提供的输入输出代码:保持原样
var a := make_counter(OS.read_string_from_stdin())
var b := make_counter(OS.read_string_from_stdin())
var ticks := OS.read_string_from_stdin().split(" ")
for i in int(ticks[0]):
a.tick()
for i in int(ticks[1]):
b.tick()
print("a: %d (step %d)" % [a.value, a.step])
print("b: %d (step %d)" % [b.value, b.step])
var total := a.plus(b)
print("a plus b: %d (step %d)" % [total.value, total.step])
print("same value: %s" % a.equals(b))
print("same object: %s" % (a == b))
func make_counter(line: String) -> Counter:
var parts := line.split(" ", false)
if parts.is_empty():
return Counter.new()
if parts.size() == 1:
return Counter.new(int(parts[0]))
return Counter.new(int(parts[0]), int(parts[1]))
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: GDScript 在线编译器