見出し画像

ChatGPTに恐竜ゲーム風のゲームを作ってもらった

ChatGPT(GPT-4)にゲームを作ってもらっているのをよく見かけるので、便乗してやってみました。

ブラウザでサクッと実行したいので、以下のように依頼します。

なお、一度に出力できる文字数には制限があるようで、何も指示をしないとJavaScriptファイルを出力している途中でネットワークエラーとなり、チャットが中断されてしまう事象が多々発生しました。
そのため、「1つのファイルを出力したら、そこで発言を止めてください」と指示を出して上記事象を回避するようにしています。

まず、index.htmlが出力されました。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Browser Game</title>
    <style>
        /* CSSはここに書きます */
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="800" height="400"></canvas>
    <script>
        // JavaScriptはここに書きます
    </script>
</body>
</html>

CSS、JavaScriptをhtmlに直接記述する形式ですね。
CSS、JavaScriptは別ファイルとして出力されるケースも多々ありました。

次に、CSS。

body {
    margin: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: #f0f0f0;
}

canvas {
    border: 1px solid #000;
}

そしてJavaScript。

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

let isJumping = false;
let jumpHeight = 0;

const player = {
    x: 100,
    y: canvas.height - 50,
    size: 40,
    draw() {
        ctx.fillStyle = 'black';
        ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
    },
    jump() {
        if (!isJumping) {
            isJumping = true;
            jumpHeight = 0;
        }
    }
};

canvas.addEventListener('click', player.jump);

function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    if (isJumping) {
        jumpHeight += 10;
        if (jumpHeight > 100) {
            isJumping = false;
        }
    } else {
        if (jumpHeight > 0) {
            jumpHeight -= 10;
        }
    }
    
    player.draw();
    
    requestAnimationFrame(gameLoop);
}

gameLoop();

コードの説明も記載してくれます。

このJavaScriptコードは、プレイヤーを表す四角形のオブジェクトを作成し、クリックでジャンプするようにします。また、gameLoop関数でアニメーションを実行し、プレイヤーを描画しています。

これで、Google Chromeの「Dinosaur Game」に似たシンプルなブラウザゲームが完成しました。index.htmlファイルを保存して、ブラウザで開いてゲームを試してみてください。もちろん、ゲームの要素や機能を追加して、さらに発展させることができます。

CSS、JavaScriptをindex.htmlに埋め込み、ブラウザで実行した結果がこちら。

クリックをすると、プレイヤーに見立てた黒い四角がジャンプします。それだけです。

明らかに機能が足りていないので、
・クリックでのジャンプからスペースキーでのジャンプへの変更
・ジャンプによって障害物をよける横スクロールアクションゲームへの修正
を依頼します。

JavaScriptが長くなりネットワークエラーが発生してしまうため、40行出力したらそこで止めるような指示を加えています。
プログラムの説明を長々されるとそこでも制限に引っかかるため、不要としています。

出力されたJavaScriptを組み合わせたものが以下です。

const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');

    let isJumping = false;
    let jumpHeight = 0;

    const player = {
      x: 100,
      y: canvas.height - 50,
      size: 40,
      draw() {
        ctx.fillStyle = 'black';
        ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
      },
      jump() {
        if (!isJumping) {
          isJumping = true;
          jumpHeight = 0;
        }
      }
    };

    document.addEventListener('keydown', (e) => {
      if (e.code === 'Space') {
        player.jump();
      }
    });

    class Obstacle {
      constructor(x, y, width, height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
      }

      draw() {
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x, this.y - this.height, this.width, this.height);
      }

      update() {
        this.x -= 5;

        if (this.x + this.width < 0) {
          this.x = canvas.width;
        }
      }
    }

    const obstacle = new Obstacle(canvas.width, canvas.height - 50, 40, 60);

    function checkCollision(player, obstacle) {
      const playerTop = player.y - player.size - jumpHeight;
      const playerBottom = player.y - jumpHeight;
      const playerLeft = player.x;
      const playerRight = player.x + player.size;

      const obstacleTop = obstacle.y - obstacle.height;
      const obstacleBottom = obstacle.y;
      const obstacleLeft = obstacle.x;
      const obstacleRight = obstacle.x + obstacle.width;

      return (
        playerBottom > obstacleTop &&
        playerTop < obstacleBottom &&
        playerRight > obstacleLeft &&
        playerLeft < obstacleRight
      );
    }

    function gameLoop() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      if (isJumping) {
        jumpHeight += 10;
        if (jumpHeight > 100) {
          isJumping = false;
        }
      } else {
        if (jumpHeight > 0) {
          jumpHeight -= 10;
        }
      }

      player.draw();
      obstacle.draw();
      obstacle.update();

      if (checkCollision(player, obstacle)) {
        console.log('Game Over');
      } else {
        requestAnimationFrame(gameLoop);
      }
    }

    gameLoop();

