テクノロジー

【テクノロジー】プログラミング初心者がChatGPTを利用してブロック崩し風ゲームの作成にチャレンジ!

テクノロジー

■はじめに

前回、プログラミング初心者がChatGPTを利用すれば、簡単にゲームを作成できるかチャレンジしましたが、
今回はその「 応用編 」として、「 プログラミング初心者がChatGPTを利用すれば、簡単にブロック崩し風ゲーム 」を作成できるかチャレンジしたいと思います。

細かい説明は前回さてもらいましたので、今回は「 ChatGPTの説明 」や「 拡張子の説明 」など細かい部分は省略して話しを進めていきたいと思います。

また、「 テトリス風ゲーム 」の作成は次回に紹介したいと思いますので、急ぎの方はページ下部の「 Nextボタン 」や「 もくじ 」を利用して次ページを閲覧してください。

この記事を見て皆さんが、「 明日の話しのネタにしてみよう 」、今度の休みは「 こんなことやってみよう 」のヒントになれば幸いです。

【 結果 】
「 ChatGPT 」を上手く活用することができれば、プログラミングを自分で行わなくても、簡単な「 ブロック崩し風ゲーム 」であれば作成することができました。(詳細は下記参照)

ただ、プログラムの内容が分からないため単純な修正も行えず、自分の思うプログラムができるまで時間がかかるため、同じ時間をかけるなら「 プログラミングを覚えながら 」ChatGPTを活用するほうが自分の力になるし、効率がよいとのではないかと思います。

■開発環境

今回も前回と同様に、開発環境は、「 インターネット閲覧ソフト(ブラウザ) 」と「 メモ帳 」を使いたいと思います。
この二つであればすでにパソコンにインストールしてあると思いますので、特別な準備をしないで済むと思います。
また、新しくソフトをインストールする行為は「 簡単に 」とは言い難いためです。

【開発環境】
 ・ChatGPT 3.5
 ・Windowsのインストールしてあるパソコン
 (OSはWindows10 or 11が好ましい)
 ・インターネットを見られる環境。
 (Edge、chrome)
 ・メモ帳

■ブロック崩し風ゲームを作る

ChatGPTへの質問の仕方

ChatGPTに質問をするために、以下のキーワードを含めて質問をしたいと思います。

【キーワード】
ブラウザ
インターネット閲覧ソフトを使ってゲームを行うため、「 ブラウザ 」という言葉を使用します。

HTML
ブラウザでプログラミングを行うということは「 HTML 」という言語をつかうため、「 HTML 」という言葉を使用します。

ソースコード
プログラミングの内容のことを「 ソースコード 」というので、「 ソースコード 」という言葉を使用します。

ブロック崩し
「 ブロック崩し風 」のゲームを作りたいため、「 ブロック崩し 」という言葉を使用します。

上記の「 キーワード 」を含めて、下記のような質問をしたいと思います。

質問内容

「 htmlを使用し、パソコンのブラウザ上で動くブロック崩しゲームのプログラミングのソースコードを教えて。 」

ChatGPTへ質問する

先ほど決めた質問内容をChatGPTへ質問したいと思います。

ChatGPTへ質問

「 htmlを使用し、パソコンのブラウザ上で動くブロック崩しゲームのプログラミングのソースコードを教えて。 」

ChatGPTの回答

上記の質問を行った結果、下記のような回答を得ることができました。
※ 文章の末尾に[ChatGPT]と記載している箇所は、ChatGPTの回答文になります。

ChatGPTの回答

ブロック崩しゲームのHTML5とJavaScriptを使用した簡単な実装例を以下に示します。このコードは、HTMLファイル内にJavaScriptを埋め込んでいます。[ChatGPT]

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ブロック崩しゲーム</title>
<style>
    #gameCanvas {
        background: #eee;
        display: block;
        margin: 0 auto;
    }
