Unityでのゲーム制作もChatGPTに任せたい

本記事は[Craft Egg Advent Calendar 2022](https://qiita.com/advent-calendar/2022/craftegg)の12/23の記事です。

12/22の記事は@ce_suzuki_ryoheiさんの[リクルートA3RTとAzureを用いて音声対話システムを作ってみた](https://qiita.com/ce_suzuki_ryohei/private/f301755690e84bc02e0a)
でした。

# はじめに

株式会社Craft EggでUnityクライアントエンジニアをしている中垣です。

[~~昨今は謝罪会見の台本もAIが作成する世の中ですが、~~](https://youtu.be/nDoqlXNmQgc)世間で話題のAI,　***ChatGPT***がコーディングもこなすという話を耳にしたので、Unityでのゲームプログラミングをどこまでやってもらえるのか実験してみました。

# ChatGPTについて

まずはChatGPTについて軽くおさらいしておきます。
https://chat.openai.com/
チャット形式でAIに質問を語りかけると、それの返答をしてくれます。
![スクリーンショット 2022-12-16 19.04.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/65c6b945-4d3e-33cb-81af-868bac032a65.png)
……と思いきや、結構ウソをついてきます。
![スクリーンショット 2022-12-16 18.43.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/ea5f7435-014e-9824-4d18-4e0da37982fa.png)

竹刀の読み方は(しない)ですし、84cmの竹刀は通常幼稚園児が使用する2尺8寸より短いです。また、年齢別に一般的な竹刀の長さや重さは決まっているので竹刀の長さを決めることが大切という感覚はあまり無いです。

知らない人からしたら自信満々に答えられると信じてしまう人もいるかも知れませんね。



# コードは書ける？
上記のような問答を多少楽しんだあと、他の人がどのような入力をしているかをTwitterなどで拝見したところ、指定した言語で指定した内容のコードができるという話を耳にしましたので一つ試してみました。
![スクリーンショット 2022-12-16 19.27.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/706f1a0e-a176-e905-0f0f-bdb6fbbbeb2d.png)
おお、ちゃんとできてる。ご丁寧に色が分かれたコードに使用法やコピーボタンまで。if文を習ったばかりの学生の宿題を一瞬で終わらせる実力はありそうです。

# Unityを使ってゲームを作ってもらう
さて、前置きはここまでにしてChatGPT君にゲーム制作をどこまで任せることができるか試してみます。

ちなみに、
![スクリーンショット 2022-12-20 12.20.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/afd4f669-055a-a467-ffee-24aa114ff23b.png)
とのことなのでクリエイティブはありません。画像や音楽を作成するAIもありますので併せて使用すれば必要な殆どの事柄をAIに任せることができるかもしれません。

### Unityバージョンの選定

まずはどのUnityバージョンをインストールすべきかを尋ねました。回答が冗長になってしまったので趣旨のみを要約すると
- 最新版が基本だが、プラットフォーム次第。
- PCの場合は最新版。
- Pre-releasesは使用しない。
との回答を頂いたので執筆時最新の2021.3.16f1をインストールし、以降使用します。

### 設計もしてもらう
今回は巷で流行ってるゲームを簡略化した仕様のゲームを作成できればと思いますので、「画面外から自機に向かって迫ってくる敵を避けてその時間を競う2D見下ろしビューのゲーム」の設計をしてもらいます。
![スクリーンショット 2022-12-19 15.44.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/33eb5337-bf42-0e10-df2b-008d14af25a9.png)

まだ弾を発射することは伝えてないもののあとから追加しようとしていたBulletクラスまで設計してもらえました。

では、敵味方どちらも弾を発射する仕様に変更してみましょう。

![スクリーンショット 2022-12-19 15.52.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/744363a4-b350-2f3e-d401-380436a91d6b.png)

なるほど、Bulletは敵味方でクラスは同一のものを使用する仕組みになるようですね。弾をタイプ分けしてCollisionDetectorで判別したりするのでしょうか。

GameObjectという命名だけ気になったので、ツッコミをいれてみました。
![スクリーンショット 2022-12-19 15.57.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/472db923-c9b7-3af0-0286-bff1c38cb5cb.png)
知っているなら最初から回避してほしい。ただ、融通が効かないように見えてしっかり修正を試みてもらえるのは便利ですね。今回はEntityを採用することにします。

### Prefabの構成もしてもらう
次はどんなPrefabがあればいいかも教えてもらいます。
![スクリーンショット 2022-12-19 16.45.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/cc2cd420-f7d0-87c3-c9b1-960e50fa084a.png)
...おや。GameManagerはPrefabにしないのかな？という疑問風修正を投げかけてみる。
![スクリーンショット 2022-12-19 18.29.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/697de05a-8e63-ab10-a6fe-4676409963c8.png)
やはり一から十までとはいかない雰囲気はあります。

### 処理を書いてもらう
ChatGPTから出力されたものをできるだけそのまま利用する縛りでコーディングしてみます。
特徴のあった問答を一例として抜粋して紹介します。

プレイヤーの操作はマウスカーソルに吸い付くような動きにしたいと依頼し出力されたコードは

    // 移動速度
    public float speed = 1.0f;
    // 目標の位置
    private Vector3 targetPosition;
    // 現在の位置
    private Vector3 currentPosition;
    // Start is called before the first frame update
    void Start()
    {
        // 初期位置は現在の位置
        currentPosition = transform.position;
    }
    // Update is called once per frame
    void Update()
    {
        // 目標位置をマウスカーソルの位置に設定
        targetPosition = Input.mousePosition;
        // 現在の位置から目標位置へのベクトルを計算
        Vector3 direction = targetPosition - currentPosition;
        // ベクトルを単位ベクトル化
        direction = direction.normalized;
        // 移動量を計算
        Vector3 moveAmount = direction * speed * Time.deltaTime;
        // 移動量が目標位置までの距離より大きい場合は、移動量を目標位置までの距離に設定
        if (moveAmount.magnitude > direction.magnitude)
        {
            moveAmount = direction;
        }
        // 現在の位置を更新
        currentPosition += moveAmount;
        // オブジェクトの位置を現在の位置に設定
        transform.position = currentPosition;
    }
上記のように出力されました。かなりコメントを入れてくれているのは助かる。しかしこのままだと画面上のマウスカーソルの位置がゲーム上の座標へ変換されていないため、思った挙動にならなかったです。

挙動の不具合を指摘したときは、

    void Update()
    {
        // マウスカーソルの位置を取得する
        Vector3 mousePos = Input.mousePosition;

        // マウスカーソルの位置を画面上の座標からワールド空間内の座標に変換する
        Vector3 worldPos = camera.ScreenToWorldPoint(mousePos);
    }

と変換の方法を教示してくれました。ただこの場合もそのまま使用するとz座標がcameraと同一になってしまい画面表示されない位置に移動してしまう不具合が出てしまいました。(これも指摘することでz座標を0にする処理を挟んでもらいました。）

このように
1. 欲しいコードを入力すると大体あってるコードが出力される。
1. バグが有った場合、バグを指摘すると治す方法を教えてくれる。
1. バグがなくなるまでこれを繰り返す。

というサイクルで書き進めることができました。簡単な作りとはいえほとんど自力でコーディングすることなくゲームのプロトタイプくらいのものが出来上がりました。

ただ、どう実装するか分かっている場合はこのサイクルを回すほうがかえって手間がかかってしまうことも高い確率であるだろうと思います。しかし、叩き台として利用するならば十分な働きをしてくれていると思いますし、不具合が出た際に例えば初学者が調べながら実装するなどといった状況では対話形式のためその場での修正が可能な点が有効な点だと感じました。



# 完成品の動作
![ezgif.com-gif-maker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2301970/e32aaa22-26fb-f80d-f5ac-a59dd7f3e8b0.gif)

大まかな実装
- マウスに自機がついてくる
- 敵がランダム位置にランダム範囲間隔秒で生成される
- 自機は一番近い敵に弾を発射する
- 敵は自機に弾を発射する
- 敵は弾が当たると消滅
- 自機に何発か弾が当たるとゲーム終了

※弾同士や敵同士がコリジョンしているのに関しては一旦良しということに自分はしましたが、これを回避したい場合の実装法もChatGPTに質問したら答えてもらえます。

# 終わりに
今回はChatGPTにできるだけ任せてゲームを制作してみました。体感は当初思っていたよりは楽できませんでしたが、とはいえここまでできたことに驚かされました。まだまだChatGPTにはできることが沢山あるようなので引き続き活用法を探して見たいと思います。

ここまでご覧いただきありがとうございました。

Craft Egg Advent Calendar 2022 明日は@tsune_ceさんの記事になります！

# 参考サイト
[ChatGPT使い方総まとめ](https://qiita.com/sakasegawa/items/82069c97a1ee011c2d1e)
[話題爆発中のAI「ChatGPT」の仕組みにせまる！](https://qiita.com/omiita/items/c355bc4c26eca2817324)