JavaScriptを差し替えると、障害物が右から左へスクロールされるようになりました。
この障害物に衝突すると、そこで動作が停止する仕様になっています。

さらに本家の恐竜ゲームへと近づけるため、
・ジャンプの滞空時間を長く
・複数の障害物を生成
・画面上に経過時間を表示
という依頼をしていきます。

最終的に出力されたJavaScriptは以下。

const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');

    let isJumping = false;
    let jumpHeight = 0;
    let elapsedTime = 0;

    const player = {
      x: 100,
      y: canvas.height - 50,
      size: 40,
      draw() {
        ctx.fillStyle = 'black';
        ctx.fillRect(this.x, this.y - this.size - jumpHeight, this.size, this.size);
      },
      jump() {
        if (!isJumping) {
          isJumping = true;
          jumpHeight = 0;
        }
      }
    };

    document.addEventListener('keydown', (e) => {
      if (e.code === 'Space') {
        player.jump();
      }
    });

    class Obstacle {
      constructor(x, y, width, height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
      }

      draw() {
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x, this.y - this.height, this.width, this.height);
      }

      update() {
        this.x -= 5;

        if (this.x + this.width < 0) {
          this.x = canvas.width + Math.random() * 800;
        }
      }
    }

    const obstacles = [
      new Obstacle(canvas.width, canvas.height - 50, 40, 60),
      new Obstacle(canvas.width + 400, canvas.height - 50, 40, 60),
    ];

    function checkCollision(player, obstacle) {
      const playerTop = player.y - player.size - jumpHeight;
      const playerBottom = player.y - jumpHeight;
      const playerLeft = player.x;
      const playerRight = player.x + player.size;

      const obstacleTop = obstacle.y - obstacle.height;
      const obstacleBottom = obstacle.y;
      const obstacleLeft = obstacle.x;
      const obstacleRight = obstacle.x + obstacle.width;

      return (
        playerBottom > obstacleTop &&
        playerTop < obstacleBottom &&
        playerRight > obstacleLeft &&
        playerLeft < obstacleRight
      );
    }

    function gameLoop(timestamp) {
      elapsedTime = Math.floor(timestamp / 1000);

      ctx.clearRect(0, 0, canvas.width, canvas.height);

      if (isJumping) {
        jumpHeight += 5;
        if (jumpHeight > 100) {
          isJumping = false;
        }
      } else {
        if (jumpHeight > 0) {
          jumpHeight -= 5;
        }
      }

      player.draw();
      obstacles.forEach(obstacle => {
        obstacle.draw();
        obstacle.update();
      });

      ctx.fillStyle = 'black';
      ctx.font = '20px Arial';
      ctx.fillText(`Time: ${elapsedTime}s`, 10, 30);

      if (obstacles.some(obstacle => checkCollision(player, obstacle))) {
        console.log('Game Over');
      } else {
        requestAnimationFrame(gameLoop);
      }
    }

    requestAnimationFrame(gameLoop);

40行単位で分割して出力しているからか、一部関数が重複したり抜けたりすることはあったものの、そこを切り張りで対応したのみで、プログラム自体の修正は全くしていません。

これで、この記事の冒頭でお見せした恐竜ゲーム風のゲームの完成です。

ネットワークエラー回避のための試行錯誤を含めても、トータル1時間かかっていません。
改めてGPT-4のすごさを実感させられました。

言葉通りの意味での「プログラマ」は、もはや不要なのでは。そう思う、元職業プログラマでした。


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