見出し画像

AIにnoteのネタを相談したら、なんやかんやで卓球をプログラムしてくれた件

前回は「卓球」を作ってみた。

卓球

今回は、noteのネタをAIに相談してみたら、いつの間にかAIが「卓球」のプログラムを書いてくれた。


Copilotに「noteの記事のネタ」を聞いてみた

今回お願いしたのは、Windowsに標準装備されたCopilotさん。
それではnoteの記事のネタを相談してみよう。

ゲーム作りについて、どんな記事が読まれやすいか教えて

1. ゲーム開発の基礎
2. 成功したゲームの事例
3. 最新の技術トレンド
4. チュートリアルやガイド

Copilot

ゲーム開発の基礎について記事にするなら、どんなものがおすすめ?

1. ゲーム開発の流れ
2. 基本的なツールとソフトウェア
3. プログラミングの基礎
4. アートとデザイン
5. サウンドデザイン
6. プロトタイピングとテスト

Copilot

ゲームのプロトタイプのコードを書いて欲しい

OK, let's tackle this together! To get started, can you tell me a bit more about the game you want to create? For instance, what's the basic concept, and which features or mechanics are you envisioning? This'll help me tailor the code to fit your vision better.

なぜか英語で答えるCopilot

卓球ゲームのコードを書いて欲しい

<!DOCTYPE html>
<html>
<head>
    <title>卓球ゲーム</title>
    <style>
        canvas {
            background: #000;
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    <canvas id="pong" width="800" height="400"></canvas>
    <script>
        const canvas = document.getElementById('pong');
        const context = canvas.getContext('2d');

        const player = {
            x: 0,
            y: (canvas.height - 100) / 2,
            width: 10,
            height: 100,
            color: 'WHITE',
            score: 0
        };

        const computer = {
            x: canvas.width - 10,
            y: (canvas.height - 100) / 2,
            width: 10,
            height: 100,
            color: 'WHITE',
            score: 0
        };

        const ball = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            radius: 10,
            speed: 5,
            velocityX: 5,
            velocityY: 5,
            color: 'WHITE'
        };

        function drawRect(x, y, w, h, color) {
            context.fillStyle = color;
            context.fillRect(x, y, w, h);
        }

        function drawCircle(x, y, r, color) {
            context.fillStyle = color;
            context.beginPath();
            context.arc(x, y, r, 0, Math.PI * 2, false);
            context.closePath();
            context.fill();
        }

        function drawText(text, x, y, color) {
            context.fillStyle = color;
            context.font = "45px Arial";
            context.fillText(text, x, y);
        }

        function render() {
            drawRect(0, 0, canvas.width, canvas.height, 'BLACK');
            drawRect(player.x, player.y, player.width, player.height, player.color);
            drawRect(computer.x, computer.y, computer.width, computer.height, computer.color);
            drawCircle(ball.x, ball.y, ball.radius, ball.color);
            drawText(player.score, canvas.width / 4, canvas.height / 5, 'WHITE');
            drawText(computer.score, 3 * canvas.width / 4, canvas.height / 5, 'WHITE');
        }

        function movePaddle(event) {
            let rect = canvas.getBoundingClientRect();
            player.y = event.clientY - rect.top - player.height / 2;
        }

        function update() {
            ball.x += ball.velocityX;
            ball.y += ball.velocityY;

            if (ball.y + ball.radius > canvas.height || ball.y - ball.radius < 0) {
                ball.velocityY = -ball.velocityY;
            }

            let playerOrComputer = (ball.x < canvas.width / 2) ? player : computer;

            if (collision(ball, playerOrComputer)) {
                ball.velocityX = -ball.velocityX;
            }

            if (ball.x - ball.radius < 0) {
                computer.score++;
                resetBall();
            } else if (ball.x + ball.radius > canvas.width) {
                player.score++;
                resetBall();
            }
        }

        function collision(b, p) {
            p.top = p.y;
            p.bottom = p.y + p.height;
            p.left = p.x;
            p.right = p.x + p.width;

            b.top = b.y - b.radius;
            b.bottom = b.y + b.radius;
            b.left = b.x - b.radius;
            b.right = b.x + b.radius;

            return p.left < b.right && p.top < b.bottom && p.right > b.left && p.bottom > b.top;
        }

        function resetBall() {
            ball.x = canvas.width / 2;
            ball.y = canvas.height / 2;
            ball.velocityX = -ball.velocityX;
            ball.speed = 5;
        }

        canvas.addEventListener('mousemove', movePaddle);
        function gameLoop() {
            update();
            render();
        }

        const framePerSecond = 50;
        setInterval(gameLoop, 1000 / framePerSecond);
    </script>
