【Day10】蛇足:Blender側のワークフロー

Godotのインポートスクリプトでコリジョンを自動設定するために、Blender側でも扱いやすくするためのBlenderスクリプト。

Python
import bpy
from bpy.app.handlers import persistent

# 🛡️ ハンドラ関数の定義
@persistent
def auto_setup_collision_viz(scene):
    """
    シーンの更新を監視して、-col配下のメッシュを自動でワイヤー表示にする 🕵️
    """
    # シーン内の全オブジェクトをループして条件チェック
    for obj in bpy.data.objects:
        # 親がEmptyであり、かつ名前に "-col" が含まれているか確認 📦
        if obj.parent and obj.parent.type == 'EMPTY' and obj.parent.name.endswith("-col"):
            
            # メッシュオブジェクトのみ対象 💎
            if obj.type == 'MESH':
                # 既に設定済みならスキップして負荷を軽減 ⚡
                if obj.display_type != 'WIRE' or not obj.show_in_front:
                    obj.display_type = 'WIRE'
                    obj.show_in_front = True
                    print(f"✨ [Auto] {obj.name} をコリジョン表示に切り替えました 🔧")

# 📋 ハンドラの登録解除(二重登録を防ぐ)
def register():
    if auto_setup_collision_viz not in bpy.app.handlers.depsgraph_update_post:
        bpy.app.handlers.depsgraph_update_post.append(auto_setup_collision_viz)
        print("🚀 コリジョン監視ハンドラを登録しました!")

def unregister():
    if auto_setup_collision_viz in bpy.app.handlers.depsgraph_update_post:
        bpy.app.handlers.depsgraph_update_post.remove(auto_setup_collision_viz)
        print("🛑 コリジョン監視ハンドラを解除しました。")

# 🚀 実行
if __name__ == "__main__":
    register()

基本的にはBlenderでは描画を変えるだけで特に何をするわけでもない。
これで編集中に何がコリジョンで何が描画されるのか見た目で判断できるので制作の邪魔にならない。

使い方と注意点

  1. 登録方法: Blenderの「Text Editor」にこのコードを貼り付け、「Run Script」を一回だけ押す。
  2. 動作:
    • メッシュを -col という名前のEmptyの子にした瞬間にワイヤー表示になる。
    • 逆に、普通のEmptyの名前を後から -col に変更しても、即座に中身がワイヤー化される。
  3. 保存: このスクリプトが含まれた .blend ファイルを保存し、次回開いた時にも自動で有効にしたい場合、テキストエディタのメニューから Text > Register(登録) にチェックを入れる。

次にGodotのインポートスクリプト。

GDScript
# 🛠️ カスタム・ブレンダー・インポーター
# 表示オブジェクトを維持しつつ、コリジョンを自動構成します
@tool
extends EditorScenePostImport

func _post_import(scene: Node) -> Object:
	_iterate_nodes(scene, scene)
	return scene

func _iterate_nodes(node: Node, root: Node):
	if node == null:
		return

	# 🔍 名前が "-col" で終わるノードを検索
	if node is Node3D and node.name.ends_with("-col"):
		_process_custom_collision(node, root)
		# 変換後はこの枝の走査を終える(内部で再構築されるため)
		return 

	for child in node.get_children():
		_iterate_nodes(child, root)

func _process_custom_collision(source_node: Node3D, root: Node):
	var parent = source_node.get_parent()
	if not parent:
		return

	# 📦 1. 新しい StaticBody3D を作成(ここが表示と物理の親になる)
	var static_body = StaticBody3D.new()
	static_body.name = source_node.name.replace("-col", "")
	static_body.transform = source_node.transform
	
	parent.add_child(static_body)
	static_body.owner = root
	
	print("✨ [CustomImport] 物理・表示統合ノードを生成: ", static_body.name)

	# 🔄 2. 子ノード(メッシュ等)の処理
	for child in source_node.get_children():
		# 物理形状 (CollisionShape3D) の生成
		if child is MeshInstance3D:
			var mesh = child.get_mesh()
			if mesh:
				# コリジョン形状の作成
				var col_shape = CollisionShape3D.new()
				col_shape.shape = mesh.create_convex_shape()
				col_shape.transform = child.transform
				col_shape.name = "Collision_" + child.name
				
				static_body.add_child(col_shape)
				col_shape.owner = root
				
				child.get_parent().remove_child(child)
				
				print("  ✅ 物理と表示をセットしました: ", child.name)

	# 🗑️ 3. 役割を終えた元の Empty のみを削除
	source_node.queue_free()

GodotにはEmptyを自動的にコリジョン形状として扱う機能があるはずなんだけど、だいぶ前から完全に死んでるっぽいので、特定のEmptyの子をすべてコリジョン形状として扱うスクリプトとした。

