Menu
CoddyTech

仮想メソッド入門

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)のようなメソッドを書きましょう。

challenge icon

チャレンジ

簡単

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]))
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: GDScriptオンラインコンパイラ