Claude CodeでUnityゲーム開発を進める — C#とCLIで検証する手順
Claude CodeはUnity EditorをCLIで動かし、C#の編集とコンパイル確認ができます。CLAUDE.mdの規約、バッチモードでのテストとビルド、フックでの自動化を扱います。
Claude CodeとUnity開発の役割分担
Claude CodeからUnityを使うには、UnityのCLI(コマンドライン引数)を呼び出します。C#スクリプトの編集、コンパイル確認、テスト、ビルドはこの経路で回せます。Editorの画面操作は含まれません。
| 作業 | Claude Code + CLI | 補足 |
|---|---|---|
| C#スクリプトの作成・修正 | Claude Code + CLIできる | 補足規約はCLAUDE.mdに書く |
| コンパイルエラーの確認 | Claude Code + CLIできる | 補足-batchmode -quitとログのerror CS |
| テスト実行 | Claude Code + CLIできる | 補足-runTests、結果はNUnit形式のXML |
| Playerのビルド | Claude Code + CLIできる | 補足-executeMethodで静的メソッドを呼ぶ |
| シーン編集・プレハブ配線 | Claude Code + CLIできない | 補足シーン・アセット操作はUnity公式MCPサーバーで扱える |
Unity Editorには-batchmodeや-runTestsといった引数が用意されており、エディタ画面を開かなくてもスクリプトの健全性を検証できます。この検証ループを権限設定とフックに組み込めば、書かせたC#スクリプトがコンパイルを通るかをその場で確認できます。テクスチャやFBXの設定を一括点検する流れはUnityのインポート設定の一括点検にあります。コンパイル待ちが長いプロジェクトでは、asmdefでAssemblyを分ける手順も選択肢になります。
書かせて検証させるまでの流れ
- 1
CLAUDE.mdに規約を置く
コンストラクタ禁止・実行順序への非依存・C# 9.0までの構文を書いておきます。
- 2
C#スクリプトを書かせる
ゲームロジックをMonoBehaviourとして実装させます。
- 3
バッチモードで検証する
コンパイルエラーはログの
error CS、テストはNUnit形式のXMLで読みます。 - 4
フックで自動化する
.csの編集直後に検証を走らせ、失敗をClaudeに返します。
シーンの組み立てやプレハブの配線、ライティング調整といったEditor GUI上の作業はClaude Codeの守備範囲外です。この領域まで自動化したい場合は、Unity Editorに組み込まれたMCPブリッジをClaude Codeに接続するUnity公式MCPサーバーをClaude Codeで使う方法が別の選択肢になります。本記事はMCPサーバーを使わず、CLAUDE.mdとコマンドライン引数だけでC#スクリプトのゲームロジックを書き進める手順に絞ります。
前提条件
次の2点を先に整えておきます。
- Unity Editor(Unity 6系、6000.x)でプロジェクトを一度は開いたことがある。本記事はUnity 6.6のマニュアルに基づきます
- Claude CodeのBash権限で、Unity Editorの実行ファイルパスへのコマンド実行を許可している(手順はステップ3で扱います)
ステップ1: CLAUDE.mdにMonoBehaviourの規約を書く
UnityのスクリプトはMonoBehaviourクラスを継承したC#ファイルとして書きます。Claude Codeに規約を渡さないと、一般的なC#クラスの流儀でコンストラクタを書いてしまうことがあります。Unity公式マニュアルは、MonoBehaviourの初期化にコンストラクタを使うとUnityの通常動作を妨げると明記しています。
CLAUDE.mdには次のような規約を書いておきます。
## Unityスクリプトの規約
- MonoBehaviourを継承するクラスにコンストラクタを書かない。初期化は`Awake`か`Start`で行う
- `Start`はゲームプレイ開始前に一度だけ呼ばれる。変数の初期化や他オブジェクトとの参照解決はここに書く
- `Update`は毎フレーム呼ばれる。移動や入力処理などフレームごとの処理はここに書く
- クラス名とファイル名を一致させる
- C# 9.0までの構文を使う。initアクセサー(init専用セッター)と共変戻り値は使わない。シリアライズ対象の型にrecordを使わない
- 同じイベント関数でも、異なるGameObject間・同じスクリプトの異なるインスタンス間で呼び出し順序は保証されない。順序に依存するロジックは書かない最後の1行は見落としやすい制約です。Unity公式マニュアルは、同じイベント関数が呼ばれる順序を異なるGameObject間で当てにできないと明記しています。あるオブジェクトのUpdateが別オブジェクトのUpdateより必ず先に呼ばれる、という前提でロジックを書くと、Editorやプラットフォームによって挙動が変わる不具合になります。順序が必要な場面では、書き方で解決せず、UnityのScript Execution Order設定で異なるスクリプト間の順序を明示します。
ステップ2: ゲームロジックをC#スクリプトとして書かせる
規約を渡したうえで、具体的な指示を出します。例えば「プレイヤーの左右移動を実装するPlayerMoverスクリプトを作って」と依頼すると、次のような形のスクリプトが返ってきます。
using UnityEngine;
public class PlayerMover : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5f;
private void Update()
{
float horizontal = Input.GetAxis("Horizontal");
transform.Translate(Vector3.right * horizontal * moveSpeed * Time.deltaTime);
}
}StartやAwakeを使わずコンストラクタを書いていない点、Updateにフレームごとの処理をまとめている点が規約どおりです。Unity 6.6のC#コンパイラはRoslynで、対応言語バージョンはC# 9.0です。C# 10以降で追加された構文(ファイルスコープ名前空間やrequired修飾子など)を書かせると、コンパイルエラーになります。C# 9.0の中にも非対応の機能があり、init専用セッターと共変戻り値がその例です。シリアライズ対象の型にrecordを使うのも避けます。新しい構文を書かせると踏みやすい落とし穴なので、CLAUDE.mdに「C# 9.0までの構文を使う」と明記しておくと安全です。
サンプルで使ったInput.GetAxisはレガシーのInput Managerが提供するAPIです。Unity公式マニュアルは、Input Managerはレガシー機能であり新規プロジェクトには推奨しないとし、新規プロジェクトにはInput Systemパッケージの使用を案内しています。既存プロジェクトがどちらを使っているかはClaude Codeからは判別できません。CLAUDE.mdに「このプロジェクトはレガシーInput Managerを使う」か「Input SystemパッケージのInputActionを使う」かを明記しておくと、書かせるコードの入力処理が食い違いません。Input Systemを選んだ場合の.inputactionsの編集と検証はClaude CodeでUnityのInput Systemを設定する手順にあります。
ステップ3: バッチモードでコンパイルとテストを検証する
Unity Editorは-batchmodeを付けて起動すると、ダイアログ表示なしでコマンドライン引数だけを処理します。まずBash権限で実行ファイルへのコマンドを許可します。
{
"permissions": {
"allow": [
"Bash(/Applications/Unity/Hub/Editor/6000.6.0f1/Unity.app/Contents/MacOS/Unity -batchmode *)"
]
}
}*より前の文字列は書かれたとおりに照合されます。そのためバージョン番号は固定し、以降の3つの例も-batchmodeを先頭の引数にそろえます。-runTests -batchmodeのように順序を変えると、このルールには一致しません。実行ファイルのパスを二重引用符で囲んだ形や、行継続の\を挟んだ形がこのルールに一致するかは、権限のドキュメントに記載がありません。一致しなければ確認プロンプトが出るだけで、実行は止まりません。以降の例は引用符なしで書きます。末尾が*なので、-executeMethodで渡す任意の静的メソッドも同じルールで通る点には注意が必要です。設定の詳細はBash権限ルールの複合コマンド判定で扱っています。
コンパイルエラーの有無は、プロジェクトを開いて即座に終了させ、ログファイルを読む形で確認します。
/Applications/Unity/Hub/Editor/6000.6.0f1/Unity.app/Contents/MacOS/Unity \
-batchmode -quit -nographics -accept-apiupdate \
-projectPath . \
-logFile /tmp/unity-check.log
echo "exit code: $?"
cat /tmp/unity-check.log | grep -i "error CS"バッチモード中に例外が発生するとUnityは終了コード1で終了します。ただしコンパイルエラーの有無は、終了コードよりログで見るのが確実です。-logFileのログをerror CSでgrepすれば、エラー番号付きのメッセージを拾えます。この形式はRoslynの標準的な診断表記に基づくもので、Unityのマニュアルには明記がありません。コンソール出力は最小限に絞られ、-quitは一部のエラーメッセージを隠すことがあります。どちらも全情報はログファイルに残ります。-nographicsではログ出力が止まるので、-logFileは省略できません。
テストを回す場合はUnity Test Frameworkのコマンドライン引数を使います。ゲーム内テキストの多言語化は、Claude CodeでUnityのテキストをローカライズする手順にまとめています。動作が重いときの切り分けはClaudeでUnityのProfilerキャプチャを読む手順が扱います。
/Applications/Unity/Hub/Editor/6000.6.0f1/Unity.app/Contents/MacOS/Unity \
-batchmode -runTests \
-projectPath . \
-testPlatform EditMode \
-testResults /tmp/unity-test-results.xml-testPlatformはEditModeかPlayMode、または特定のビルドターゲットを指定します。未指定ならEdit Modeテストが走ります。-testfilterで対象テストを名前や正規表現で絞り込め、-assemblyNamesでテストアセンブリをセミコロン区切りで指定できます。結果はNUnit形式のXMLとして-testResultsのパスに出力されるので、Claude Codeにこのファイルを読ませて失敗内容を伝えれば、修正の材料になります。テスト対象のUnityコンポーネントが返す終了コードには、今のところ共通の定義がありません。原因の切り分けにはエラーメッセージとスタックトレースを読むのが最良の方法だとされています。
ステップ4: コマンドラインでビルドする
Playerのビルドもコマンドラインから実行できます。必須の引数は-projectPathと-quit、推奨されるのは-batchmodeと-logFile、それに-buildTargetか-activeBuildProfileです。
/Applications/Unity/Hub/Editor/6000.6.0f1/Unity.app/Contents/MacOS/Unity \
-batchmode -quit \
-projectPath . \
-buildTarget StandaloneOSX \
-executeMethod BuildScripts.BuildMacOS \
-logFile /tmp/unity-build.log-executeMethodにはビルド処理を書いた静的メソッドを渡します。Unity公式マニュアルは、1回のコマンド実行で複数のビルドターゲットを切り替えられない点を明記しています。プラットフォームを変えると内部でエディタアセンブリの再読み込みが発生し、スクリプト実行中にその切り替えが反映されないためです。Windows向けとmacOS向けを両方ビルドしたい場合は、ターゲットごとにUnityプロセスを分けて起動します。
Claude CodeのフックでUnity検証を自動化する
C#ファイルを編集するたびに手動でバッチモードコマンドを打つのは手間です。PostToolUseフックにEdit(*.cs)という条件を付けると、Claudeが.csファイルを編集した直後にだけ検証スクリプトを走らせられます。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"if": "Edit(*.cs)",
"command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/unity-compile-check.sh"
}
]
}
]
}
}ifフィールドは権限ルールと同じ書式でツール呼び出しを絞り込みます。unity-compile-check.shの中身は、ステップ3の-batchmode -quit -logFileコマンドとログのerror CS検索をまとめたシェルスクリプトです。次のように書けます。
#!/bin/bash
UNITY="/Applications/Unity/Hub/Editor/6000.6.0f1/Unity.app/Contents/MacOS/Unity"
LOG="${TMPDIR:-/tmp}/unity-check.log"
"$UNITY" -batchmode -quit -nographics -accept-apiupdate \
-projectPath "$CLAUDE_PROJECT_DIR" -logFile "$LOG"
status=$?
if grep -q "error CS" "$LOG"; then
grep "error CS" "$LOG" | head -20 >&2
exit 2
fi
if [ "$status" -ne 0 ]; then
echo "Unity exited with code $status" >&2
exit 2
fi失敗時にexit 1ではなくexit 2を返す点が要です。フックの終了コード1はブロッキングでないエラーとして扱われ、処理はそのまま進みます。PostToolUseは終了コード2のときだけ、stderrの内容がClaudeに渡ります。ツールは実行済みなので止められませんが、error CSの行を読んだClaudeは修正に進めます。終了コード0で終えたフックのstderrはデバッグログにしか残りません。
このフックには実行コストがあります。.csを1回編集するたびにUnityが起動するため、大きなプロジェクトではインポートに時間がかかります。commandフックの既定タイムアウトは600秒です。
失敗するテストを起点に実装を進める考え方はClaude Codeでテスト駆動開発(TDD)を回す手順とも重なるので、あわせて確認すると設計の参考になります。フックの仕組み自体はClaude Code Hooks完全ガイドにイベント一覧があります。
CLIワークフローとUnity公式MCPサーバーの使い分け
同じ「Claude CodeでUnityを触る」でも、CLIバッチモードとUnity公式MCPサーバーでは向いている作業が違います。
作業で選ぶ2つの経路
CLIバッチモード(本記事)
C#スクリプトの編集・コンパイル確認と-runTestsによるテスト実行は、ログとXMLで結果を読めます。Editorの画面を開かずに完結するので、CI/CDにも組み込めます。反対に、Editor GUI上のシーン編集やプレハブ配線はできません。コンソールログもファイル経由の間接的な確認になります。
Unity公式MCPサーバー
シーン作成やGameObject・アセットの操作を組み込みツールで自動化でき、コンソールログはUnity_ReadConsoleで直接取得できます。一方でEditorを開いておくことが前提になり、-runTestsのようにCI的に回す用途には向きません。
C#スクリプトの実装とコンパイル確認を繰り返す局面ではCLIバッチモードが手早く、シーンやアセットをEditor越しに触りたい局面ではMCPサーバーに分があります。両方を併用し、ロジックの実装はCLIで、シーンへの配置はMCPサーバー経由で進める組み合わせも成立します。Quest向けの開発では、MetaのVR開発用プラグインも選べます。
よくあるつまずき
検証コマンドが動かないとき
Editorで開いたまま実行した
同じプロジェクトを開いているEditorが残っていると、バッチモードでは開けません。Editorを閉じるか、別のコピーで検証します。フックの検証も、Editorを開いたままでは毎回失敗します。
`-runTests`の結果ファイルが出ない
-quitを付けていると、進行中のテストが終わる前にEditorが終了します。-runTestsのコマンドには-quitを付けません。古いAPIを使うコードでコンパイルが通らない
バッチモードでは
-accept-apiupdateを付けない限りAPI Updaterが動きません。古いAPIを使うコードが混ざると、それだけでコンパイルエラーになりえます。
MonoBehaviourにコンストラクタを書かせてしまう失敗は、CLAUDE.mdへの明記に加えて、レビューでpublic PlayerMover()のような記述が混ざっていないか目視で確認すると安心です。イベント関数の実行順序に依存した記述も同じ扱いで、Startで他のGameObjectの初期化済み状態を前提にしていないか見ます。
まとめ
ゲームロジックのC#はCLIの検証ループで回せます。シーンやプレハブなどEditor GUI側の操作が必要になった段階で、Unity公式MCPサーバーを足す形です。フックで検証を自動化する場合は、Editorを閉じて作業できるかが前提になります。Steamで配信するなら、素材の由来を整理する手順をSteamコンテンツサーベイのAI開示欄にまとめています。敵やアイテムの定義をデータ駆動にするなら、ScriptableObjectの設計手順が続きです。シェーダーの見た目はログだけでは確かめにくいため、撮影した画像で確かめる手順をClaude CodeでUnityシェーダーを書かせる手順に置いています。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。
- docs.unity3d.com/6000.6/Documentation/Manual/class-MonoBehaviour.html
- docs.unity3d.com/6000.6/Documentation/Manual/execution-order.html
- docs.unity3d.com/6000.6/Documentation/Manual/csharp-compiler.html
- docs.unity3d.com/6000.6/Documentation/Manual/class-InputManager.html
- docs.unity3d.com/6000.6/Documentation/Manual/EditorCommandLineArguments.html
- docs.unity3d.com/6000.6/Documentation/Manual/build-command-line.html
- docs.unity3d.com/6000.6/Documentation/Manual/test-framework/run-tests-from-…
- docs.unity3d.com/6000.6/Documentation/Manual/test-framework/reference-comma…
- code.claude.com/docs/en/permissions
- code.claude.com/docs/en/hooks