😠

【緊急検証!!】 『ChatGPT』はホワイトカラー共を 鮮血に染める革命のギロチンなのか?! 【Unity製インベーダーゲームを作らせる】

2023/01/09に公開

はじめに

最近界隈を賑わせている『ChatGPT』。
何者なのかというと
質問したら答えてくれるAI
みたいなもんなのだが、こいつがホワイトカラー殺しなんじゃないかとざわつきを見せている。
現に海外の大学生は論文を大筋これで生成してしまって、
仕上げだけ自分でやる、みたいな事が起きているらしい。

いわゆる『頭脳労働者』、つまりホワイトカラーって呼ばれるような奴らの
働き場所が無くなってしまうんじゃないか...
そういう類の、新しい技術の台頭が生み出す変化というものは、
いつの時代も期待と恐怖の入り混じった視線を向けられるものだ。
窓を叩いて客を起こす目覚まし屋さん達も
目覚まし時計が開発された時分にはそうとう焦ったはずである。

俺たちはこの目で確かめる必要がある。
未来からやってきたスカイネットの底力を。

実際にChatGPTがどれだけの力を持っているのか。
検証する方法は分野によって様々だが、
俺はUnityエンジニアだ。
だから簡単なゲーム、往年の『インベーダーゲーム』をテーマに
AIに制作をぶん投げてしまおうと思う。

検証する上でのルールは以下の通り。

  • Unity入門者による作業を想定(最低限操作は知ってるがほとんどコードは書いた事ない)
    • AIにコード書かせてもUnityの操作は必要になる為
    • コードはなるべく書かない
  • 設定とかの説明入れるのは本筋から外れるので画像とかは用意しない。
    • デフォルトで用意されてる適当なオブジェクトを使う。

以上のルールでAIの力を推し量ろうと思う。

『ChatGPT』は現代に生きる我々の超過残業を駆逐する一筋の光なのか?
それとも、ホワイトカラー共を鮮血で染める革命のギロチンなのか?

AIとの邂逅、そして、その記録1

ChatGPTを開いて俺は以下の質問を投げた。

井上

Unityで動くインベーダーゲームのコードを書いて

それに対してAIの返事が1行ずつタイプされていく。

ChatGPT

いただけませんか?

Unityでインベーダーゲームを作成するには、次のような手順を踏むことができます。

1. Unityのプロジェクトを作成し、必要なアセットをインポートします。これには、プレイヤーキャラクター、敵キャラクター、背景、およびゲームUIなどが含まれます。

2.プレイヤーキャラクターを動かすためのコントロールを作成します。これには、キーボードやゲームパッドなどの入力デバイスを使用することができます。

3.敵キャラクターを作成し、それらを自動的に画面の下から移動させます。また、プレイヤーが敵を倒した際には、スコアを加算するようにします。

4.ライフやスコアなどのゲーム状態を表示するUIを作成します。

5.ゲームをクリアするための条件を設定します。例えば、すべての敵を倒したときや、プレイヤーのライフが0になったときなどです。

6.ゲームオーバーやゲームクリア時のシーンを作成します。

これらの手順を踏むことで、Unityを使用してインベーダーゲームを作成することができます。

ご参考までに、次に簡単なインベーダーゲームのコードを示します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    //プレイヤーの移動スピード
    public float speed = 10.0f;

    // Update is called once per frame
    void Update()
    {
        //左右の移動
        float x = Input.GetAxis("Horizontal");

        //プレイヤーを移動させる
        transform.position += new Vector3(x, 0, 0) * Time.deltaTime * speed;
    }
}
このコードは、キーボードからの入力を受

ここで返答は途切れてしまった。
なんらか文字数制限かなんかがあるのかもしれない。
特にプラットフォームの指定をしていたわけではなかったので、
とりあえずキーボード入力での操作を前提として実装したことを伝えてくれているんだと思う。

それにしても驚いた。
AI相手だからとはいえ、
「Unityで動くインベーダーゲームのコードを書いて」
なんぞいくらなんでも雑すぎる無茶振りに対して、

  • ざっくりとした仕様書としても使える箇条書きの作業指示
  • 仕様2・3で触れている実装のサンプルコード

ここまでの粒度で答えてくれている。
コードも一応動きそうな雰囲気を醸し出している。
一度ここまで実装してみることにした。

人間の作業

作業1『プロジェクト作成とアセットインポート』

  1. Unityのプロジェクトを作成し、必要なアセットをインポートします。これには、プレイヤーキャラクター、敵キャラクター、背景、およびゲームUIなどが含まれます。

まずプロジェクト作成

作業2『プレイヤーを作成』

