UnityMCP + Claude に頼りミニゲームを作成した

# UnityMCP + claude に頼りミニゲームを作って作成した

## 背景

Unityの触りとMCPに触れてみる学習の為に行いました。
作ってみてわかったことを記載します。

触る前の筆者の知識レべルは以下です。
* UnityはUnity5時代の入門書を1冊読んだくらい
* AI関連の経験はエディタプラグインでのコーディング補助利用がある程度

## 制作したもの

マウス操作で遊ぶトランポリンゲームです。以下から遊べます。
* https://peperontium.github.io/ball_and_trampoline/

![ss_min.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725769/dc49a49a-f767-42e9-8c10-3b8df0a459b4.jpeg)

簡単な説明
* 左下から一定間隔でボールが発生します
* マウスドラッグでトランポリンを引け、ボールを跳ね返せます
  * 短く線を引いたり、ボールが線の中心付近に当たったりすると強く跳ね返せます
* ボールがゴールに入ると得点を得られます

## 環境

* Unity6 6000.1.0f1
* Claude 3.7 Sonnet (無料版)

MCPサーバの構築は以下の記事･ドキュメントを参考に行いました。
エラー無くセットアップが完了しても接続されていない場合、pythonのバージョンが古い可能性もあります。

https://modelcontextprotocol.io/quickstart/server#set-up-your-environment

https://zenn.dev/bamboohouse/articles/d8df41a995f818#1.-python%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB

## 制作の流れ

今回は冒頭にも上げたような玉入れゲームを制作することにしました。
マウスやタップ入力のみで完結する、Unityの基本機能(物理演算)を利用できる、状態制御が複雑にならなさそう辺りが理由です。

まずは、ゲームに必要となりそうな構成要素を整理します。

* **タイトルシーン**
  * ゲーム開始ボタン
  * 過去のハイスコア表示
* **ゲームシーン**
  * ボール
    * 重力の影響を受けて落下する
    * 画面下に落ちたら得点減算
  * ゴールエリア
    * ボールが触れた場合、得点加算しボール削除
  * スタート地点
    * 一定時間間隔でボールを発生させる
  * トランポリン
    * ボールがぶつかると面の方向に跳ね返す
    * 中心付近にボールが当たった場合、跳ね返す力が強くなる
    * マウスドラッグで線を引くことで配置できる
  * 残り時間タイマー
    * 0になったらゲーム終了
  * 得点記録
    * タイトルシーンと共有する

これらを元に、細かな実装タスクへ分解整理→ Claudeに依頼→ 結果を調整、の流れを繰り返して制作しました。

途中確認ダイアログ等が出てくるので、内容確認の上で進めていきます。

**Unity側確認ダイアログ例**
* Script Updating Consent
* ![17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725769/a42808e8-9694-4273-a4ff-fa56164f83da.png)
  * .csファイルが外部から変更されたけど更新していい？バックアップ撮らなくていい？と聞かれます
  * Claudeが.csスクリプトを編集した際に出てくるので、問題なければYesで許可しておきます

**Claude側エラー例**
* 「Claudeの応答が中断されました」
    * ![4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725769/04a20080-b276-473d-90f7-682146923e1d.png)
  * 1チャット内での会話メッセージ制限に引っかかっていると思われます
  * 別チャットを開いて操作を試してみてください
* 「予期せぬ容量制限により、Claudeは現在応答できません」
    * ![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2725769/cb0c8e10-eb24-4256-9b96-af6cbea18aaa.png)
  * 1日のメッセージ数制限に引っかかっていると思われます
  * 記載の通り有料版利用するか、日をまたいで制限解除されるのを待ちましょう
* 他にスクリーンショット撮り忘れましたが、UnityMCPサーバの操作を許可するかどうかを聞かれました
  * MCPサーバを通じてタスク実行して欲しいので、内容確認の上許可しておきます

### 入力例

以下は実際の入力の一例です。

**ボールの自動生成**
一定時間間隔でボールを生成し、初速を与えて射出する機能の作成を依頼しました。

<details>

* プロンプト

