見出し画像

[Unity]2日間ゲームジャムにて、chatgpt君にVampireSurviversっぽいゲームを吐いてもらおうとした

ので、備忘録つくります。
メンバ構成は
・プランナーさん x1
・AI製Sprite出力マンさん x1
・unity実装 x1 (私)
でした
https://www.e-topia-kagawa.jp/lecture/saikyo_game_jam_2023/

結局AIどうだった?

・ChatGPT(GPT-4)君に任せきりにすることを途中で頭から抜けちゃったので、この記事あんまし参考になんないかもです。
実装の補佐だったりひとまず土台組んでみて―っていうのは現状でもできそう。
プログラム部分を頼り切りにするのは、入力側にも技量要りそうだなって思いました。
 英語で聞いたり、「優秀なエンジニア」をロールとして与えればもっと優秀になるのかな? 暇あったらやってみます…

・Spriteとかはパッと揃えられるのはよさそうだけど、ライセンス回り不安しかないのよね…
あと単語文字列の出力が苦手っぽい

・アイデア出しはまあ一定やってくれそう

実装者向けメモ

・UIはUniRxのSubscribeの機能とDoTween覚えとくと結構楽になります。
HPをIntReactivePropertyとかにして、変更掛かったタイミングでUIに反映されるようSubscribeで仕込んどけばOK

・Singletonパターンでじゃんじゃかオブジェクトプール管理クラスとかUI管理クラス組んだほうが実装早くね? 依存関係酷いことになるけど…

・想定プレイ時間5分は長い 1~3分ぐらいがいいね… 風呂敷広げすぎはやっぱダメっす

・ゲージャム中に関してはSE・BGM再生周りをもう下のやつに頼り切りでいいんじゃねえかな。


成果物

期日タイミングだとゲーム開始から最初のボス撃破まで....ってとこで止まってました。仕様書上の2~3割ぐらいしか入ってない感じです。
ジャム終わったあとの調整でゲームっぽくしました。

1. お題発表「ひろがる」~仕様設定

今回はプランナー陣がお題をChatGptに食わせてゲーム内容を決めさせました。

<入力>
小学生が参加しているゲームジャムに参加中です。そこで制作ゲームの企画をする。
・開発期間は2日間
・Unityを使う。
・遊んでもらって評価をもらいたい対象は”参加している小学生”
・2Dのゲーム
・作業者は2名
・テーマは”ひろがる”
企画案を10案ください。

<出力>
以下は、上記の企画案から、ゲームリテラシーが高く、
小学生高学年に好まれそうな5つの企画案の概要です。
「花畑の旅」
プレイヤーは、花畑の中を旅しながら、新しい花を集め、自分の庭を広げていく。
広がっていく庭は、プレイヤーのセンスで作り込むことができ、美しい庭を作り上げることが目的。
ゲーム内での花の育成や庭づくりに必要なアイテムの収集、自由度の高い庭づくりなどが楽しめる。
「(以下略)

で、結果的に以下がチョイスされることになりました。

<出力>
「海賊船の冒険」は、プレイヤーが海賊船の船長となり、敵船とのバトルや宝物探しに挑戦しながら、
自分だけの海賊船を作り上げていくアクションゲームです。
プレイヤーは、海賊船を進めながら、敵船とのバトルや宝物探しに挑戦します。
また、海賊仲間を集めたり、船の改造なども可能であり、
自分だけの海賊船を作り上げる楽しみがあります。
ゲーム内での海賊仲間の募集や船の改造、敵船とのバトル、宝物の探索などが楽しめます。
また、プレイヤーが冒険を進めることで、新しい船や武器、
アイテムなどが手に入り、自分だけの海賊船を作り上げることができます。
~中略~
「海賊船の冒険」は、トップビューの視点で開発することが適切であると考えられます。
トップビューは、上から見下ろす視点で、海域や敵船などを広く見渡すことができます。

<入力>
テーマの回収どうすんの?

