godot-adapt-2d-to-3d について
Godot プロジェクトを 2D から 3D または 2.5D へ移行するためのスキルです。カメラ、移動、物理の移行スクリプトに加え、アート、UI、性能に関する指針を扱います。
主な機能
- 012Dから3Dへのノード移行ガイド
- 02カメラと移動の移行スクリプト
- 03物理レイヤー移行チェックリスト
- 04スプライト、モデル、UIの適応
- 053Dの性能とスケーリング指針
活用シーン
- 01CharacterBody2Dのゲームを3Dへ移植
- 02ビルボードスプライトによる2.5Dゲーム制作
- 03Camera2Dを3Dカメラに置き換え
- 04対象ハードウェアで2Dから3Dへの移行を計測
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ thedivergentai/ game-dev-agentic-skills --skill godot-adapt-2d-to-3dインストール後、Claude Code で/godot-adapt-2d-to-3dを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/migration-notes.mdmigration-recipes.mdscripts/adapt_2d_to_3d_patterns.gdcharacterbody3d_migration_movement.gdcrisp_projected_ui.gdlight_migration_tool.gdmassive_crowd_manager.gdnavigation_bridge_2d5d.gdphysics_layer_migration_checklist.gdspring_arm_camera_setup.gdsprite_plane.gdvector_mapping.gd詳細
絶対にしてはいけないこと
- Vector2をVector3(x, y, 0)に直接置き換えないでください — 奥行きのあるゲームプレイがない「平面的な3D」ゲームになります。3Dにする根拠として、Z軸方向の移動やカメラの回転を追加してください。
- 2Dのコリジョンレイヤーをそのまま使わないでください — 2Dと3Dの物理演算では、別々のレイヤーシステムを使用します。3Dノードのcollision_layer/collision_maskを再設定する必要があります。
- ライティングを忘れないでください — 3Dはライトがないと真っ暗になります(アンライテッドマテリアルを使う場合を除きます)。少なくとも1つのDirectionalLight3Dを追加してください。
- 3DでCamera2Dの追従ロジックを使わないでください — Camera3Dにはスプリングアームまたは注視点のロジックが必要です。位置を直接コピーすると、クリッピングや視点の混乱が発生します。
- 同じパフォーマンスだと思い込まないでください — 3Dは5〜10倍の負荷がかかります。ドローコールを減らし、モバイルではビューポートの解像度を下げることを想定してください。
- 複雑な3Dロジックにrotationプロパティを使わないでください — 3Dの回転にはオイラー角を使用します。オイラー角を補間すると、予測できない経路やジンバルロックが発生します。3Dの回転補間には必ず
Quaternionを、方向ベクトルにはBasis行列を使用してください。 - メートル単位のスケーリングを無視しないでください — 3Dの物理演算とライティングでは、1単位=1メートルを前提としています。エンジン内でモデルを拡大縮小すると、精度誤差が生じます。DCCから正しいメートル単位のスケールでアセットを書き出してください。
- カスタムカメラ追従スクリプトを使うときに、物理補間を無効にしないでください —
_physics_processで移動するボディを追従するために、_processでカメラの位置を更新すると、ジッターが発生します。スムーズなトランスフォームにはNode3D.get_global_transform_interpolated()を使用してください。
利用可能なスクリプト
必須:カメラや移動のレシピを貼り付ける前に、移行スクリプトを読み込んでください。
spring_arm_camera_setup.gd
三人称視点のSpringArm3D+Camera3Dには必須です。Camera3Dをボディに直接、親として追加しないでください。
characterbody3d_migration_movement.gd
2Dから3Dへの移植でカメラ相対のCharacterBody3D移動を実装するには必須です。
physics_layer_migration_checklist.gd
必須チェックリスト:3Dの物理レイヤー名は2Dとは別です。名前を揃えてから、ビットを適用してください。
sprite_plane.gd
Sprite3Dのビルボード設定と、3Dオブジェクトの上に2D UIを配置するためのワールドからスクリーンへの投影。
vector_mapping.gd
Vector2↔Vector3のマッピングヘルパー(YアップとZフォワードの落とし穴)。
crisp_projected_ui.gd
ダイジェティックUI/投影UIを鮮明に表示するパターン。
adapt_2d_to_3d_patterns.gd
ビルボード、マウスから3Dへのレイ、CanvasLayerオーバーレイのヘルパー。
navigation_bridge_2d5d.gd
2.5Dのスプライトアクター向けに、NavigationServer3Dのパスを2Dのスクリーン/ゲームプレイ平面に投影します。
massive_crowd_manager.gd
MultiMesh+ビルボードシェーダーによる群衆(GPUによる方向制御。ノードごとのSprite3Dではありません)。
読み込まないでください:ライティングの詳細解説はここでは読み込まず、godot-3d-lightingを参照してください。DirectionalLight3Dとアンビエントライトのみを追加してください。GI/カスケードについてはそちらで扱います。
ノード変換対応表
| 2Dノード | 3D相当 | 備考 |
|---|---|---|
| CharacterBody2D | CharacterBody3D | 必須 characterbody3d_migration_movement.gd |
| RigidBody2D | RigidBody3D | 重力はVector3(0, -9.8, 0) |
| StaticBody2D | StaticBody3D | Shape3Dリソース(自動変換なし) |
| Area2D | Area3D | トリガーの考え方は同じ。レイヤーは新規設定 |
| Sprite2D | MeshInstance3D / Sprite3D | ビルボードとメッシュのどちらでアートを表現するか選択 |
| Camera2D | Camera3D | 必須 spring_arm_camera_setup.gd |
| CollisionShape2D | CollisionShape3D | 形状を再作成 |
| RayCast2D | RayCast3D | target_positionはVector3 |
移行手順(スクリプト優先)
- 物理レイヤー — 必須
physics_layer_migration_checklist.gd。Project Settings → Layer Names → 3D Physics。 - カメラ — 必須
spring_arm_camera_setup.gd。Camera2D の追従処理を Camera3D にコピーしないでください。 - 移動 — 必須
characterbody3d_migration_movement.gd。カメラ相対の XZ 軸移動、Y 軸でジャンプ。
アート制作パイプライン:スプライト → 3D モデル
オプション 1:ビルボードスプライト(2.5D)
# Use Sprite3D for quick conversion
extends Sprite3D
func _ready() -> void:
texture = load("res://sprites/character.png")
billboard = BaseMaterial3D.BILLBOARD_ENABLED # Always face camera
pixel_size = 0.01 # Scale sprite in 3D space
オプション 2:クワッドメッシュ(浮遊スプライト)
# Create textured quads
var mesh_instance := MeshInstance3D.new()
var quad := QuadMesh.new()
quad.size = Vector2(1, 1)
mesh_instance.mesh = quad
var material := StandardMaterial3D.new()
material.albedo_texture = load("res://sprites/character.png")
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
material.cull_mode = BaseMaterial3D.CULL_DISABLED # Show both sides
mesh_instance.material_override = material
オプション 3:フル 3D モデル(Blender/Asset Library)
# Import .glb, .fbx models
var character := load("res://models/character.glb").instantiate()
add_child(character)
# Access animations
var anim_player := character.get_node("AnimationPlayer")
anim_player.play("idle")
ライティングに関する考慮事項
最低限、シーンが真っ暗にならないように DirectionalLight3D を 1 つと、環境光用の WorldEnvironment を 1 つ用意します。このスキルではカスケード/GI/ベイクに関するチュートリアルを読み込まないでください — godot-3d-lighting。
UI の適応
# ✅ GOOD: Keep 2D UI overlay
# Scene structure:
# Main (Node3D)
# ├─ WorldEnvironment
# ├─ DirectionalLight3D
# ├─ Player (CharacterBody3D)
# └─ CanvasLayer # 2D UI on top of 3D world
# └─ Control (HUD)
# UI remains 2D (Control nodes, Sprite2D for HUD elements)
パフォーマンス予算の設定(プロファイラーによる判定)
推測に基づく「2D 対 3D の予算」表は当てになりません。実測データに基づいて判定します。
- 対象ハードウェアで移植版を実行した後、Profiler/Debugger → Monitors を開きます。
- ドローコール/プリミティブ — MeshInstance の数が急増した場合は、頂点数の上限を推測する前に、Mesh LOD/Visibility Ranges を追加します。
- シャドウの負荷 — フレーム時間が回復するまで
directional_shadow_max_distanceと、シャドウを有効にした Omni/Spot の数を減らします(godot-3d-lighting で調整してください)。 - LOD の手順 — 遠方の GeometryInstance3D に
visibility_range_*を設定します。近距離帯より外側では、非ライティング/簡易マテリアルを使用します。 - 合格基準 — 表計算ソフトに「50–100 ドローコール」と書かれているかではなく、95 パーセンタイルのフレーム時間がプラットフォームの目標(例:60 FPS で ≤16.6 ms)を満たした場合にのみリリースします。
入力方式の変更
2D → 3D の入力マッピング
# 2D: left/right for horizontal movement
Input.get_axis("left", "right")
# 3D: Add forward/back, use get_vector()
var input := Input.get_vector("left", "right", "forward", "back")
# Returns Vector2(horizontal, vertical) for 3D movement
# Configure in Project Settings → Input Map:
# forward: W, Up Arrow
# back: S, Down Arrow
# left: A, Left Arrow
# right: D, Right Arrow
# Mouse look (lock cursor)
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event: InputEvent) -> void:
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
rotate_camera(event.relative)
エッジケース
物理が動作しない
# Problem: Forgot to set collision layers for 3D
# Solution: Reconfigure layers
var body := CharacterBody3D.new()
body.collision_layer = 0b0001 # What AM I?
body.collision_mask = 0b0110 # What do I DETECT?
カメラが壁を突き抜ける
必須の spring_arm_camera_setup.gd を使用し、spring_arm.collision_mask に World レイヤーを設定します。これにより、ブームが壁を突き抜けずに後退します。
プレイヤーが床をすり抜ける
# Problem: StaticBody3D floor has no CollisionShape3D
# Solution: Add collision
var floor_collision := CollisionShape3D.new()
var box_shape := BoxShape3D.new()
box_shape.size = Vector3(100, 1, 100)
floor_collision.shape = box_shape
floor.add_child(floor_collision)
3D に移行するかどうかの判断基準
| 要素 | 2D のままにする | 3D に移行する |
|---|---|---|
| ゲームプレイ | プラットフォーマー、見下ろし型、奥行き不要 | 探索、一人称視点、3D 空間での戦闘 |
| アートの予算 | ピクセルアート、リソースに制限あり | 3D モデルを利用できる、または必要 |
| パフォーマンス目標 | モバイル、ウェブ、低性能環境 | デスクトップ、コンソール、高性能モバイル |
| 開発期間 | 限られている | 3D の習得に時間をかけられる |
| チームのスキル | 2D アーティストのみ | 3D アーティスト、またはアセットライブラリ |
エキスパート向けテクニックと最適化
1. オイラー角ではなくベクトル演算を使う
3D キャラクターを移動させるときは、三角関数で角度を計算するのではなく、Transform3D の基底ベクトルを積極的に利用します。ローカル座標で前進させるには、トランスフォームの基底から負の Z 軸を取り出します:velocity = transform.basis.z * speed。
2. 座標系の違いを理解する
2D では Y 軸は下向きです。3D では Godot は右手座標系を使用し、Y 軸は上向き、前方は -Z です。2D のジャンプを 3D に移すには、Y 方向の速度の処理を反転させる必要があります(例:-JUMP_SPEED ではなく velocity.y = JUMP_SPEED)。
3. 2.5D ナビゲーション(カメラ投影パス)
3D の床上をアクターが移動し、2D スプライトとして表示される 2.5D ゲームでは、NavigationServer3D に直接問い合わせ、結果の PackedVector3Array を Camera3D.unproject_position で 2D 画面空間(または平面化したゲームプレイ平面)に投影します。
class_name NavigationBridge2D5D extends Node
## Projects 3D NavigationServer paths to 2D screenspace for 2.5D movement.
static func query_2_5d_path(camera: Camera3D, map_rid: RID, start_2d: Vector2, target_2d: Vector2) -> PackedVector2Array:
# 1. Project 2D screen points to the 3D ground plane (Y=0).
var start_3d := camera.project_position(start_2d, 0.0)
var target_3d := camera.project_position(target_2d, 0.0)
# 2. Query optimized 3D path.
var path_3d := NavigationServer3D.map_get_path(map_rid, start_3d, target_3d, true)
# 3. Project 3D world points back to 2D screenspace coordinates for the sprite.
var path_2d := PackedVector2Array()
for point in path_3d:
path_2d.append(camera.unproject_position(point))
return path_2d
4. シェーダーベースのビルボード化(大規模な群衆の描画)
数百万のインスタンスを描画するには、MultiMeshInstance3D とカスタム Visual Shader を組み合わせます。VisualShaderNodeBillboard で BILLBOARD_TYPE_FIXED_Y を使うと、平坦な地形上でスプライトを直立した状態に保てます。
class_name MassiveCrowdManager extends MultiMeshInstance3D
## Efficiently manages millions of camera-facing instances via GPU hardware.
func _ready() -> void:
# 1. Configure the MultiMesh for 3D transforms.
multimesh = MultiMesh.new()
multimesh.transform_format = MultiMesh.TRANSFORM_3D
multimesh.instance_count = 10000
# 2. Build a ShaderMaterial using VisualShaderNodeBillboard.
var material := ShaderMaterial.new()
# Note: Logic assumes billboard_type=BILLBOARD_TYPE_FIXED_Y and keep_scale=true.
multimesh.mesh = QuadMesh.new()
multimesh.mesh.surface_set_material(0, material)
# 3. Populate transforms. The GPU handles orientation.
for i in range(multimesh.instance_count):
var pos := Vector3(randf() * 100, 0, randf() * 100)
multimesh.set_instance_transform(i, Transform3D(Basis(), pos))
5. ライティングの移行
PointLight2D→OmniLight3Dへの変換は、エディターで一度だけ行う作業です。必要に応じて、プロジェクト用ツールを維持してください。継続的なライティングの品質改善は、godot-3d-lightingで行います。
詳細なレシピ(必要に応じて)
| トピック | リファレンス/スクリプト |
|---|---|
| 移行手順/パフォーマンスの基準 | migration-recipes.md |
| 2.5Dナビゲーションブリッジ/群衆ビルボード | エキスパート向けテクニックの本文+同梱スクリプト |
リファレンス
段階的な開示:特定のAPIを調査するときにのみ公式ドキュメントのリンクを開き、関連するスキルは関連分野へ移るときに読み込んでください。ナレッジ全体を事前に読み込まないでください。
公式ドキュメント
- Introduction to 3D — CanvasItem/Y軸下向きの2Dワールドから移行する際に採用する必要がある座標系、Node3D、カメラの基本事項です。
- Using transforms — Camera2Dの追従や2D回転の習慣に代わる、
Basis/Transform3D/Quaternionのパターンです。 - CharacterBody3D — CharacterBody2DからCharacterBody3Dへの変換後に使用する移行先の
move_and_slideAPIです(専用の3Dチュートリアルページはありません)。 - Physics introduction — 2D/3Dで異なるレイヤーシステム、単位(1 unit ≈ 1 m)、およびコピーした2Dマスクが使えなくなる重力ベクトルについて説明しています。
- Collision shapes (3D) — CollisionShape3Dの構成を再構築する際の、BoxShape2D/CapsuleShape2Dに相当するShape3Dについて説明しています。
- SpringArm3D — Camera2Dの位置を直接コピーする方法に代わる、三人称視点のブームと遮蔽物に応じたカメラの引き寄せについて説明しています。
- 3D lights and shadows — DirectionalLight3D/OmniLight3Dの最小構成です。ライトまたは非ライティングマテリアルがない3Dシーンは真っ暗になります。
- Environment and post-processing — 主光源の間も移行先が真っ暗にならないようにする、WorldEnvironmentの環境光について説明しています。
- Standard Material 3D — Sprite3D/QuadMeshでスプライトを平面に置き換える際の、ビルボード、透明度、シェーディングモードについて説明しています。
- Using GridMaps — 3DでTileMapLayer形式のレベルレイアウトに代わるMeshLibrary/GridMapについて説明しています。
- Importing 3D scenes — スプライトのパイプラインから実際のメッシュに移行する際の、GLB/FBXのスケールとアニメーションのインポートについて説明しています。
- Physics interpolation introduction — 物理ステップによる移動後、
_processでのカメラ追従に補間済みトランスフォームが必要な理由について説明しています。
関連スキル
前提条件
- godot-gdscript-mastery — Y→Z マッピングヘルパーを適用する前に、型付きの Vector2/Vector3 と Transform3D に習熟しておきます。
- godot-characterbody-2d — CharacterBody3D に移植する、元のプラットフォーマー/トップダウン移動のセマンティクスです。
- godot-2d-physics — 独立した 3D 物理レイヤーテーブルで再現する必要がある、既存の 2D レイヤー/マスク設計です。
- godot-input-handling —
Input.get_vectorとマウスキャプチャによる視点操作を使い、2D の左右移動をカメラ基準の XZ にマッピングします。
補完
- godot-camera-systems — 移植後に Camera2D の追従に代わる SpringArm3D/オービット/一人称視点のリグです。
- godot-3d-lighting — スプライトをライティングされたメッシュに変換した後に必要となる、DirectionalLight3D、シャドウ、環境光です。
- godot-3d-materials — QuadMesh と Sprite3D のアート移行に使う PBR/ビルボード/アルファマテリアルです。
- godot-3d-world-building — TileMapLayer のワールドを 3D に移行した後の GridMap、コリジョン生成、LOD です。
- godot-raycasting-queries — ポイントアンドクリック型の 3D 移植で使う、マウスからワールドへの
PhysicsRayQueryParameters3Dピックです。 - godot-ui-containers — ワールドコンテンツが Node3D になっても 2D のまま維持される CanvasLayer HUD です。
- godot-navigation-pathfinding — 画面やゲームプレイ平面への投影を維持する 2.5D ブリッジ用の NavigationServer3D パスです。
- godot-adapt-3d-to-2d — 平面化して戻すか、ハイブリッド 2.5D を維持するかを判断する際に使う、逆方向の適応ラティスです。
下流/利用者
- godot-performance-optimization — 3D 移植によって従来の 2D 描画コール/頂点数の予算を超えた場合に参照します。
- godot-platform-mobile — 3D 化後に LOD、シャドウの距離、解像度のトレードオフを迫られる、リリース対象のプラットフォームです。
マスター
- godot-master — ライブラリのルーターおよびミラー化されたモジュールのエントリです。複数領域にまたがる 2D/3D の課題をどのドメインスキルが担当するか確認する際に開きます。