クリスマスにちなんだブラウザゲームを作ってみた(その3)

# はじめに
[前回](https://qiita.com/noji505/items/ee1aa080cb2cebace3de)と同じくクリスマスにちなんだゲームを作ってみました
今回は、今までと違い生成AI(Copilot)を利用してゲームを作成してみるということにチャレンジしてみます

# ゲームイメージ
ゲームイメージとしては以下のようなものとします
* 登場キャラクタはサンタと子供
* サンタが画面上からランダムにプレゼントを落としてくる
* 子供を操作して落ちてくるプレゼントをキャッチする
* 一定時間のキャッチした数をスコアとする

# さっそくやってみる
上記のゲームイメージをCopilotに伝えてみます

<img width="500" alt="01_copilot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/740996/036cf776-b924-1644-555a-83b63460528a.png">

以下のソースコードが提示されました

```html
<!DOCTYPE html>
<html>
<head>
    <title>Santa's Gift Drop Game</title>
    <style>
        body { margin: 0; overflow: hidden; background: lightblue; }
        canvas { display: block; }
        .rect { position: absolute; }
        .santa { width: 50px; height: 50px; background: red; top: 20px; left: 50%; transform: translateX(-50%); }
        .child { width: 50px; height: 50px; background: green; bottom: 20px; left: 50%; transform: translateX(-50%); }
        .gift { width: 20px; height: 20px; background: gold; position: absolute; }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <div class="rect santa" id="santa"></div>
    <div class="rect child" id="child"></div>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const gifts = [];
        let score = 0;
        const child = document.getElementById('child');
        const santa = document.getElementById('santa');

        function random(min, max) {
            return Math.floor(Math.random() * (max - min)) + min;
        }

        function dropGift() {
            const gift = document.createElement('div');
            gift.className = 'gift';
            gift.style.left = random(0, canvas.width - 20) + 'px';
            gift.style.top = '0px';
            document.body.appendChild(gift);
            gifts.push(gift);
        }

        function updateGifts() {
            for (let i = 0; i < gifts.length; i++) {
                const gift = gifts[i];
                gift.style.top = (parseInt(gift.style.top) + 5) + 'px';

                if (parseInt(gift.style.top) > canvas.height - 70 &&
                    Math.abs(parseInt(gift.style.left) - parseInt(child.style.left)) < 50) {
                    document.body.removeChild(gift);
                    gifts.splice(i, 1);
                    score++;
                    console.log('Score:', score);
                }
            }
        }

        function moveChild(event) {
            const step = 10;
            if (event.key === 'ArrowLeft') {
                child.style.left = (parseInt(child.style.left) - step) + 'px';
            } else if (event.key === 'ArrowRight') {
                child.style.left = (parseInt(child.style.left) + step) + 'px';
            }
        }

        document.addEventListener('keydown', moveChild);

        setInterval(dropGift, 2000);
        setInterval(updateGifts, 50);
    </script>
</body>
</html>
```

ブラウザで表示すると以下のように表示されました
<img width="500" alt="02_game_img.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/740996/bb30846c-2d12-4498-325a-6842ad88c8c4.png">

画面の上下にサンタと子供(上にサンタ、下に子供)が表示され、プレゼントが画面上から下に向かってランダムに落ちてきています
この時点で概ね自分のイメージしたアプリが作られています

# 機能追加
以下の部分が実現出来ていないため、追加してみます

* カーソルキーで子供を移動させる(コード上には矢印キーで移動する処理があるが動いていない)
* 子供がプレゼントを取るとスコアが加算される

以下のように質問してみました
<img width="500" alt="03_copilot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/740996/f64bed2a-3708-1678-8caa-8c787d73846a.png">

出力されたコード

```html
<!DOCTYPE html>
<html>
<head>
    <title>Santa's Gift Drop Game</title>
    <style>
        body { margin: 0; overflow: hidden; background: lightblue; }
        canvas { display: block; }
        .rect { position: absolute; }
        .santa { width: 50px; height: 50px; background: red; top: 20px; left: 50%; transform: translateX(-50%); }
        .child { width: 50px; height: 50px; background: green; bottom: 20px; left: 50%; transform: translateX(-50%); }
        .gift { width: 20px; height: 20px; background: gold; position: absolute; }
        #scoreBoard { position: absolute; top: 10px; left: 10px; font-size: 20px; font-family: Arial, sans-serif; }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <div class="rect santa" id="santa"></div>
    <div class="rect child" id="child"></div>
    <div id="scoreBoard">Score: 0</div>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const gifts = [];
        let score = 0;
        const child = document.getElementById('child');
        const santa = document.getElementById('santa');
        const scoreBoard = document.getElementById('scoreBoard');

        function random(min, max) {
            return Math.floor(Math.random() * (max - min)) + min;
        }

        function dropGift() {
            const gift = document.createElement('div');
            gift.className = 'gift';
            gift.style.left = random(0, canvas.width - 20) + 'px';
            gift.style.top = '0px';
            document.body.appendChild(gift);
            gifts.push(gift);
        }

        function updateGifts() {
            for (let i = 0; i < gifts.length; i++) {
                const gift = gifts[i];
                gift.style.top = (parseInt(gift.style.top) + 5) + 'px';

                if (parseInt(gift.style.top) > canvas.height - 70 &&
                    Math.abs(parseInt(gift.style.left) - parseInt(child.style.left)) < 50) {
                    document.body.removeChild(gift);
                    gifts.splice(i, 1);
                    score++;
                    scoreBoard.textContent = 'Score: ' + score;
                    console.log('Score:', score);
                }
            }
        }

        function moveChild(event) {
            const step = 10;
            const currentPosition = parseInt(child.style.left) || (canvas.width / 2 - 25); // 初期位置設定
            if (event.key === 'ArrowLeft') {
                child.style.left = Math.max(0, currentPosition - step) + 'px';
            } else if (event.key === 'ArrowRight') {
                child.style.left = Math.min(canvas.width - 50, currentPosition + step) + 'px';
            }
        }

        document.addEventListener('keydown', moveChild);

        setInterval(dropGift, 2000);
        setInterval(updateGifts, 50);
    </script>
</body>
</html>
```

ブラウザでの表示はこのようになりました

<img width="500" alt="04_game_img2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/740996/4c223478-9b72-7d6e-e274-7a141ac0da0c.png">

スコアの表示が追加されたのと、カーソルキーの左右で移動出来るようになりました
またプレゼントを取るとスコアが加算される部分も実現出来ています


# ゲームとしての体裁を整える
現時点で大まかな部分は出来たので、もう少しだけゲームの形になるように要素を追加してみます

具体的には、
* タイトル画面→ゲーム画面(先ほどのプレゼントが落ちてくる画面)→結果画面の3画面構成とする
* ゲーム画面は30秒経過すると自動で結果画面へ移動するようにする

というわけで以下のように質問します

<img width="500" alt="05_copilot.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/740996/26611055-1c72-bc95-396d-992f84568031.png">

↓以下のものが作成されました
※実際に遊べます

<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="wBwGbQX" data-pen-title="Qiita30_santagame03" data-user="noji505" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/noji505/pen/wBwGbQX">
  Qiita30_santagame03</a> by nojima (<a href="https://codepen.io/noji505">@noji505</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>


# 最後に
今回は自身初の試みとして生成AIを使用してゲームアプリを作成してみました
本記事では質問1→質問2と順当に機能をブラッシュアップさせていってますが、実際はその前に動いていた機能が動かなくなる(プレゼントが降ってこなくなる、キャラが操作出来なくなる等)ことがあり、何度か質問を繰り返してコードを生成しました

それでも作りたいアプリを日本語で指示するだけで、イメージ通りのものが出来上がってくるのはとても楽しかったし可能性を感じました
これからも生成AIの分野は進化していくと思うので、使う側も日々進化していきたいと思います