</style>
</head>
<body>
<canvas id="gameCanvas" width="480" height="320"></canvas>
<script>
    var canvas = document.getElementById("gameCanvas");
    var ctx = canvas.getContext("2d");

    var ballRadius = 10;
    var x = canvas.width / 2;
    var y = canvas.height - 30;
    var dx = 2;
    var dy = -2;

    var paddleHeight = 10;
    var paddleWidth = 75;
    var paddleX = (canvas.width - paddleWidth) / 2;

    var rightPressed = false;
    var leftPressed = false;

    var brickRowCount = 5;
    var brickColumnCount = 3;
    var brickWidth = 75;
    var brickHeight = 20;
    var brickPadding = 10;
    var brickOffsetTop = 30;
    var brickOffsetLeft = 30;

    var bricks = [];
    for (var c = 0; c < brickColumnCount; c++) {
        bricks[c] = [];
        for (var r = 0; r < brickRowCount; r++) {
            bricks[c][r] = { x: 0, y: 0, status: 1 };
        }
    }

    document.addEventListener("keydown", keyDownHandler, false);
    document.addEventListener("keyup", keyUpHandler, false);

    function keyDownHandler(e) {
        if (e.key === "Right" || e.key === "ArrowRight") {
            rightPressed = true;
        } else if (e.key === "Left" || e.key === "ArrowLeft") {
            leftPressed = true;
        }
    }

    function keyUpHandler(e) {
        if (e.key === "Right" || e.key === "ArrowRight") {
            rightPressed = false;
        } else if (e.key === "Left" || e.key === "ArrowLeft") {
            leftPressed = false;
        }
    }

    function collisionDetection() {
        for (var c = 0; c < brickColumnCount; c++) {
            for (var r = 0; r < brickRowCount; r++) {
                var b = bricks[c][r];
                if (b.status === 1) {
                    if (
                        x > b.x &&
                        x < b.x + brickWidth &&
                        y > b.y &&
                        y < b.y + brickHeight
                    ) {
                        dy = -dy;
                        b.status = 0;
                    }
                }
            }
        }
    }

    function drawBall() {
        ctx.beginPath();
        ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }

    function drawPaddle() {
        ctx.beginPath();
        ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
        ctx.fillStyle = "#0095DD";
        ctx.fill();
        ctx.closePath();
    }

    function drawBricks() {
        for (var c = 0; c < brickColumnCount; c++) {
            for (var r = 0; r < brickRowCount; r++) {
                if (bricks[c][r].status === 1) {
                    var brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
                    var brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
                    bricks[c][r].x = brickX;
                    bricks[c][r].y = brickY;
                    ctx.beginPath();
                    ctx.rect(brickX, brickY, brickWidth, brickHeight);
                    ctx.fillStyle = "#0095DD";
                    ctx.fill();
                    ctx.closePath();
                }
            }
        }
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        drawBricks();
        drawBall();
        drawPaddle();
        collisionDetection();

        if (x + dx > canvas.width - ballRadius || x + dx < ballRadius) {
            dx = -dx;
        }
        if (y + dy < ballRadius) {
            dy = -dy;
        } else if (y + dy > canvas.height - ballRadius) {
            if (x > paddleX && x < paddleX + paddleWidth) {
                dy = -dy;
            } else {
                alert("ゲームオーバー");
                document.location.reload();
            }
        }

        if (rightPressed && paddleX < canvas.width - paddleWidth) {
            paddleX += 7;
        } else if (leftPressed && paddleX > 0) {
            paddleX -= 7;
        }

        x += dx;
        y += dy;
        requestAnimationFrame(draw);
    }

    draw();
</script>
</body>
</html>

このコードは、基本的なブロック崩しゲームを作成します。ブロックの数やサイズ、ボールの速度などのパラメータは変更可能です。[ChatGPT]

ゲームを動かす

ゲームを動かす手順。

【 ゲームを動かす手順 】
 ① メモ帳を新規に作成する。(名前はお好みでOK)
 ② メモ帳を開く。
 ③ メモ帳に「 プログラム 」を張り付ける。
  ※ DOCTYPE html ~ /html の部分になります。
 ④ メモ帳(~~.txt)を「 保存 」する。
 ⑤ 拡張子を変更する。(~~.txt → ~~.html)
 ⑥ 「 拡張子を変更しますか? 」で、「 はい 」を選択する。
 ⑦ 「 HTML形式ファイル 」を「 ダブルクリック 」で起動する。
 ⑧ ゲームで遊ぶ。