2.プレイヤーキャラクターを動かすためのコントロールを作成します。これには、キーボードやゲームパッドなどの入力デバイスを使用することができます。

テキトーなプリミティブを用意。
生成されたPlayerController.csをコピペして作成。
それをアタッチする。
それっぽい位置に移動させる。(2DゲームなのでカメラをOrthographにしたけどお好みで)

左右矢印キー押したら動いた

なるほど、これは感慨深いものがある。

AIに「Unityで動くインベーダーゲームのコードを書いて」と雑に振っただけで

  • 仕様の概略とUnity上での作業指示
  • 実際に使うコード

こいつらが吐き出されて、しかも一応動くという結果になった。

井上は続きが気になった。

AIとの邂逅、そして、その記録2

井上

続きを書いて

ChatGPT

頂けますでしょうか?

次に、敵キャラクターを自動的に移動させるコードを示します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class EnemyController : MonoBehaviour
{
    //敵の移動スピード
    public float speed = 5.0f;

    // Update is called once per frame
    void Update()
    {
        //画面下へ移動する
        transform.position += new Vector3(0, -1, 0) * Time.deltaTime * speed;
    }
}
また、ゲームの状態を表示するUIを作成するためのコードを示します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class UIController : MonoBehaviour
{
    //スコアを表示するテキスト
    public Text scoreText;

    //スコア
    private int score;

    // Update is called once per frame
    void Update()
    {
        //スコアを表示する
        scoreText.text = "Score : " + score;
    }

    //スコアを加算する
    public void AddScore(int value)
    {
        score += value;
    }
}
これらのコードを組み合わせることで、Unityを使用して簡単なインベーダーゲームを作成することができます。

井上

続きを書いて

ChatGPT

いただけますでしょうか?

次に、ゲームをクリアするための条件を設定するコードを示します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameController : MonoBehaviour
{
    //プレイヤーのライフ
    public int playerLife;

    //ゲームクリア条件
    public int enemyCount;

    // Update is called once per frame
    void Update()
    {
        //すべての敵を倒したかどうかを判定する
        if (enemyCount <= 0)
        {
            //ゲームクリア処理を呼び出す
            OnClear();
        }

        //プレイヤーのライフが0になったかどうかを判定する
        if (playerLife <= 0)
        {
            //ゲームオーバー処理を呼び出す
            OnGameOver();
        }
    }

    //ゲームクリア処理
    void OnClear()
    {
        //ゲームクリア画面を表示する
    }

    //ゲームオーバー処理
    void OnGameOver()
    {
        //ゲームオーバー画面を表示する
    }
}
最後に、ゲームオーバーやゲームクリア時のシーンを作成するコードを示します。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneController : MonoBehaviour
{
    //ゲームクリアシーンのシーン名
    public string clearSceneName;

    //ゲームオーバーシーンのシーン名
    public string gameOverSceneName;

    //ゲームクリア処理
    public void OnClear()
    {
        //ゲームクリアシーンに遷移する
        SceneManager.LoadScene(clearSceneName);
    }

    //ゲームオーバー処理
    public void OnGameOver()
    {
        //ゲームオーバーシーンに遷移する
        SceneManager.LoadScene(gameOverSceneName);
    }
}
これらのコードを組み合わせることで、Unityを使用してインベーダーゲームを作成することができます。

井上

続きを書いて

ChatGPT

いただけますでしょうか?

その他にも、ゲームに必要な処理を記述することで、より複雑でリアルなゲームを作成することができます。

例えば、ゲーム内で使用するオーディオを制御するコードは次のようになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AudioController : MonoBehaviour
{
    //BGMを再生するためのオーディオソース
    public AudioSource bgmSource;

    //SEを再生するためのオーディオソース
    public AudioSource seSource;

    //BGMを再生する
    public void PlayBgm(AudioClip clip)
    {
        //BGMを停止する
        bgmSource.Stop();

        //BGMを設定する
        bgmSource.clip = clip;

        //BGMを再生する
        bgmSource.Play();
    }

    //SEを再生する
    public void PlaySe(AudioClip clip)
    {
        //SEを停止する
        seSource.Stop();

        //SEを設定する
        seSource.clip = clip;

        //SEを再生する
        seSource.Play();
    }
}
また、ゲームで使用する画像を切り替える処理は次のようになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ImageController : MonoBehaviour
{
    //画像を切り替える対象のImageコンポーネント
    public Image image;

    //切り替える画像のリスト
    public List<Sprite> imageList;

    //現在表示している画像の番号
    private int currentImageNumber;

    //画像を切り替える
    public void ChangeImage()
    {
        //次の画像の番号を計算する
        currentImageNumber = (currentImageNumber + 1) % imageList.Count;

        //画像を切り替える
        image.sprite = imageList[currentImageNumber];
    }
}
これらのコードを使用することで、Unityを使用してより複雑でリアルなインベ