<出力>
ゲームの目的を「新しい海域を発見し、冒険の世界を広げること」として中心に据えます。
~以下略~

おいおいおい、機能もりもりやん、2日でできんのかこれ…(※できなかった)

2. (AI)実装開始のための設計

ひとまずトップビューシューターの原型を作るためChatgptくんにクラス図書かせてみました。

plantUML形式で吐かせて―
こんな感じ

ゲームマネージャー、プレイヤー、敵、玉と欲しいところは抑えていそう

3. (AI)プレイヤー実装させてみる

設計大体想像ついたんでコード書かせてみます

プログラム部分は後述
実装され...で止まるのはご愛敬。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Player : MonoBehaviour
{
    // プレイヤーの移動速度
    public float moveSpeed = 5.0f;

    // 弾丸プレファブ
    public GameObject bulletPrefab;

    // 弾丸発射速度
    public float fireRate = 0.5f;
    private float nextFire;

    // Update is called once per frame
    void Update()
    {
        Move();
        Shoot();
    }

    private void Move()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");

        Vector3 moveDirection = new Vector3(horizontal, vertical, 0).normalized;
        transform.position += moveDirection * moveSpeed * Time.deltaTime;
    }

    private void Shoot()
    {
        if (Input.GetButton("Fire1") && Time.time > nextFire)
        {
            nextFire = Time.time + fireRate;
            Instantiate(bulletPrefab, transform.position, Quaternion.identity);
        }
    }

    public void TakeDamage(int damage)
    {
        // プレイヤーのHPを減らす処理
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        // 敵や敵の弾丸と衝突したときの処理
    }
}

<気づいた点>
・コメント付き偉いね
・ちゃんと事前のクラス図出力に沿ってメソッド吐いてるね
・移動処理に関しては問題なさそう
・弾についてもおおむね問題なさそうだけど、Time.time使うのちょっと気になった。 deltaTime使っていいんじゃねえかな
・入力受け取り部分についてもInput.Get系使ってるので偉い
・private、public変数ともにロワーキャメルなのはちょっと気になりますが、まあコーディングルール指定すればいいのかな?
・コンポーネントアタッチ部分まで説明してくれてるので、初心者にはうれしそう

で、言われたとおりにアタッチしたところ、プレイヤーオブジェはいい感じに動いてくれました。
カメラ追従させたくなったので、その要望伝えたところ

cinemachineって事前に伝えちゃったのは、コンセプト的には悪手だったかも

まあいい感じに教えてくれました。Packageのインスコ方法まで教えてくれるなんて優しいですね。従って設定したところいい感じに追従してくれました。

…..

他にもコード書く必要あったんだけど、ChatGPT君にお任せするってコンセプト忘れて一定自分でコーディングしちゃってました

詳細な要件来たタイミングが結構深夜になっちゃったのと、
結局実装中に必要な機能(敵とか弾のオブジェクトプールとか)思いついたりしてシームレスに追加実装とかしちゃうので。。。
ちゃんと余裕あるスケジュで実装挑んで再挑戦したいですー


補佐として使ったケースは何件かあるので記しておきます。

4. (AI/失敗)逆マスク作らせたかった

要件として、
・未開放海域の雲の中にいる間、自分の周り以外を真っ暗にしてくれ
というのが来ました。

雲エリアに入ると…
こんな感じ

Shader使ったら楽そうだけど、この辺りパッと書ける自信なかったので、ChatGPT君に書かせてみることにしました。

コードまで吐いてくれたね

なんかUpdateメソッド部分で謎のposition移動やってんのは気になる。そもそもコード途中で切れてるし.…
で、ひとまず5あたりまで進めたんですが、普通にマスクしてくれないんですよね…
相談してみました。

なんだこのshaderは…

うーん? Shaderあんまわからない私でも、

o.Albedo = 1 - c.rgb;
o.Alpha = c.a;

あたり、なんか的外れなことしてるのが感じられました。変えるならo.Alphaあたりっすよね...?

まあ普通に従っても意図した表示になりませんでした。