ゲーム画面

ゲームを起動すると下図のような「 ブロック崩し風ゲーム 」がブラウザで起動します。

操作方法は下記になります。

【 操作方法 】
・「 キーボド 」の左右を使って、丸いボールを弾き、ブロックを崩していきます。
・丸いボールが落ちるとゲームオーバーで操作不能になります。

【 操作不能になったら 】
・「 ×印 」でブラウザを閉じて終了するか、「 F5キー 」を押して画面を更新することで再スタートできます。

■問題点の洗い出し

「 ChatGPT 」を利用することで、簡単に「 ブロック崩し風ゲーム 」を作ることができましたが、いろいろ問題点がありました。

【 問題点 】
致命的:
・スタート直後の画面を見ると、向かって右側にブロックが配置されていません。
・ゲームオーバーになると、画面が固まってしまい、「 F5で更新 」をするか、「 ×印 」で終了するしかありません。

希望:
・スコアも表示したい。
・ボールの色も変えてみたい。
・その他各種

下図はスタート直後の様子になります。
画面に右側にブロックが配置されていないことが確認できます。

■同じ質問をChatGPTにした時の変化

問題点の改善を依頼したいところですが、まったく同じ質問を「 New chat(新規で質問) 」で何度か繰り返して見たところ、右側にもブロックが配置され、先ほどよりよさそうな出来栄えになってくれました。
※ 5回ほど質問しました。

ChatGPTへ質問

「 htmlを使用し、パソコンのブラウザ上で動くブロック崩しゲームのプログラミングのソースコードを教えて。 」

ChatGPTは、「 同じ質問 」を行っても、毎回考えて回答をしてくれるため、「 回答の結果がいつも同じになるとは限りません 」。
そのため、自分の知りたい回答と違った場合、同じ質問を数回行うか、少し質問の内容を変えてあげると希望する回答を得られることがあります。

今回はわざと「 New chat(新規で質問) 」で質問を行いましたが、続けて質問を行ったほうが回答の精度は上がります。

下図は、ブロックを5列にしてくれた時の画面になります。

■スタートボタンと再スタートボタンの追加

ChatGPTへ質問する

何度か質問を繰り返すことで、右側にもブロックが配置され見た目は改善されましたが、
今回も、ゲームオーバーになると、画面が固まってしまい、「 F5で更新 」をするか、「 ×印 」で終了するしかなかったため、追加で以下の質問をしてみました。

ChatGPTへ質問

「 スタートボタンと、ゲームオーバーになったときに再スタートできるようにボタンを追加して。 」
※ 今度は「 New chat(新規で質問) 」ではなく連続して質問しました。

ChatGPTの回答

ChatGPTの回答

