はじめに
Peanuts Codeさん の Tutorial で Godotを学習中。こんなに充実したコンテンツを提供してもらい感謝しきれません
ブロック崩し制作を終えて、現在はプラットフォーマー制作を学習中。
今回のエラー現象、ブロック崩しの時は Part14 で対処されていたが、プラットフォーマー制作では(未着手ページを斜め読みしたところ)見当たらなかったので、自分なりに対処したことを記録しておくことにしました。
環境
- Windows版 Godot Engine Ver.3.5(stable)
- GDScript
現象
Godot で作るプラットフォーマー Part 5、Part 7 において、最弱敵キャラである Mushroom が Playerに踏まれて死ぬ、もしくはステージの切り替わり時にレベルシーンごと抹消される際、
resume: Resumed function '_on_Timer_timeout()' after yield, but class instance is gone. At script: res://*****
というエラーが発生する。(エラーにならない時もある。Mushroomインスタンスが削除されるタイミング次第)
エラーの対象箇所はMushroom のスクリプト、歩行・停止の待ち時間制御部
yield(get_tree().create_timer(2), "timeout")
この方法は、公式リファレンスに 『 短い時間の一時停止であれば Timerノードの代わりに SceneTreeのcreate_timer()がある 』と紹介されている。
デバッグ実行時、エラーは出力されるが動作はします。放っておくか迷いましたが、ちゃんと対処することにしました。
ボツ案
Playerにやられたら Mushroom自身の表示とコリジョンを消して3秒待機してから queue_free()
する方法を実施。Playerアタックによるエラーは解消されたが、ステージ切り替え制御を追加した時にエラーが発生。
解決策
この方法が一番スッキリしていそうなので採用しました(リンク先の一番下)
https://godotengine.org/qa/76800/resumed-function-after-yield-but-class-instance-is-gone
- MashroomのルートノードにTimerノードを追加。名前をYieldTimerに変更
- コード(Mashroom.gd)の変更
- 旧:
yield(get_tree().create_timer(2), "timeout")
- 新:
$YieldTimer.start(2); yield($YieldTimer, "timeout")
- 旧:
Playerからのアタック、ステージ切り替え、共にエラーを解消できた。
yield実行中にルートノードのインスタンスが消える可能性がある場合は、yield実行用のTimerノードを用意することにしました。
最後に
まだ学習し始めなので、良し悪しの判断が付かない。もっと良い方法があるかもしれません。また、正式リリースが近づいている Godot4 では yield が廃止、await に置き換わるようです。それによって、本件気にしなくてもよくなる可能性はあります。