2024/12/17(火) [n年前の日記]
#1 [godot] Godot EngineでRigidBody3Dが何に当たったか調べたい
_昨日
に続き、Windows10 x64 22H2 + Godot Engine 4.3 64bit でゴルフゲームっぽいものが作れないものかなと試してる。
ボールを RigidBody3D で用意しているけれど、地面を担当してる StaticBody3D と衝突した時、何と衝突しているのか調べたい。ゴルフコースには色々な場所があるはずで。グリーンとかフェアウェイとかバンカーとか。どこに当たっているかが分からないと、ボールの挙動を変化させられない。
ただ、その何かの情報を、何を通じて持たせるのかで悩む…。当たったポリゴンのマテリアル名を取得できれば、とも思ったけれど、ググった感じでは Godot Engine はそういう機能を持ってないらしい。いや、頑張ればやれないこともないらしいけど…。
_How to detect the mesh material on contact collision : r/godot
Godot Engine が標準で持っている機能だけで実現するにはどうしたらいいのか試してみた。以下を参考にした。
_How to detect "collision" of RigidBody3D and StaticBody3D? : r/godot
とりあえず、以下のような結果にはなった。ボール(RigidBody3D)が乗っている、床(StaticBody3D)の種類を調べることができている。
Godotエディタ上での見た目は以下。
ノード構成はこんな感じになった。
StaticBody3D がずらずら並んでるあたりがポイント、ではあるけれど、ダサい…。結局、StaticBody3D を種類分用意して、それぞれにグループを設定して、衝突したことが分かった StaticBody3D がどのグループに属しているかを調べることで、何と衝突しているかを把握している。
スクリプトは以下。RigidBody3D にアタッチしてる。「# get hit group」のすぐ下が、判定している部分。
_ball_rigid_body_3d.gd
しかし、この方法はダサい…。ゴルフコースにある場所の種類分、blenderでモデルデータを複数作って、複数ファイルをエクスポートして、Godotにインポートしたらそれぞれにコリジョンとグループを設定していかないといけない…。どう考えても面倒臭い…。
でもまあ、100や200の種類があるわけではないから手作業でやれなくはないし、この方法なら確実に目的を果たせそうではあるけれど…。しかし、ダサい…。
この方法のまま、どこかを自動化するとしたら、1ファイルの .objモデルデータを読み込んで、マテリアル別に分割して複数の .obj として出力するスクリプトを書く、みたいな感じになるのだろうか。
ボールを RigidBody3D で用意しているけれど、地面を担当してる StaticBody3D と衝突した時、何と衝突しているのか調べたい。ゴルフコースには色々な場所があるはずで。グリーンとかフェアウェイとかバンカーとか。どこに当たっているかが分からないと、ボールの挙動を変化させられない。
ただ、その何かの情報を、何を通じて持たせるのかで悩む…。当たったポリゴンのマテリアル名を取得できれば、とも思ったけれど、ググった感じでは Godot Engine はそういう機能を持ってないらしい。いや、頑張ればやれないこともないらしいけど…。
_How to detect the mesh material on contact collision : r/godot
Godot Engine が標準で持っている機能だけで実現するにはどうしたらいいのか試してみた。以下を参考にした。
_How to detect "collision" of RigidBody3D and StaticBody3D? : r/godot
とりあえず、以下のような結果にはなった。ボール(RigidBody3D)が乗っている、床(StaticBody3D)の種類を調べることができている。
Godotエディタ上での見た目は以下。
ノード構成はこんな感じになった。
StaticBody3D がずらずら並んでるあたりがポイント、ではあるけれど、ダサい…。結局、StaticBody3D を種類分用意して、それぞれにグループを設定して、衝突したことが分かった StaticBody3D がどのグループに属しているかを調べることで、何と衝突しているかを把握している。
スクリプトは以下。RigidBody3D にアタッチしてる。「# get hit group」のすぐ下が、判定している部分。
_ball_rigid_body_3d.gd
extends RigidBody3D @export var label3d: Label3D @export var move_speed: float = 3.0 # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): # move ball by cursor key var d = Vector3.ZERO if Input.is_action_pressed("ui_left"): d.x = -1 if Input.is_action_pressed("ui_right"): d.x = 1 if Input.is_action_pressed("ui_up"): d.z = -1 if Input.is_action_pressed("ui_down"): d.z = 1 if d != Vector3.ZERO: d = d.normalized() apply_central_force(d * move_speed) # get hit group var grp_name_list = ["bunker", "water", "green", "rough", "ob"] var txt = "" for grp in get_colliding_bodies(): for grpname in grp_name_list: if grp.is_in_group(grpname): txt += "on %s\n" % grpname label3d.global_position = global_position + Vector3(0, 1.2, 0) label3d.text = txt
- get_colliding_bodies() で、衝突している *Body3D のグループを取得できる。
- .is_in_group() で、そのグループが指定グループ名を含んでいるかどうかを調べることができる。
しかし、この方法はダサい…。ゴルフコースにある場所の種類分、blenderでモデルデータを複数作って、複数ファイルをエクスポートして、Godotにインポートしたらそれぞれにコリジョンとグループを設定していかないといけない…。どう考えても面倒臭い…。
でもまあ、100や200の種類があるわけではないから手作業でやれなくはないし、この方法なら確実に目的を果たせそうではあるけれど…。しかし、ダサい…。
この方法のまま、どこかを自動化するとしたら、1ファイルの .objモデルデータを読み込んで、マテリアル別に分割して複数の .obj として出力するスクリプトを書く、みたいな感じになるのだろうか。
◎ 余談。グループの設定方法 :
グループ名は、Godotエディタの右端のあたりで指定できる。StaticBody3D を選択した状態で…。
試してはいないけど、おそらく複数のグループに所属させることもできるのではないかと…。
- ノード → グループ、を選んで、
- 「+」ボタンをクリックして必要になりそうなグループ名を追加して、
- *Body3D に割り当てたいグループ名にだけチェックを入れる。
試してはいないけど、おそらく複数のグループに所属させることもできるのではないかと…。
◎ 余談。特定フォルダをインポートの対象から外したい :
プロジェクトフォルダ内の特定フォルダを、Godot Engine の自動インポート処理の対象から外したい。スクリーンショット画像も入れておいたら、インポートされてしまったので…。そのフォルダは無視して欲しい…。
そのフォルダの中に「.gdignore」という名前で空のファイルを作成しておくだけでいいらしい、と知ったのでメモ。
_【Godot Engine】始める前に抑えておきたい事【ベストプラクティス?】 | ひらまめゲーム制作研究室
_プロジェクトの構成 - Godot Engine (4.x)の日本語のドキュメント
そのフォルダの中に「.gdignore」という名前で空のファイルを作成しておくだけでいいらしい、と知ったのでメモ。
_【Godot Engine】始める前に抑えておきたい事【ベストプラクティス?】 | ひらまめゲーム制作研究室
_プロジェクトの構成 - Godot Engine (4.x)の日本語のドキュメント
特定のフォルダを無視する
Godot が特定のフォルダに含まれるファイルをインポートしないようにするには、フォルダ内に .gdignore という空のファイルを作成します (先頭に . が必要です)。これは、(既存の構成などからの)初期プロジェクトのインポートを高速化するのに役立ちます。
[ ツッコむ ]
以上、1 日分です。