了解です。スタートボタンと再スタートボタンを追加して、ゲームを開始および再開できるようにしましょう。以下が更新されたソースコードです。[ChatGPT]

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ブロック崩しゲーム</title>
    <style>
        #gameCanvas {
            background-color: #eee;
            display: block;
            margin: auto;
            margin-top: 20px;
            border: 2px solid #333;
        }
        .button {
            display: inline-block;
            padding: 10px 20px;
            font-size: 16px;
            cursor: pointer;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <div id="buttonContainer" style="text-align: center;">
        <button id="startButton" class="button">スタート</button>
        <button id="restartButton" class="button" style="display: none;">再スタート</button>
    </div>

    <script>
        // Canvas要素を取得
        var canvas = document.getElementById("gameCanvas");
        var ctx = canvas.getContext("2d");

        // ボールの初期位置と速度
        var x = canvas.width / 2;
        var y = canvas.height - 30;
        var dx = 2;
        var dy = -2;

        // ボールの半径
        var ballRadius = 10;

        // パドルのサイズと位置
        var paddleHeight = 10;
        var paddleWidth = 75;
        var paddleX = (canvas.width - paddleWidth) / 2;

        // パドルを動かすためのキーイベント
        var rightPressed = false;
        var leftPressed = false;

        function keyDownHandler(e) {
            if(e.key == "Right" || e.key == "ArrowRight") {
                rightPressed = true;
            }
            else if(e.key == "Left" || e.key == "ArrowLeft") {
                leftPressed = true;
            }
        }

        function keyUpHandler(e) {
            if(e.key == "Right" || e.key == "ArrowRight") {
                rightPressed = false;
            }
            else if(e.key == "Left" || e.key == "ArrowLeft") {
                leftPressed = false;
            }
        }

        // ブロックの設定
        var brickRowCount = 3;
        var brickColumnCount = 5;
        var brickWidth = 75;
        var brickHeight = 20;
        var brickPadding = 10;
        var brickOffsetTop = 30;
        var brickOffsetLeft = 30;

        var bricks = [];
        for(var c=0; c<brickColumnCount; c++) {
            bricks[c] = [];
            for(var r=0; r<brickRowCount; r++) {
                bricks[c][r] = { x: 0, y: 0, status: 1 };
            }
        }

        // スコアとゲームオーバーメッセージ
        var score = 0;
        var gameOver = false;

        // スタートボタンと再スタートボタン
        var startButton = document.getElementById("startButton");
        var restartButton = document.getElementById("restartButton");

        startButton.addEventListener("click", startGame);
        restartButton.addEventListener("click", restartGame);

        function startGame() {
            startButton.style.display = "none";
            document.addEventListener("keydown", keyDownHandler, false);
            document.addEventListener("keyup", keyUpHandler, false);
            draw();
        }

        function restartGame() {
            document.location.reload();
        }

        // ボールとブロックの当たり判定
        function collisionDetection() {
            for(var c=0; c<brickColumnCount; c++) {
                for(var r=0; r<brickRowCount; r++) {
                    var b = bricks[c][r];
                    if(b.status == 1) {
                        if(x > b.x && x < b.x+brickWidth && y > b.y && y < b.y+brickHeight) {
                            dy = -dy;
                            b.status = 0;
                            score++;
                            if(score == brickRowCount*brickColumnCount) {
                                gameOver = true;
                                alert("ゲームクリア!");
                                restartButton.style.display = "inline-block";
                            }
                        }
                    }
                }
            }
        }

        // パドルを描画
        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, canvas.height - paddleHeight, paddleWidth, paddleHeight);
            ctx.fillStyle = "#0095DD";
            ctx.fill();
            ctx.closePath();
        }

        // ボールを描画
        function drawBall() {
            ctx.beginPath();
            ctx.arc(x, y, ballRadius, 0, Math.PI*2);
            ctx.fillStyle = "#0095DD";
            ctx.fill();
            ctx.closePath();
        }

        // ブロックを描画
        function drawBricks() {
            for(var c=0; c<brickColumnCount; c++) {
                for(var r=0; r<brickRowCount; r++) {
                    if(bricks[c][r].status == 1) {
                        var brickX = (c*(brickWidth+brickPadding))+brickOffsetLeft;
                        var brickY = (r*(brickHeight+brickPadding))+brickOffsetTop;
                        bricks[c][r].x = brickX;
                        bricks[c][r].y = brickY;
                        ctx.beginPath();
                        ctx.rect(brickX, brickY, brickWidth, brickHeight);
                        ctx.fillStyle = "#0095DD";
                        ctx.fill();
                        ctx.closePath();
                    }
                }
            }
        }

        // ゲームを描画
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawBricks();
            drawBall();
            drawPaddle();
            collisionDetection();

            // ボールが左右の壁に当たった場合、反射させる
            if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
                dx = -dx;
            }

            // ボールが上の壁に当たった場合、反射させる
            if(y + dy < ballRadius) {
                dy = -dy;
            }
            // ボールがパドルに当たった場合、反射させる
            else if(y + dy > canvas.height-ballRadius) {
                if(x > paddleX && x < paddleX +

paddleWidth) {
                    dy = -dy;
                }
                else {
                    // ゲームオーバー
                    gameOver = true;
                    alert("ゲームオーバー!");
                    restartButton.style.display = "inline-block";
                }
            }

            // パドルを動かす
            if(rightPressed && paddleX < canvas.width - paddleWidth) {
                paddleX += 7;
            }
            else if(leftPressed && paddleX > 0) {
                paddleX -= 7;
            }

            x += dx;
            y += dy;

            if (!gameOver) {
                requestAnimationFrame(draw);
            }
        }

        // ゲームの開始時にスタートボタンを表示する
        function init() {
            startButton.style.display = "inline-block";
            restartButton.style.display = "none";
        }

        // ゲームを初期化
        init();

    </script>
