様々な学問/勉強課目をシミュレーションで解説!シミュレーター/ツール/ゲームで、いろんな学問を楽しく分かりやすく解説するサイトです!思考の改善や、効率化の話題も!
⇒ 本ブログの詳細/連絡先はコチラ!
学問系TOP AI/ChatGPT 数学 物理 統計学 コンピューター 経済学 Webツール
  1. ホーム
  2. 〇学問シミュレーター/改善・効率化
  3. AI/ChatGPT
  4. ChatGPTプログラム生成実験
  5. ChatGPT 自動プログラミング実験: 「マリオ風ゲーム」を作らせてみた!
■注目記事一覧

高校数学 教科書用シミュレーターの制作に携わりました!!

コンピューターの全理基礎:半加算器の原理をシミュレーターで理解しよう!

統計学/確率入門:偏差値とは何か?をシミュレーターを用いて詳しく解説!

余命(〇〇年後に死亡している確率)/各年齢での死亡確率 判定

なぜ賭け/投資(株式/FX)市場はほとんどの人が勝てないのか?シミュレーションで解説!

本サイトの「サイコロ シミュレーター」が熊本の特別教育テレビ授業で使われました!

コンピューターの半理基礎:半加算器の原理をシミュレーターで理解しよう!
 
全テーマ共通記事一覧

ChatGPT 自動プログラミング実験: 「マリオ風ゲーム」を作らせてみた!

自分が今まで理系の学問系中心に、内容を深く理解するためのシミュレータープログラムを作成してきました。このシミュレーター、簡単なものなら結構短いプログラムで書けてしまうこともあります。

「それなら、ChatGPTに全てプログラムを書かせるのも有り?」とふと思いました。ということで、様々なブラウザで動くようなシミュレーターやゲームをChatGPTに作成させる実験をしていきたいと思っています!

ChatGPT 自動プログラミング実験: 「マリオ風ゲーム」を作らせてみた!

今回のお題: マリオ風ゲームの作成

今回のお題は、マリオです。一番有名なゲームでもありますし、ちょうど2023年GW現在、マリオの映画も公開中ですので。

記念して、どれだけマリオっぽいゲームが自動で作れるか実験してみました!

ChatGPT 初回命令

ChatGPTへの命令

まずは↓の命令でプログラムを出力させてみました。

マリオのようなゲームを作って。javascriptで作って、ブラウザで動く形式で出力して下さい。

コード

生成されたプログラムが↓ですね。3つわけて出ていました。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simple Platformer</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <canvas id="gameScreen"></canvas>
    <script src="game.js"></script>
</body>
</html>

 

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

canvas {
    border: 1px solid #fff;
}

 

game.js
const canvas = document.getElementById('gameScreen');
const ctx = canvas.getContext('2d');

canvas.width = 800;
canvas.height = 400;

class Player {
    constructor(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
        this.velocityX = 0;
        this.velocityY = 0;
        this.onGround = false;
    }

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

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

        if (this.y + this.height < canvas.height) {
            this.velocityY += 1;
        } else {
            this.y = canvas.height - this.height;
            this.velocityY = 0;
            this.onGround = true;
        }
    }
}

const player = new Player(100, 100, 50, 50, 'blue');

function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    player.update();
    player.draw();
    requestAnimationFrame(gameLoop);
}

gameLoop();

document.addEventListener('keydown', (event) => {
    if (event.code === 'Space' && player.onGround) {
        player.velocityY = -15;
        player.onGround = false;
    }
});

document.addEventListener('keydown', (event) => {
    if (event.code === 'ArrowRight') {
        player.velocityX = 5;
    } else if (event.code === 'ArrowLeft') {
        player.velocityX = -5;
    }
});

document.addEventListener('keyup', (event) => {
    if (event.code === 'ArrowRight' || event.code === 'ArrowLeft') {
        player.velocityX = 0;
    }
});

生成されたゲーム

↓のようなゲームができました。全然マリオじゃないし、ゲームではないけどとりあえず、、。最低限はできている。キーボードの左右で移動、空白でジャンプができます。勝手にそういう設定になりました。

*画面内クリックしてから、左右と空白で操作できます

改変1: 敵を出現させて踏めるようにする

改変命令

さすがに敵がでないとマリオではないので、指導。

敵を作って、ジャンプで踏みつけて倒せるようにして

生成コード

↓のように変更点だけ、提示してくれる方式になりました。