この作業やってるのが深夜4時ぐらいだったというのもあり、コードでクールに解決するのめんどくさくなりました。
顔ハメ看板よろしく適当に真ん中くりぬいた1280x720の画像用意して、それを表示/非表示切り替えるようにして代用しました。

5. (AI/失敗)矩形の判定に、プレイヤーが乗っかってる状態を取得したかった

前の項目でやってた、
・未開放海域の雲の中にいる間、自分の周り以外を真っ暗にしてくれ

の機能で、雲の中にいるかどうかって判定をChatgptにやらせてみました。

コード後述


うーん
using UnityEngine;

public class BoxCollidersController : MonoBehaviour
{
    public BoxCollider2D[] boxColliders;
    private int playerOnCollidersCount = 0;
    public bool allCollidersActivated = false;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            playerOnCollidersCount++;

            if (playerOnCollidersCount == boxColliders.Length)
            {
                allCollidersActivated = true;
            }
        }
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            playerOnCollidersCount--;

            if (allCollidersActivated)
            {
                allCollidersActivated = false;
            }
        }
    }
}

プレイヤーが3つのBoxCollider2Dのすべてに乗っている場合にのみ、

辺りで解釈間違ってるっぽいです。
ここ実装してるのが徹夜明け朝8時、期限まで数時間だったというのもあり、もうめんどくさくなって自分で実装しました。

6. (AI) プレイヤーと敵の位置関係をもとに角度取得する処理を書かせた

要件として、
・ボスの方向にロケーター出してほしい
ってのがあったので、これについて処理書かせました。

左にボスいるので、ロケーターが左に向いている

画面中央にロケーター表示して、プレイヤーとターゲットの位置関係をもとに0~360度回転させることによりコンパスっぽくします。
ターゲット.position - プレイヤー.positionで方向ベクトル取って、ここから角度取る方法を聞いてみました。

三角関数苦手マンの救世主?

そのまま使ってもいい感じに動いてくれました。
(まあ毎フレこの計算するのちょっと負荷が怖いけどね)

7. (AI) プレイヤーレベルに応じて、弾発射数を増やさせてみた

要件として、
・プレイヤーのレベルアップに伴って出す弾増やせ
ってのがあったので、こちらもAIにやらさせてみました。

Lv2の時は5way
いい感じ

まあそのまま使えました。
前提条件として使うメソッド渡してみたのですが、それもいい感じに引数指定して使えています。

8. (AI) DoTween使ってオブジェ動かしてみた

経験値アイテムである金貨を拾うとき、一定近づいたタイミングでプレイヤーに移動させたいので、それを書かせてみました。

金貨をプレイヤーに移動させたい
いい感じ
using UnityEngine;
using DG.Tweening;

public class MoveToObject : MonoBehaviour
{
    [SerializeField] private GameObject objectToMove;
    [SerializeField] private GameObject targetObject;
    [SerializeField] private float duration = 1f;

    private void Start()
    {
        MoveObjectToTarget();
    }

    private void MoveObjectToTarget()
    {
        Vector3 targetPosition = targetObject.transform.position;
        objectToMove.transform.DOMove(targetPosition, duration).SetEase(Ease.Linear);
    }
}

Dotweenってサードパーティのライブラリなんだけど、いい感じに使えてて偉い。
まあ結局終着点更新のため書き方変えたけど、このままでも十分使えます。

9. (AI) スマホ対応

スマホからでも遊べるようできないかという話になったので、雑に相談してみました。

ですけどぉ

なんかいろいろ教えてくれましたが、バーチャルパッドだけ追加することにしました。

驚くべきことに、「Joystick Pack」ってAssetStore上にあるんですよね。今回それ入れていい感じに動きました。


以上です。
次やるならちゃんと余裕持ったスケジュール + 仕様ミニマムにして、AI頼り切りで作れないか検証したいですねー



この記事が参加している募集

AIとやってみた

この記事が気に入ったらサポートをしてみませんか?