</body>
</html>

これで、基本的な卓球ゲームが動くはずです。HTMLファイルとして保存してブラウザで開くと遊べますよ。もっと機能を追加したりデザインを変えたりしてカスタマイズしてみて。これで十分かな?他にも何か足したい機能があるなら教えて。

Copilot

Copilotのプログラムをテキストエディタにコピーしてhtml形式で保存してブラウザで開いてみたら動いた。
ただ、敵が動かないなど色々直して欲しいことがあったのでお願いしてみた。

Copilotが作った卓球をブラウザで動かして見た

卓球をカスタマイズしてもらう

右側のプレイヤーを自動で動くようにして

了解!右側のプレイヤー、つまりコンピュータプレイヤーを自動で動かすコードを追加します。
このコードでは、コンピュータプレイヤーがボールのY座標に追従するように動きます。これでゲームの難易度が少し上がったかな?もっと追加したい要素があれば教えてね。

Copilot

これで、敵が動くようになった。

敵を動かす

いくつかまとめてお願いしてみる

画面サイズを640x360にして
画面サイズを変更するためには、<canvas>の幅と高さを640x360に設定します。コードの一部を変更してみるね

パドルを画面端から20ドット離して
もちろんです!パドルを画面の端から20ドット離すように設定するためには、playerとcomputerのx座標を調整します。

パドルの長さを50%にして、跳ね返る度にスピードが10%上がるようにして
パドルの長さを50%にし、ボールが跳ね返るたびにスピードが10%上がるように変更しましょう。

5点取った方が勝利にして、開始時やボールロスト時は左クリックでスタートするようにして
この新たなルールを追加して、ゲームが5点マッチでプレイできるようにしましょう。また、左クリックで開始する機能も加えました

Copilot

いくつかまとめてお願いすることもできた。凄いね。
一応、一つづつバグチェックした方が良いかもしれない。
というのも次のお願いで動かなくなってしまった。

複数の修正もやってくれる

お願いしたらバグったので自分で直す

ボールをロストした側がボールを発射できるようにして
OK, let's modify the game so that the player who loses the ball gets to launch it again. Here's the updated code to add that functionality

ボールを失った側がボールを発射するまで、パドルが動いたらボールも一緒に動いて
調整完了。ボールを失った側がボールを発射するまで、パドルと一緒にボールが動くようにしましょう。

英語で答えたらヤバい前兆なのかCopilotよ!

このプログラムを実行したら、黒い画面になったので、直すようにお願いした。

ゲームが立ち上がらなくなりました
Oops, that's a bummer. Let's double-check everything to get it back on track.
Here's the complete code with a few fixes to ensure the ball moves along with the paddle correctly

パニクって英語で答えるCopilotさん

この後、動くようにはなったが、何度お願いしても、ボールを失った方ではなく、得点した方に次のボールの発射権が移ってしまった。

ボールを失った側ではない方がボールを発射します。ボールを失った側がボールを発射するようにしてください
わかりました。ボールを失った側がボールを発射するようにコードを修正しますね

Copilotさん直ってないんやけど。。。

指定の仕方が間違っているようで治らん。
時間かかりそうなので、自分でなおすために、以下の質問をした。

ボールを発射する側を設定している箇所を教えてください。
ボールを発射する側を設定している箇所は以下の部分です:

丁寧に説明してくれるCopilotさん
// 1. resetBall関数内でボールを発射するプレイヤーを決定しています。

function resetBall(lastLoss) {
    ball.speed = 5; // ボールの速度をリセット
    ball.velocityX = 0;
    ball.velocityY = 0;

    if (lastLoss === 'player') {
        ball.x = player.x + player.width + ball.radius;
        ball.y = player.y + player.height / 2;
    } else {
        ball.x = computer.x - ball.radius;
        ball.y = computer.y + computer.height / 2;
    }
    gameStarted = false;
    launchingPlayer = lastLoss; // ボールを発射するプレイヤーを設定
}

