await
って何や_基本編
Godot3ではyield
でしたが、Godot4よりawait
というしくみに変わりました。
この記事では、await
の基本的な使い方と動作について解説します。
await
について知識がない初学者向けです。
await
を使うことで、実行中に「他のものの完了を待つ」ことができます。
1秒待つコード await get_tree().create_timer(1.0).timeout
をくわしく
サンプルコードとして頻出する、この1行コードです。
たしかにこのコードを実行すると「1秒待つ」のですが、
これを「1秒待つ」とだけ認識するのではなく、詳しくみていきましょう。
extends Node
func _ready():
print("_ready開始")
await get_tree().create_timer(1).timeout
print("1秒待った")
↑このコードを実行すると、1秒たってから1秒待った
が出力されますね。
この1行を分解します。
extends Node
func _ready():
print("_ready開始")
# 「このスクリプトをアタッチしたノード」があるシーンツリーを参照する
var scene_tree:SceneTree = get_tree()
# そのシーンツリーから、シーンツリータイマーを作成する。時間は1秒を指定。
# シーンツリータイマーは、作成された瞬間にタイマースタートする。
var scene_tree_timer:SceneTreeTimer = scene_tree.create_timer(1)
# そのシーンツリータイマーの timeout シグナルを参照する
var timeout_signal:Signal = scene_tree_timer.timeout
# そのシグナルが emit するのを await で待つ
await timeout_signal
print("1秒待った")
↑このようになります。
1行で書かれることが多いコードですが、やっていることを詳しくみるとこのような処理になっています。
つまり、
「1秒待つ」
↓詳しく
「1秒のシーンツリータイマーを作成し、そのシーンツリータイマーのtimeout
シグナルのemit
を待つ」
emit
はシグナルが発火することを示します。
Godot組み込みノードはシグナルがemit
されますし、
自作シグナルならコードからzisaku_signal.emit()
を呼ぶことでemit
されます。
このコードから言えることは、
await
は 「対象のシグナルがemit
されるまで待つ」 ことができます。
await
で待てるもの
では、await
は「シグナルがemit
されるまで待つ」だけなのか?と思ってしまいますが、そうではありません。
await
はシグナルのemit
以外にも待てるものがあります。
それはコルーチンです。
コルーチンは一般的には実行中に処理を中断し、再開できることを指します。
Godotにおいて、await
で待つことができる「GDScriptのコルーチンとは」を分かりやすく言うと、
実行途中でawait
で止まった関数 です。
つまり、await
を使用すると「実行途中でawait
で止まった関数 が完了する」のを待つことができます。
extends Node
func _ready():
print("_ready開始")
await totyuu_de_await_no_func()
print("1 完了")
var result = await totyuu_de_await_no_func_2()
print(str(result))
print("2 完了")
func totyuu_de_await_no_func():
print("途中でawaitの関数 returnなし")
await get_tree().create_timer(1).timeout
print("もっと待つ")
await get_tree().create_timer(1).timeout
func totyuu_de_await_no_func_2():
print("途中でawaitの関数 returnあり")
await get_tree().create_timer(1).timeout
return 2
_ready開始
途中でawaitの関数 returnなし
もっと待つ
1 完了
途中でawaitの関数 returnあり
2
2 完了
また、コルーチンが実行途中でawait
で止まった関数であることから分かるとおり、
そのコルーチン内でまたawait
でコルーチンを待つ~のように、await
待ちの連鎖をすることができます。
よく使われます。
まとめると、
「シグナルを待つ」「コルーチンを待つ」
await
はこの2つのことができます。
extends Node
func _ready():
print("_ready開始")
await signal_no_func()
print("これは関数でreturnされるシグナルのemitをawaitで待つ")
await totyuu_de_await_no_func()
print("これは「シグナルのemitをawaitで待つ」コルーチンの完了をawaitで待つ")
func signal_no_func():
print("関数 returnシグナル")
return get_tree().create_timer(1).timeout
func totyuu_de_await_no_func():
print("途中でawaitの関数 returnなし")
await get_tree().create_timer(1).timeout
_ready開始
関数 returnシグナル
これは関数でreturnされるシグナルのemitをawaitで待つ
途中でawaitの関数 returnなし
これは「シグナルのemitをawaitで待つ」コルーチンの完了をawaitで待つ
次回
await
を使ってなにか作ります。