```
Unityでゲーム開発をしています。
エディタ上ではGameSceneを開いています。
GameSceneには "名称(種類)" の形式で記載した以下のオブジェクトを配置済です。

* Canvas(Canvas)
  * Background(Image)
* 2D Camera(Camera)
* Ball(Rigidbody 2D, Circle Collider 2D)
* Global Light 2D(Light 2D)

このSceneにて、一定時間間隔でBallを生成し配置してほしい。
配置したBallには上方向の速度を与えてほしい。
```

* Claude応答
  * ()内はMCPサーバとの通信を行っていた箇所です

```

ご依頼いただいたボールを一定時間間隔で生成して上方向に速度を与える機能を実装します。これには以下の手順が必要です：

1. ボール生成を制御するスクリプトを作成
2. そのスクリプトをシーンの適切なオブジェクトにアタッチ
まず、ボール生成を管理するスクリプトを作成しましょう：

(manage_script)

次に、このスクリプトをシーンに追加するためのGameObjectを作成します：

(manage_gameobject)

すみません、先にスクリプトコンポーネントを追加するには、Unityが新しいスクリプトをコンパイルする必要があります。空のGameObjectを先に作成し、その後でスクリプトをアタッチしましょう：

(manage_gameobject)

次に、既存のBallオブジェクトをプレファブ化して、スポナーが複製できるようにします：

(manage_gameobject)

ボールオブジェクトをプレファブとして保存します：

(manage_gameobject)

Prefabsフォルダがないかもしれないので、まず作成します：

(manage_asset)

フォルダを作成したので、ボールオブジェクトをプレファブとして保存します：

(manage_asset)

すみません、別のアプローチを試します。まずはGameObjectをプレファブ化します：

(manage_gameobject)

申し訳ありません。システムの制約により、プレファブの作成が難しいようです。別のアプローチを取りましょう。既存のBallオブジェクトをスクリプトからコピーする形で実装します。
BallSpawnerスクリプトを以下のように更新します：

(manage_script)

次に、作成したBallSpawnerコンポーネントをBallSpawnerオブジェクトにアタッチします：

(manage_gameobject)

次に、BallSpawnerコンポーネントにoriginalBallを設定します：

(manage_gameobject)

元のボールは見えているが生成に使うだけにしたいので、非表示にします：

(manage_gameobject)

シーンを実行して確認するために、Playモードを開始します：

(manage_editor)

これで一定間隔でボールが生成され、上方向に移動するようになりました。以下は実装の概要です：

1. **BallSpawnerスクリプト**:
   - 一定間隔（デフォルト2秒）でボールを生成
   - 生成したボールに上方向の速度を設定
   - ランダムなX座標位置に生成
   - 元のボールをテンプレートとして使用
2. **パラメータ設定**:
   - `spawnInterval`: ボール生成の間隔（秒）
   - `initialUpwardSpeed`: ボールに与える上方向の初期速度
   - `minX`と`maxX`: 生成するX座標の範囲
   - `spawnY`: 生成するY座標の位置

必要に応じてBallSpawnerコンポーネントのインスペクターからこれらの値を調整できます。元のボールはテンプレートとして使用されているため非表示にしています。
実行を止めるにはStopボタンを押してください：
```

</details>

Scene内から作成済のボールを探してコピー生成する、生成用スポナークラスを作成してくれました。
途中Prefab作成に失敗して方法変えていますが、これは私がUnity側に出ていた許可ダイアログに気づき遅れて応答なし扱いされたことが原因です。


**画面外のボールを削除**

画面外に出たボールを消して、その数を記録する機能の作成を依頼しました。

<details>

* プロンプト

```
Unityでゲーム開発をしており、エディタ上でGameSceneを開いています。
GameSceneには "名称(種類)" の形式で記載した以下のオブジェクトを配置済です。

* Canvas(Canvas)
* 2D Camera(Camera)
* Global Light 2D(Light 2D)
* Ball(Rigidbody 2D, Circle Collider 2D)
* 
重力を受け落下しているBallだが、画面外に出てカメラに映らなくなったら削除したい。
また削除したBallの数は記録しておき、画面にテキストで表示したい。
```

* Claude応答

