要約
衝突中を通知するシグナル通知が無いので、Area2D.GetOverlappingAreas()を使って自作しよう
アドベントカレンダーはお祭りだから、この程度のコタツ記事で良いんですよ(個人の感想です)
はじめに
Godotの衝突を通知するシグナルに衝突の開始(Enter)と終了(Exit)はありますが、衝突中(Stay)を通知するシグナルはありません。衝突中の武器が一定間隔で敵にダメージを与えるといった機能を実現するには少々物足りないです。無ければ自作しましょう。
環境:Godot4.1+ C#(.Net Framework7.0)
方式
Area2D.GetOverlappingAreas()が現在衝突中のArea2D配列を返してくれるのでこれを使用します。
ドキュメントによれば少々癖のある振る舞いをしており、物理ステップ間隔が経過しないと衝突中エリアの更新をしないようです。つまり_Process()ではなく_PhysicsProcess()で取得せよという事ですね。
For performance reasons (collisions are all processed at the same time) this list is modified once during the physics step, not immediately after objects are moved. Consider using signals instead.
試行回数が少ないのでまだ遭遇していませんが、この方式ではEnterとExitの間にStayが必ず呼び出される保証がありません。具体的に書くと以下のような呼出し順になる事が想定されます。
期待する動作) Enter→Stay→Stay→Stay→Stay→Exit
ありえる動作) Stay→Enter→Stay→Stay→Exit→Stay
エンジンが提供しない機能を自作するとだいたいこういう結果になるものです。必要なら自分で整流処理を追加しましょう。
サンプルノード
Godotは関連するノードの親子関係とコードが揃わないとシーン全体を理解するのが難しいので、まずはシーン構成から。
衝突を通知するArea2Dに衝突形状を表すCollisionShape2Dだけのシンプル構成です。シグナルを見てもStayがありません。
サンプルコード
基本的にこの方式はポーリングですのでなるべく負荷を下げたいものです。
先にHasOverlappingAreas()を使って処理対象が無ければ何もせずメソッドから抜けてます。_Process()も_PhysicsProcess()も毎フレーム呼び出されるのは仕方がないとして、仕事が無ければ即リターンです。
using Godot;
using System;
public partial class OnAreaStayDemo : Area2D
{
public override void _PhysicsProcess(double delta)
{
if(!HasOverlappingAreas()) return;
Godot.Collections.Array<Area2D> areas = GetOverlappingAreas();
foreach(Area2D area in areas){
OnAreaStay(area);
}
}
private void OnAreaStay(Area2D area)
{
}
private void _on_area_entered(Area2D area)
{
}
private void _on_area_exited(Area2D area)
{
}
}
動かしてみた
このツイートに添付した動画の最後の所で、この処理が仕事をしています。
おわりに
Qiitaアドベントカレンダーはお祭りです。自分の中の「思いついた!」を文章にして掲載すればよいのです。どこかで読んだような記事でも貴方にとって新発見ならそれで充分です。誰かと被っても良いのです。重複だとしても読み手が判断してくれます。
「中途半端な内容を書いたら変な人が絡んでくるんじゃないかしら…?」と心配な時はタグにポエムを追加してみてください。(この記事にも付けてあります)厄介な人も「この記事ポエムだしなー」で帰ってくれます。
そもそもGodotの日本語記事が少なすぎるので、もうちょっと増やしませんか?というお誘いがこの記事の目的です。検索エンジンで調べても公式ドキュメントと英語記事しか引っ掛からないのは、日本語圏のユーザーにとってGodot利用者が存在しないに等しいのです。オープンなインターネットに記事を書きましょう。
OSSコミュニティへの貢献の仕方として「口コミで広める」「ブログ記事を書く」という項目があります。私には寄付する余裕もコードにコミットするレベルの内部理解もありません。それでも日本語のコタツ記事くらいなら書くことが出来ます。
せっかくの機会なのでQiitaのアドベントカレンダーに参加してみませんか?
Be part of the community. The best way to contribute to Godot and help it become ever better is simply to use the engine and promote it by word-of-mouth, in the credits or splash screen of your games, blog posts, tutorials, videos, demos, gamedev or free software events, support on the Q&A, forums, Contributors Chat, Discord, etc. Participate! Being a user and advocate helps spread the word about our great engine, which has no marketing budget and can therefore only rely on its community to become more mainstream.