注意

  • コリジョン形状をメッシュそのままを使うので、複雑な形状は重くなる。
  • StaticBody3Dしか扱わないようにしてるので、RigidBody3DやArea3Dなどの他の型は別途工夫する必要がある。

個人的にはほぼ地形にしか使わないつもりなので、一旦これで進める。

【Day9】プログラム以外をだいぶ進めてた

けど、Vellum UIの改修と、ゲームの遷移周りの調整をしてました。

ゲーム開始は必ずゲームローダーを通すようにすると、セーブデータの有無で新規ゲームかどうかを判断してうまいことやってくれると思う。

それとVellumで非同期ロードを実装したので、ローディング画面を作った。

Vellumのモーダルをもう少し改修しないといけないけど、概ねいい感じになったかな…。
参照がまばらなので、もうちょっとうまく整理しないといけないね。

頑張れ俺!

それとシナリオも作っていた。
この三日でプロットは概ね完成。箱書きも1章分は完了。
あとは実際の執筆ですな…。

キャラ制作のワークフローも考えたので、実際に手を動かしてうまくいくか試してみないとね。

【Day8】ライブラリ&フレームワーク化しました

まだまだ完成とは言いにくいですが、概ねできた。

  • フォーカスマネージャーにより特定範囲にのみフォーカスするように設定している。
  • フォーカスカーソルは自動的にフォーカスしているアイテムに追従
  • コンテナごとにカーソルを設定できる
  • リストコンテナにオーディオエミッタを設定することで自動的にサウンドが再生される
  • シーンマネージャーにより画面(Screen)・モーダル(Modal)などの追加が可能
  • コンポーネントをいくつか追加
    • セレクター:左右ボタンでリストの値を切り替えていくセレクター
    • スイッチ:ON/OFFのトグル
    • ゲージ:指定したサイズのゲージ
    • 上記、どれもエディタのインスペクタでアクションキーの割り当てが可能
    • スムーズスクロールコンテナ(シンプル版)を追加
    • 既存のSmoothScrollContainerのほうが高機能だけど、こっちのはシンプル
      • TweenベースではなくVelocityベースのスムーズスクロールなので拡張性は低い
      • マウス・タッチ・フォーカスに対応してる
  • モーダルを追加
    • デフォルトシーン(テンプレートシーン)を使う
    • もちろんユーザーがカスタムしたシーンを使うことも可能

大まかにはこんな感じ。

SceneManagerは通常シーンの追加に対応してないのと、FocusManagerがほとんど管理しててGUIManagerでの管理があんまりされてないから、この辺を整理するのが直近の課題かな。

でも概ね動いてるし、整理と拡張をしていく感じで進めます。

【Day7】蛇足:UIフレームワーク作ります

昨日さんざん作ってわかったんですが、ちゃんとフレームワークを作ったほうが良さそう。
今後のためにも。

GodotのFocusのシステムは結構曲者で、マウスを基準として結構自由にフォーカスができるし、状態管理もしっかりしてるとは思う。
でも、キー操作(コントローラー操作)においては、表示されてるフォーカスできる要素を容赦なく際限なくフォーカスしていってしまう。
例えば、ウィンドウが2個重なっていたとして、裏のウィンドウ内の要素もフォーカスしに行ってしまう。

この辺の制御をするのが面倒で、内部にカウンターを持たせて作るパターンもあるんだけど、今度はマウスとの整合性を取るのに少し手間がある。

なので、Godot Meetup Tokyoで公開用にVellum UIというコンポーネントライブラリ&フレームワークを作ります。

今着手してるプロジェクトにそのまま入れて作っていくので、進捗的にも大きくは問題はないし、正直今後プロジェクトが大きくなった時に、確実にUIを作ったりシーンの遷移だけで大幅に時間を使うであろうことが予測されるので、今のうちに片付けておこうねってこと。

作り始めて、昨日まで作ったUIのシステムを剥がしていってるけど、アドオンとしての手応えがあるんで、4月のMeetupに向け公開していくぜ。

読み込み中...

ゲーム開発を応援していただけたら幸いです

Buy Me a Coffee

Blender超基礎備忘録

いつもブランクが開くとすぐ忘れてしまうので備忘録。

Tab編集モードに入る
M頂点などを複数選択してる場合にマージ(M)
L選択している頂点などからつながった要素を選択(たぶん)
GGrabなんじゃないか。選択要素を移動
G→X/Y/Z各軸に対してのみ移動
G→G頂点を移動する際、辺上を移動
SScale‥‥拡縮
S→X/Y/Z各軸に対してのみスケール
E選択要素を押し出し
E→X/Y/Z各軸に対して押し出し方向
CTRL+Rループカット
R要素を回転
R→X/Y/Z各軸に対して回転
Shift+X/Y/Z入力した軸以外で操作