```
Unity上でバウンドやカメラ視界外の球体を削除し、削除数を表示するゲームを作りたいですね。これを実現するために次のステップで進めていきましょう。

1. ボールを削除するスクリプト（BallDestroyer）
2. 削除数をカウントし表示するスクリプト（ScoreManager）

では順番に作成していきます。

1. まずはBallDestroyerスクリプトを作成しましょう

(manage_script)

2. 次にScoreManagerスクリプトを作成します

(manage_script)

3. 現在のシーン階層を確認しましょう

(manage_scene)

4. Canvasに削除数表示用のTextを追加

(manage_gameobject)

TextMeshProUGUIコンポーネントが見つからないようです。TextMeshProパッケージがインポートされているか確認する必要があります。まずは通常のUnityのTextコンポーネントを使ってみましょう。

(manage_gameobject)

5. ScoreManagerスクリプトを修正して、UIのTextコンポーネントを使うように調整します

(manage_script)

6. ScoreManagerオブジェクトを作成

(manage_gameobject)

7. ScoreManagerにBallCountTextを設定

(manage_gameobject)

8. Ball（ボール）オブジェクトにBallDestroyerスクリプトをアタッチ

(manage_gameobject)

現在シーン上にBallオブジェクトがないようです。新規にボールを作成し、必要なコンポーネントを追加しましょう。

(manage_gameobject)

3Dプリミティブと2Dコンポーネントの互換性の問題が起きたようです。代わりにSphereではなく、空のGameObjectを作成し、2Dコンポーネントを追加します。

(manage_gameobject

9. ボールを円形に表示するため、Sprite設定が必要です。デフォルトの円形スプライトを設定するスクリプトを作成

(manage_script)

すでにBallSpawnerスクリプトが存在するようです。既存のスクリプトを更新しましょう。

(manage_script)

すでに良いBallSpawnerスクリプトがあるようです。それでは現在のシーンにBallDestroyerコンポーネントを追加しましょう。

(manage_gameobject)

10. シーンを保存しましょう

(manage_scene)

完成しました！

これで設定が完了しました。システムの動作フローは以下のようになります：
1. BallSpawnerが定期的にボールを生成します
2. ボールは画面下部から上向きの初速を持って飛び出し、重力によって落下します
3. 画面外に出たボールはBallDestroyerスクリプトによって検出され、削除されます
4. ボールが削除されるたびに、ScoreManagerの削除カウントが1増加します
5. 削除されたボールの数はCanvas上のBallCountTextに表示されます

ゲームを実行するには、以下のようにして再生モードを開始します：

(manage_editor)

ゲームが実行中です。ボールが生成され、画面外に出たボールが削除されるたびにカウントが増加していることを確認できるはずです。

何か調整や追加の機能が必要でしたら、お知らせください。例えば：
- ボールの見た目のカスタマイズ
- 削除されたボール数に応じたゲームプレイの変化
- ボールの発射速度や重力の調整
- ボールの生成頻度の調整

などが可能です。
```

</details>

「削除」と「記録」をまとめて依頼していて分割が甘いのですが、それでもちゃんと段階を踏んで実装してくれていました。
作成後、テキストのサイズが画面に対し大きすぎたので手動調整しました。

## 感じたことわかったこと

ニワカ知識の手探り指示でしたが、一通り遊べるゲームに仕上がってくれました。
直接指示していなくても、操作性に関わる部分を配慮して生成してくれたのが印象的でした。
実際にClaude側で追加してくれた機能例としては、以下があります。
 * トランポリン配置途中はプレビューを表示する
 * カウントダウン中は操作やボール出現を止める

ただ、最低限入門レベルのUnity知識はあったほうが良さそうです。

当たり前ですが、Claudeがエージェントとしてタスクを細分化･実行する過程での応答には、基本的なUnity用語や頻出するコンポーネント名も含まれます。
調べれば出てくる内容ではありますが、簡単なものは抑えておいた方がスムーズに受け答えを行えます。

また、Claudeが配置したものをUnityエディタ上で微調整することもしばしばありました。
コライダーの位置調整や、GUIのスケーリング調整といったワンタッチで終わる操作は、一々チャットで応答するよりもさっと手で直す方が早いです。

その他、無料版で試したからと思われますが、会話数の制限が厳しかったです。
今回は対策として、最初のプロンプトにオブジェクトツリーを含めて伝えてあげるようにしていました。
あとは依頼タスクを予めこちらで分解して渡すくらいでしょうか… この辺りは一般的なプロンプトの話に通じる気がします。

----------

以上となります。
参考になる点があれば幸いです。