// 2. 左クリック時のイベントリスナー内で実際にボールを発射するプレイヤーの処理を行っています。

canvas.addEventListener('click', () => {
    if (!gameStarted) {
        gameStarted = true;
        if (launchingPlayer === 'player') {
            ball.velocityX = ball.speed;
        } else {
            ball.velocityX = -ball.speed;
        }
        ball.velocityY = (Math.random() * 2 - 1) * ball.speed; // ランダムなY方向の速度
        launchingPlayer = null;
    }
});

AIの作ってくれたプログラムを改造

・負けた方がサーブ権を得るように修正
・プレイヤーを青、敵を赤、ボールを黄色に修正

AIと作った卓球
<!DOCTYPE html>
<html>
<head>
    <title>卓球ゲーム</title>
    <style>
        canvas {
            background: #000;
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    <canvas id="pong" width="640" height="360"></canvas>
    <script>
        const canvas = document.getElementById('pong');
        const context = canvas.getContext('2d');

        let gameStarted = false;
        let launchingPlayer = null; // ボールを発射するプレイヤー

        const player = {
            x: 20,
            y: (canvas.height - 50) / 2,
            width: 10,
            height: 50,
            color: 'AQUA',
            score: 0
        };

        const computer = {
            x: canvas.width - 30,
            y: (canvas.height - 50) / 2,
            width: 10,
            height: 50,
            color: 'RED',
            score: 0,
            dy: 5
        };

        const ball = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            radius: 10,
            speed: 5,
            velocityX: 0,
            velocityY: 0,
            color: 'YELLOW'
        };

        function drawRect(x, y, w, h, color) {
            context.fillStyle = color;
            context.fillRect(x, y, w, h);
        }

        function drawCircle(x, y, r, color) {
            context.fillStyle = color;
            context.beginPath();
            context.arc(x, y, r, 0, Math.PI * 2, false);
            context.closePath();
            context.fill();
        }

        function drawText(text, x, y, color) {
            context.fillStyle = color;
            context.font = "45px Arial";
            context.fillText(text, x, y);
        }

        function render() {
            drawRect(0, 0, canvas.width, canvas.height, 'BLACK');
            drawRect(player.x, player.y, player.width, player.height, player.color);
            drawRect(computer.x, computer.y, computer.width, computer.height, computer.color);
            drawCircle(ball.x, ball.y, ball.radius, ball.color);
            drawText(player.score, canvas.width / 4, canvas.height / 5, 'WHITE');
            drawText(computer.score, 3 * canvas.width / 4, canvas.height / 5, 'WHITE');

            if (!gameStarted) {
                drawText("Click to Start", canvas.width / 2 - 100, canvas.height / 2, 'WHITE');
            }
        }

        function movePaddle(event) {
            let rect = canvas.getBoundingClientRect();
            player.y = event.clientY - rect.top - player.height / 2;
            if (!gameStarted && launchingPlayer === 'player') {
                ball.y = player.y + player.height / 2;
            }
        }

        function moveComputerPaddle() {
            if (ball.y < computer.y + computer.height / 2) {
                computer.y -= computer.dy;
            } else if (ball.y > computer.y + computer.height / 2) {
                computer.y += computer.dy;
            }
            computer.y = Math.max(Math.min(computer.y, canvas.height - computer.height), 0);
            if (!gameStarted && launchingPlayer === 'computer') {
                ball.y = computer.y + computer.height / 2;
            }
        }

        function update() {
            if (!gameStarted) return;

            ball.x += ball.velocityX;
            ball.y += ball.velocityY;

            if (ball.y + ball.radius > canvas.height || ball.y - ball.radius < 0) {
                ball.velocityY = -ball.velocityY;
            }

            let playerOrComputer = (ball.x < canvas.width / 2) ? player : computer;

            if (collision(ball, playerOrComputer)) {
                ball.velocityX = -ball.velocityX;
                ball.speed *= 1.1; // ボールのスピードを10%増加
                ball.velocityX = (ball.velocityX > 0 ? 1 : -1) * ball.speed;
                ball.velocityY = (ball.velocityY > 0 ? 1 : -1) * ball.speed;
            }

            if (ball.x - ball.radius < 0) {
                computer.score++;
                if (computer.score >= 5) {
                    alert("Computer Wins!");
                    resetGame();
                } else {
                    resetBall('player');
                }
            } else if (ball.x + ball.radius > canvas.width) {
                player.score++;
                if (player.score >= 5) {
                    alert("Player Wins!");
                    resetGame();
                } else {
                    resetBall('computer');
                }
            }

            moveComputerPaddle();
        }

        function collision(b, p) {
            p.top = p.y;
            p.bottom = p.y + p.height;
            p.left = p.x;
            p.right = p.x + p.width;

            b.top = b.y - b.radius;
            b.bottom = b.y + b.radius;
            b.left = b.x - b.radius;
            b.right = b.x + b.radius;

            return p.left < b.right && p.top < b.bottom && p.right > b.left && p.bottom > b.top;
        }

        function resetBall(lastLoss) {
            ball.speed = 5; // ボールの速度をリセット
            ball.velocityX = 0;
            ball.velocityY = 0;

            if (lastLoss === 'player') {
                ball.x = player.x + player.width + ball.radius;
                ball.y = player.y + player.height / 2;
            } else {
                ball.x = computer.x - ball.radius;
                ball.y = computer.y + computer.height / 2;
            }
            gameStarted = false;
            launchingPlayer = lastLoss; // ボールを発射するプレイヤーを設定
        }

        function resetGame() {
            player.score = 0;
            computer.score = 0;
            resetBall();
        }

        canvas.addEventListener('mousemove', movePaddle);
        canvas.addEventListener('click', () => {
            if (!gameStarted) {
                gameStarted = true;
                if (launchingPlayer === 'player') {
                    ball.velocityX = ball.speed;
                } else {
                    ball.velocityX = -ball.speed;
                }
                ball.velocityY = (Math.random() * 2 - 1) * ball.speed; // ランダムなY方向の速度
                launchingPlayer = null;
            }
        });

        function gameLoop() {
            update();
            render();
        }

        const framePerSecond = 50;
        setInterval(gameLoop, 1000 / framePerSecond);
    </script>