何度か続きを書かせたら

  • 敵キャラの挙動
  • UIの操作
  • ゲームの進行
  • シーン遷移
  • BGM・SE
  • 2D画像の切り替え

この辺まで出てきた。
冒頭の作業指示にはない範囲までコードを吐き出してくれている。
なかなかにサポートが厚い。

しかし、ここで問題が出てきた。

  • GameController.cs
  • SceneController.cs
  • AudioController.cs
  • ImageController.cs

これらはメソッドを定義するところまでは行けたようだが、
その呼び出しまでは処理を書かれていないので、少しコードをいじる必要が出てきた。

いや、それくらい自分でやれよって話かもしれないが、
プログラミング未経験の人がお気軽にやれる内容とは言い難いので、
AIに全部お任せ♪って言えるような範囲は逸脱してしまったという結果になった。
(また、AudioSourceはデフォルトでPlayOnAwakeがOnになっているので、勝手に音がなってしまう。
そこに気づく必要もあったりするので、まだまだ問題は出てきそうだ)

とはいえ、一歩人間側が歩み寄って、
「他クラスのメソッドを任意のタイミングで呼び出す」というところは
やってあげれば動きそうな範囲をカバーしているのはすごい。
AIに修正依頼出してみようかと思ったけど、しゃあない。
少しだけいじってみるか。

人間の作業

さっきみたいにスクリプトコピペしてオブジェクト作って〜みたいなことをした。
サウンド周りは割愛。

あと、インベーダーの降りてくるスピードがやたらめったら早かったので、
EnemyController.csのspeedのパラメータだけはインスペクタからいじった(5.0f -> 0.1f)

ちなみに、今回は適当な3DオブジェクトでやっているのでImageControllerは使わない。
せっかく作ってもらったのに申し訳ない。

ただ、一個勉強になったことがあって、

//次の画像の番号を計算する
currentImageNumber = (currentImageNumber + 1) % imageList.Count;

処理を走らせるたびにカウントアップ、上限まで来たら0に戻る挙動

は「対象の数字に+1して全体数で割った余り」で作れるんだなぁ...
と、「かなりなるほどね...」と唸ってしまった(さんすう苦手、ゆるして...)
実際に検証してみたのでちゃんと動作する


(最初だけStartイベントで明示的に0で初期化した)

ちょっと脱線してしまったが、AIから提示されたコードが普通にお勉強になった、
と言う体験が結構強烈だったのでどうしても書きたかったので、やむなし。

ここで致命的な事に気がついた。
これ、攻撃できないじゃん。
AIでもこういう漏れはありうるらしい。
修正依頼を出してみる事にしよう。

井上

PlayerController.csに「スペースボタンを押したら攻撃をする」処理を追加してください

ChatGPT

できます。

次のようなコードを追加することで、スペースキーを押すことで攻撃をすることができるようになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    //プレイヤーの移動スピード
    public float speed = 10.0f;

    //攻撃をするためのスクリプト
    public PlayerShooter playerShooter;

    // Update is called once per frame
    void Update()
    {
        //左右の移動
        float x = Input.GetAxis("Horizontal");

        //プレイヤーを移動させる
        transform.position += new Vector3(x, 0, 0) * Time.deltaTime * speed;

        //スペースキーが押されたかどうかを判定する
        if (Input.GetKeyDown(KeyCode.Space))
        {
            //攻撃をする
            playerShooter.Shoot();
        }
    }
}

井上

PlayerShooter.csを定義してください

ChatGPT

PlayerShooter.csは、プレイヤーが弾を発射できるようにするためのスクリプトです。

以下がPlayerShooter.csのコードの例です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    //弾を生成するプレハブ
    public GameObject bulletPrefab;

    //弾の発射間隔
    public float interval = 0.5f;

    //経過時間
    private float elapsedTime;

    // Update is called once per frame
    void Update()
    {
        //経過時間を更新する
        elapsedTime += Time.deltaTime;
    }

    //攻撃をする
    public void Shoot()
    {
        //弾を生成する
        GameObject bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);

        //弾をプレイヤーの真正面に向ける
        bullet.transform.LookAt(transform.position + transform.forward);
    }
}

要らないメンバ変数が入っていて、若干文脈がわかんなくなってそうな予感がする。
あとこれ弾飛ばなくね??
思うにelapsedTimeは弾のY軸方向への射出に使いたかったのかもしれない。

雲行きが怪しくなってきたな。
ちょっと詰めてみることにした。

井上

現状のPlayerShooter.csは玉が飛ばないバグがあるように見えます。修正してください