改変部分コード
// 1. 敵キャラクターを表すEnemyクラスを作成
class Enemy {
    constructor(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }

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

// 2. 敵キャラクターを生成し、画面に表示
const enemy = new Enemy(400, 300, 50, 50, 'red');

// 敵キャラクターをゲームループに追加
function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    player.update();
    player.draw();
    enemy.draw(); // 追加
    checkCollision(); // 追加
    requestAnimationFrame(gameLoop);
}

// 3. プレイヤーと敵キャラクターの衝突判定
function checkCollision() {
    const playerX = player.x;
    const playerY = player.y;
    const playerWidth = player.width;
    const playerHeight = player.height;

    const enemyX = enemy.x;
    const enemyY = enemy.y;
    const enemyWidth = enemy.width;
    const enemyHeight = enemy.height;

    if (
        playerX < enemyX + enemyWidth &&
        playerX + playerWidth > enemyX &&
        playerY < enemyY + enemyHeight &&
        playerY + playerHeight > enemyY
    ) {
        // 4. 衝突が発生した場合、プレイヤーが敵キャラクターの上にいるか判定
        if (playerY + playerHeight < enemyY + enemyHeight / 2) {
            enemy.x = -100; // 敵を画面外に移動して倒す
        }
    }
}

生成されたゲーム

敵出現!でもなんか横からぶつかっても倒せてしまう、、、

*画面内クリックしてから、左右キーと空白キーで操作できます

改変2: 敵に横からぶつかったら、プレイヤーが死ぬようにする

改変命令

さすがにこれではプレイヤーが死なないので、改変

横からぶつかっても敵が倒せてしまいます。横からぶつかったら、プレイヤーが死ぬようにしてください。

生成コード

↓のように変更点提示されました。結構ながくなってくるので、プログラム書いたことない人だと、どこを変えればよいか分からなくなってきそう。

改変部分コード
class Player {
    // ... 既存のコード ...
    constructor(x, y, width, height, color) {
        // ... 既存のコード ...
        this.isDead = false; // 1. isDeadプロパティを追加
    }

    // ... 既存のコード ...
}

// ... 既存のコード ...

function checkCollision() {
    // ... 既存のコード ...

    if (
        playerX < enemyX + enemyWidth &&
        playerX + playerWidth > enemyX &&
        playerY < enemyY + enemyHeight &&
        playerY + playerHeight > enemyY
    ) {
        // 2. 衝突が発生した場合、プレイヤーが敵キャラクターの上にいるか判定
        if (playerY + playerHeight < enemyY + enemyHeight / 2) {
            enemy.x = -100; // 敵を画面外に移動して倒す
        } else {
            player.isDead = true; // プレイヤーを死亡状態にする
        }
    }
}

function gameLoop() {
    // プレイヤーが死んでいない場合のみ、ゲームループを続ける
    if (!player.isDead) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        player.update();
        player.draw();
        enemy.draw();
        checkCollision();
        requestAnimationFrame(gameLoop);
    } else {
        // プレイヤーが死んだ場合、ゲームオーバーのメッセージを表示
        ctx.font = '48px sans-serif';
        ctx.fillStyle = 'white';
        ctx.fillText('Game Over', canvas.width / 2 - 100, canvas.height / 2);
    }
}

生成されたシミュレーター

ちゃんと横からぶつかると、ゲームオーバーになるようになりました。ただ、プレイヤーのほうが敵より上なら、、、と判定してるので、上からぶつかっても倒せてしまう、、

*画面内クリックしてから、左右キーと空白キーで操作できます

改変3: 敵を定期的に出現させて、スコアを表示させる

改変命令

これだと敵一体倒したら終わりだし、スコアもなにもないので改変

敵を倒すごとに10ptのスコアが加算されるようにして下さい。スコアを右上に表示するようにして下さい。敵を倒したら、3秒後に次の敵が現れるようにして下さい。

生成コード

↓のように変更点だけ、提示してくれる方式になりました。

改変部分コード
// 1. スコアを保持する変数を追加
let score = 0;

// ... 既存のコード ...

function checkCollision() {
    // ... 既存のコード ...

    if (
        playerX < enemyX + enemyWidth &&
        playerX + playerWidth > enemyX &&
        playerY < enemyY + enemyHeight &&
        playerY + playerHeight > enemyY
    ) {
        if (playerY + playerHeight < enemyY + enemyHeight / 2) {
            enemy.x = -100; // 敵を画面外に移動して倒す
            score += 10; // 2. 敵を倒したときにスコアを加算
            spawnEnemy(); // 3. 敵を倒したら、3秒後に次の敵が現れるようにする
        } else {
            player.isDead = true; // プレイヤーを死亡状態にする
        }
    }
}

