はじめに
キャラクターが樽に当たった時に樽からアイテムが出現するようにしてみます。(fig.1)
fig.1 樽に当たったらアイテムが出る
目次
プロジェクトの準備
まず、サンプルシーンを作成します。(fig.2)
用意するものは、”プレイヤー”、”樽”、”アイテム”の3つです。
サンプルシーンはこちらからダウンロードできますので参考にしてください。
プレイヤーのシーン
プレイヤーはカーソルキーの右を押すと右に移動し、樽に当たると樽にダメージを与えるようにします。
ルートとなるノードの種類は”Area2D”とし、名前を"Player"にします。
その子に"Sprite2D"、"CollisionShape2D"を追加します。
コリジョンの大きさはスプライトの大きさに合わせます。(fig.3)
fig.3 ノードの準備
"Player"ノードのシグナル"body_enterd(body:Node2D)"を自身に繋ぎます。(fig.4)
fig.4 "body_enterd(body:Node2D)"シグナル
script.1 Playerノードのスクリプト
アイテムのシーン
アイテムは、実ゲームでは必要なので、とりあえず当たり判定を付けておきます。(fig.5)
コリジョンのレイヤーとマスクはプレイヤーとは別の番号を有効にします。
スクリプトはアタッチしません。
fig.5 アイテムのシーン
樽のシーン
樽は体力(HP)を設定して0以下になったらアイテム出現と"Break"アニメーションを再生し、
アニメーション終了時に自身を削除するようにします。
まず、ノードの構成とコリジョンの設定は次の図のようにします。(fig.6)
次に、Taruノードにアタッチするスクリプトは下記のようになります。(script.2)
script.2 Taruノードのスクリプト
"script.2"でキモになるのは、アイテムを出現させる部分です。(fig.7)
fig.7 アイテムを出す部分のスクリプト
順番に解説します。
実体化したノードは仮のノードに紐づけします。
var callable = owner.add_child.bind(temp_node)
"add_child"メソッドの呼び出しをフレームごとに遅延させるために必要です。
忘れがちですが"bind"メソッドを入れるようにします。
get_tree().process_frame.connect(callable, CONNECT_ONE_SHOT)
先ほどのメソッドを1フレーム遅延させて呼び出します。
引数"CONNECT_ONE_SHOT"ならば1回のみ実行を指示します。
これらの処理を行わなかった場合のスクリプト(fig.8)ではどうなるでしょうか?
fig.8 遅延呼び出しを行わなかった場合のスクリプト
アイテムを出す段階で次のエラーが出ます。(fig.9)
fig.9 エラー表示
これはしっかり調べてはいないので、はっきり言えず申し訳ございません。
このエラーは連続で複数回発せられることもあります。
実行確認
シーンにプレイヤーと樽を配置したら実行してみましょう。(fig.1)
fig.1 樽に当たったらアイテムが出る
おわりに
エラーの解決にあたり、"call_deferred"を調べるところから始めました。
bingの翻訳機能を使いつつなんとか解決できた感じです。
本件と同じエラーは過去にもあり、その時は別の方法に切り替えて対処しましたが、
ようやく雛形が見えた気がします。
今回の記事はここまでとなります。
最後までお読みいただきありがとうございました。
参考文献
Godot Engine 4.3の日本語のドキュメント -> Object -> call_deferred
https://docs.godotengine.org/ja/4.x/classes/class_object.html#class-object-method-call-deferred