仮想メソッド入門
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 31/65。
Python には __init__ や __str__ のようなマジックメソッドがあり、言語がそれらを呼び出します。Godot ではこれに相当するのが仮想メソッドです。これは、アンダースコアで始まる固定名を持つメソッドで、クラス内で定義すると、適切なタイミングで Godot が呼び出します。すでに 2 つ使いました。
_init()は、new()がオブジェクトを作成するときに、new()に渡された引数とともに実行されます。_ready()は、ノードがシーンツリーに入ったときに実行されます。これはmain.gdが開始する場所です。
その他には、オブジェクトが出力されるときに呼び出される _to_string()、for ループでオブジェクトを走査できるようにするイテレーターメソッド(どちらも次のレッスンで扱います)、そしてエンジンからイベントを受け取る _notification() があります。そのうちの1つである 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") # ホールのたいまつが点灯した
torch = null # ホールのたいまつが燃え尽きたRefCountedオブジェクトは、どの変数からも参照されなくなるとすぐに削除されるため、torch = nullは即座に通知を送信します。_init()のデフォルト値によって、new()の引数は省略可能になります。Torch.new()は、Torchという名前の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)は新しいポーションを返し、元の2つのポーションには変更を加えません。2つのオブジェクト間の==は、両者の値が一致するかどうかではなく、両者が同じオブジェクトかどうかを確認します。つまり、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()はvalueにstepを加算します。plus(other)は、GDScriptでは定義できない+演算子の代わりになります。両方の値の合計を値とし、このカウンターのステップをステップとする新しいCounterを返します。どちらのカウンターも変更されません。equals(other)は、両方のカウンターの値が同じ場合にtrueを返します。
用意されたコードは、カウンターaとbを作成する2行(空行、START、またはSTART STEP)を読み込み、続いてaとbを何回刻むかを指定する1行を読み込みます。両方のカウンター、その合計、値が等しいかどうか、および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オンラインコンパイラ