Menu
CoddyTech

ダックタイピング

CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 22/65。

ダックタイピングでは、オブジェクトがどのクラスに属しているかではなく、何ができるかを重視します。呼び出すメソッドを持っていれば、その呼び出しは機能します。この名前は、「アヒルのように泳ぎ、アヒルのように鳴くなら、それはアヒルだ」ということわざに由来します。

これら 2 つのクラスには共通の親クラスはありませんが、どちらにも swim() と quack() があります:

# duck.gd
class_name Duck
extends RefCounted

func swim() -> String:
	return "Duck swimming"

func quack() -> String:
	return "Quack!"
# robot.gd
class_name Robot
extends RefCounted

func swim() -> String:
	return "Robot swimming with propellers"

func quack() -> String:
	return "Robot sound: BEEP BEEP!"

型なしのパラメーターは、あらゆるオブジェクトを受け取ります。この関数はメソッドを呼び出し、それぞれのオブジェクトが独自の処理を実行します:

func make_it_swim_and_quack(thing) -> void:
	print(thing.swim())
	print(thing.quack())
make_it_swim_and_quack(Duck.new())
make_it_swim_and_quack(Robot.new())
Duck swimming
Quack!
Robot swimming with propellers
Robot sound: BEEP BEEP!

オーバーライドには共通の親クラスが必要ですが、ダックタイピングには必要ありません。パラメーターの型が thing: Duck と指定されている場合、Robot を渡すとパースエラーになります。

オブジェクトにメソッドがない場合、呼び出しによって関数は Invalid call. Nonexistent function 'quack' のようなエラーで停止します。まず has_method() で確認します。このメソッドはメソッド名を String として受け取ります。

var things := [Duck.new(), Rock.new()]
for thing in things:
	if thing.has_method("quack"):
		print(thing.quack())
	else:
		print("This one cannot quack")
Quack!
This one cannot quack

代償:型を使うと、Godotはプログラムの実行前に誤ったメソッド名を見つけます。ダックタイピングでは、その行が実行されたときに初めてわかります。いくつかのメソッドを共有する、互いに関連のないクラスのオブジェクトに使いましょう。

challenge icon

チャレンジ

簡単

爆発は、近くにあるダメージを受ける可能性のあるものすべてにダメージを与えます。オブジェクトに共通の親クラスはありません。player.gd と rock.gd は完成しています。Player には take_damage(amount) と status() があり、Rock には status() だけがあります。

  • crate.gd で、最初は false の broken 変数と、ダメージ量が 10 以上の場合に木箱を壊す take_damage(amount) メソッドを Crate に追加し、status() が Crate: broken または Crate: intact を返すようにします。
  • explosion.gd で、静的メソッド hit_all(things, amount) を記述します。Array 内の各オブジェクトのうち、そのメソッドを持つものに take_damage(amount) を呼び出し、命中した数を返します。

提供されているコードは、オブジェクト名の行(player、crate、または rock)を読み込み、続いて爆発の回数とそれぞれのダメージ量を読み込みます。各爆発が命中したオブジェクトの数を出力し、その後、すべてのオブジェクトの状態を出力します。player crate rock と 5 および 20 の爆発の場合、次のように出力します。

Explosion 1 hit 2 objects
Explosion 2 hit 2 objects
Player: 75 HP
Crate: broken
Rock: solid

コードは crate.gd と explosion.gd に記述します。main.gd には提供された入出力コードがあり、編集できません。

自分で試してみよう

extends Node

func _ready():
	# 提供された入出力コード:そのままにしておいてください
	var things := []
	for word in OS.read_string_from_stdin().split(" "):
		if word == "player":
			things.append(Player.new())
		elif word == "crate":
			things.append(Crate.new())
		else:
			things.append(Rock.new())
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var hits := Explosion.hit_all(things, int(OS.read_string_from_stdin()))
		print("Explosion %d hit %d objects" % [i + 1, hits])
	for thing in things:
		print(thing.status())
quiz icon腕試し

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

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

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