// 2. スコアを表示する関数を追加
function drawScore() {
    ctx.font = '24px sans-serif';
    ctx.fillStyle = 'white';
    ctx.fillText(`Score: ${score}`, canvas.width - 150, 30);
}

// 3. 敵を倒したら、3秒後に次の敵が現れるようにする
function spawnEnemy() {
    setTimeout(() => {
        enemy.x = canvas.width - 50;
        enemy.y = canvas.height - 50;
    }, 3000);
}

function gameLoop() {
    if (!player.isDead) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        player.update();
        player.draw();
        enemy.draw();
        checkCollision();
        drawScore(); // スコアを表示
        requestAnimationFrame(gameLoop);
    } else {
        // ... 既存のコード ...
    }
}

生成されたシミュレーター

いいですね。ゲームっぽくなってきました

*画面内クリックしてから、左右と空白で操作できます

改変4: 地面を表示させる

改変命令

さすがに風景の見た目がわるいので、指示

背景を空色にしてください。地面を茶色に塗ってください。

生成コード

↓のような感じになりました。いいですね。曖昧な指示でも意図が伝わる。

改変部分コード
function drawBackground() {
    // 1. キャンバスの背景色を空色に設定
    ctx.fillStyle = 'skyblue';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
}

function drawGround() {
    // 2. 地面を表す矩形を描画し、茶色に塗る
    const groundHeight = 50;
    ctx.fillStyle = 'saddlebrown';
    ctx.fillRect(0, canvas.height - groundHeight, canvas.width, groundHeight);
}

function gameLoop() {
    if (!player.isDead) {
        // ... 既存のコード ...

        drawBackground(); // 背景を描画
        drawGround();     // 地面を描画
        player.update();
        player.draw();
        enemy.draw();
        checkCollision();
        drawScore();
        requestAnimationFrame(gameLoop);
    } else {
        // ... 既存のコード ...
    }
}

生成されたシミュレーター

あれ、表示はいいけどなんでプレイヤーが地面の下にいるんだろう、、、
と思って色々指示しましたが、ここはなぜか簡単には直せませんでした、、。修正によってプレイヤー出現位置は地面上に指定できるけど、最初に設定した着地位置が変えられないので結局プレイヤーが↓の位置まで下がってしまう感じですね。こういった文脈が長くなってくると、なかなか日本語指示だけでなおさせるのは難しくなります。

*画面内クリックしてから、左右キーと空白キーで操作できます

改変5: 敵が同じところばかりでるので修正

敵の位置が毎回同じはきついので、ランダム出現するように依頼しました。

ChatGPTへの命令

敵の位置がいつも同じです。ランダムに出現させて下さい。プレイヤーが倒せる範囲内で

生成コード

↓のような改変命令がでました。ちなみに初回はなぜかy軸しかランダムにしてくれなかったので、x軸ランダムも追加依頼実はしてます。

改変部分
function getRandomEnemyY(height) {
    const minY = canvas.height - GROUND_HEIGHT - height * 2;
    const maxY = canvas.height - GROUND_HEIGHT - height;
    return Math.floor(Math.random() * (maxY - minY + 1)) + minY;
}

function getRandomEnemyX(width) {
    const minX = canvas.width / 2;
    const maxX = canvas.width - width;
    return Math.floor(Math.random() * (maxX - minX + 1)) + minX;
}

function spawnEnemy() {
    setTimeout(() => {
        // 2. 敵をスポーンする関数で、x座標をランダムに設定
        enemy.x = getRandomEnemyX(enemy.width);
        enemy.y = getRandomEnemyY(enemy.height);
    }, 3000);
}

生成されたゲーム

なんか厳しい位置に敵が現れるし、ぶつかって倒してるように見えるし、いまだにプレイヤーが地面下にいるのは気になるけど。とりあえずゲームとしては最低限のレベルになりましたね、、

*画面内クリックしてから、左右キーと空白キーで操作できます

結論:何度も修正は必要だが、最低限のゲームの骨組みなら作れる!

今回は何回かの指示で、マリオ風ゲームをつくっていきました。やっぱりいきなり出てきたゲームは別物であったため、少しずつ指示してつくっていきました。基本的には少しずつなおせばいいんですが、今回の地面下に配置されるのとか直りにくいバグもあるので、そしたら手でやっぱり修正する必要がありますね、、、

ということで完全に全自動は現状きついかと思います><


⇒「ChatGPTプログラム生成実験」カテゴリ記事一覧

その他関連カテゴリ




お気軽にコメントお願いします!

Your email address will not be published. Required fields are marked *




記事カテゴリ