ダックタイピング
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はプログラムの実行前に誤ったメソッド名を見つけます。ダックタイピングでは、その行が実行されたときに初めてわかります。いくつかのメソッドを共有する、互いに関連のないクラスのオブジェクトに使いましょう。
チャレンジ
簡単爆発は、近くにあるダメージを受ける可能性のあるものすべてにダメージを与えます。オブジェクトに共通の親クラスはありません。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())
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