</body>
</html>

このコードでは、スタートボタンをクリックすることでゲームを開始し、再スタートボタンをクリックすることでゲームを再開できるようになります。ゲームオーバー時には再スタートボタンが表示され、クリックすることでゲームが再開されます。[ChatGPT]

補足

実は途中で、文字数が多くなって回答が止まってしまったため、「 続きはありますか? 」と質問しました。
長文の回答中が途中で止まってしまった時や、続きの文章がありそうなときは、「 続きはありますか? 」「 これで終わりですか? 」などと「 ChatGPT 」へ質問をすると、続きを表示してくれます。

【 回答が途中で止まった時のやりとり 】


~ 略 ~
  // ボールがパドルに当たった場合、反射させる
            else if(y + dy > canvas.height-ballRadius) {
                if(x > paddleX && x < paddleX +

※ ※ ここで回答が止まってしまった ※ ※


【質問】
「 続きはありますか? 」

【回答】
もちろんです!失礼しました。以下に続きのコードを提供します。[ChatGPT]

paddleWidth) {
                    dy = -dy;
                }
                else {
                    // ゲームオーバー
                    gameOver = true;
                    alert("ゲームオーバー!");
                    restartButton.style.display = "inline-block";
~ 略 ~

ゲームを動かす

先ほどの「 スタートボタン 」付の「 ブロック崩し風ゲーム 」を起動すると、何やらスタートボタンのようなものが追加されていることが分かります。

スタートボタンを押してみると、ゲームが開始されました。

ゲームオーバーになってしまったため、ポップアップの「 OK 」ボタンを押してみます。

「 再スタート 」ボタンが表示されたので、「 再スタート 」ボタンを押してみます。

「 スタート 」画面に戻りました。

このように、「 スコア 」を表示したければ「 スコア表示を追加できますか? 」など、自分の追加したい機能を続けて質問していくことにより、「 ChatGPT 」にプログラムを組んでもらうことができます。

■結果

プログラミングができなくても

プログラミングができなくても、上記のように「 ChatGPT 」を上手く活用することができれば簡単なゲームなら作成することは可能です。
ただ、プログラムの内容がさっぱり分からないため単純な修正も行えず、自分の思うプログラムができるまで時間がかかることが予想できると思います。

プログラミングができれば

もし、プログラミングができれば、はじめに作った「 ブロック崩し風ゲーム 」を少し修正してあげればブロックを「 5列 」にしてあげることが容易にできます。

修正内容は、プログラム中の「 3 」を「 5 」に変更するだけです。

【修正内容】
    var rightPressed = false;
    var leftPressed = false;

    var brickRowCount = 5;
    var brickColumnCount = 3;  ← ここを「 5 」にすると5列になる
    var brickWidth = 75;
    var brickHeight = 20;
    var brickPadding = 10;
    var brickOffsetTop = 30;
    var brickOffsetLeft = 30;

下図は、ブロックが修正されて「 5列 」になった様子です。

このように、プログラミングが分かると「 ChatGPT 」にプログラムのたたき台を作ってもらって、あとは修正するだけで簡単なゲームを作ることができたり、「 ChatGPT 」の組んだプログラムの一部を「 コピー 」して修正したり、プログラムのアイデアをマネすることで作業の効率化が図れます。

「 ChatGPT 」は、プログラミング以外の「 文章や資料 」も作ってもらうことができるため、文章や資料のたたき台を作ってもらって、あとは自分で修正するといった形で作業の効率化を図ることもできます。

次回は更に踏み込んで「 テトリス風ゲーム 」の作成にチャレンジしてみたいと思います。

内容を理解しやすくするため表現を誇張しているが部分があることや、 このサイトの内容が絶対に正しいという保証は出来ません。 また、実作業における破損・傷害等に付きましても保証できないため、ご了承の上お付き合い頂けたら幸いです。

タイトルとURLをコピーしました