ChatGPT

そのようなバグがある場合、以下のように修正することで弾を発射できるようになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    //弾を生成するプレハブ
    public GameObject bulletPrefab;

    //弾の発射間隔
    public float interval = 0.5f;

    //経過時間
    private float elapsedTime;

    // Update is called once per frame
    void Update()
    {
        //経過時間を更新する
        elapsedTime += Time.deltaTime;

        //スペースキーが押されたかどうかを判定する
        if (Input.GetKeyDown(KeyCode.Space) && elapsedTime > interval)
        {
            //攻撃をする
            Shoot();

            //経過時間をリセットす

井上

まじめにやってください

ChatGPT

ご迷惑をおかけして申し訳ありません。本当にご質問の解決に心がけて回答させていただきます。

PlayerShooter.csを修正するとして、以下のようなコードになるでしょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerShooter : MonoBehaviour
{
    //弾を生成するプレハブ
    public GameObject bulletPrefab;

    //弾の発射間隔
    public float interval = 0.5f;

    //経過時間
    private float elapsedTime;

    // Update is called once per frame
    void Update()
    {
        //経過時間を更新する
        elapsedTime += Time.deltaTime;

        //スペースキーが押されたかどうかを判定する
        if (Input.GetKeyDown(KeyCode.Space) && elapsedTime > interval)
        {
            //攻撃をする
            Shoot();

            //経過時間をリセットする
            elapsedTime = 0;
        }
    }

    //攻撃をする
    public void Shoot()
    {
        //弾を生成する
        GameObject bullet = Instantiate(bulletPrefab, transform.position, Quaternion.identity);

        //弾をプレイヤーの真正面に向ける

「違う、そうじゃない」って感じの返事を涙目でしてくるようになった。
頑張ってくれたけど、まぁ、しゃあないね。

できあがったのはこんな感じ。

もっと丁寧に「生成した弾をY軸方向に飛ばす実装」を要求すれば、ちゃんとそれっぽいコードを出してくれるのかもしれないが、こういう齟齬は恐らく頻出する予感があり、そういうのに突っ込んだことしてもイタチごっこ感がある。ここで井上の時間切れとなり、検証は終了とさせてもらう。

最低限修正しなければならない問題を挙げると

  • プレイヤーの玉が飛んでいかない
  • ライフの概念があるが、攻撃を受ける実装が行われていない
  • インベーダーを破壊、ポイント加算する処理がない
  • Playerが無限に左右動けるので行方不明になりかねない
  • クリア・ゲームオーバー後にゲーム画面に戻る実装がない

とかでしょうか、ぱっと思いつく限り。

命名がクソ、要らない変数がある、設計されてなさそうで行き当たりばったり、なので将来クソコードを生み出す肥沃な土壌になっている、とかは、そもそもAIへのオーダーがクソなので、そこは仕方がないものとする。

まとめ

『ChatGPT』はホワイトカラー共を鮮血に染める革命のギロチンなのか?!

NOだと感じました。(少なくともUnityエンジニアの場合)

現状の完成度だと、”適当なオーダー”で
「よしなにいい感じの完成品」が出てくることはないからですね。

それに、それが正しく仕様を満たしたものなのか、
検証したり組み込んだりする人間が必要です。
だから、現時点ではすぐにエンジニアにとって変わるものでもない。
ただし、これがもうちょっと「細かい粒度」でかつ「目的がはっきりした」質問になれば、
よりAIはこっちの要望に答えた質の高い回答をしてくれるはずです。

質の高い質問をするにはそれなりの知識や経験が必要です。
つまり、それが我々の職を奪う事につながる事はなく、
むしろ、生産性を上げる素晴らしいツールになっていると思います。

なんせ、あんな適当なオーダーでも要望の概略はなぞることはできていたので。
とてもかなりすごく非常にレベルが高いなぁと思いました。
(しかもまだまだ発展途上なんだから末恐ろしい)

中間生成物レベルの成果物が出てきやすいので、それをうまく使っていく意識が大事かも。

起きるポジティブな変化

ちょろっと使った所感

  • 使いこなす人間とそうでない人間、両者のアウトプットの質と量は大きく差が出る。
  • 雑なオーダーでも最初にある程度の概略は示してくれるので「何が分からないのかが分からない」というシチュエーションがだいぶ減る。
  • 上記踏まえると学習効率が上がると思うし、思いがけず知識の幅も広がる。

初・中級者にとっては重い腰を上げる為のブースト剤、
上級者にとっては効率化を図る知恵の電卓になるって感じするな。
他の分野ではどんな感じなんだろ、気になる。
気が向いたら使い方をもうちょっと研究してみます。
読んでくれてありがとうございました。

Discussion