</body>
</html>

AIにプログラムを書いてもらうのは楽だった

なかなか使えそう。これでバグが頻発しなければな。バグを直してもらう方法も研究してみよう。俺のやり方が悪いだけで、絶対できる子だ。

Copilotさんは「絵」も描ける。

noteの絵は全部Copilotさんに描いてもらっている。
サイズを変えたり、ラフスケッチした絵を元に描いてもらったりするAIもあるらしいが、タダで使えるのは素晴らしい。

Copilotさんに自画像を描いてもらった
アニメタッチで自画像を書き直してもらったら、可愛く描いてるCopilotさん

SEは作れないが、アドバイスはくれるらしい。

SEは作れますか?
私はサウンドエフェクト自体を生成することはできませんが、ゲームに使用するためのサウンドエフェクトの作成方法やツールについてアドバイスできますよ。
例えば、以下のようなツールを使ってサウンドエフェクトを作成できます:

1. Bfxr:シンプルで直感的なインターフェースを持つ無料のオンラインツールです。特にレトロな8ビットサウンドを作成するのに適しています。
2. Audacity:無料のオーディオ編集ソフトウェアで、録音やエフェクトの追加、音声の編集ができます。
3. Freesound:ユーザーがアップロードした無料のサウンドエフェクトライブラリです。適切なライセンスを確認して使用できます。
4. FL Studio:プロフェッショナルなオーディオ編集および音楽制作ソフトウェアです。高度なサウンドデザインが可能です。

ゲームのサウンドエフェクトに関して具体的なアドバイスが必要でしたら、どのような効果音が必要か教えてください。アドバイスやチュートリアルのリンクなども提供できますよ。どうぞお知らせください。

ダメもとでGameMakerのコード書けるか聞いてみた。

gamemakerでプログラムできますか?
もちろん、GameMaker Studioを使ってプログラムできます。具体的なゲームのアイディアや機能を教えてもらえれば、それに応じたコードを提供できますよ。例えば、先ほどの卓球ゲームのコードをGameMaker用に書き直してほしいとか、特定の機能を追加したいとか。どんなアイディアがありますか?

GameMakerでもプログラムできるCopilotさん凄すぎ!

というわけで次回は、AIと協力してGameMakerで「卓球」を作ってみる。


いいなと思ったら応援しよう!