見出し画像

【ChatGPT o1-mini】インベーダーゲーム:仕様書を作ってからコーディング(遊べます)


はじめに

o1-miniのコーディングの実力を試す。
前回のアステロイドゲームに続き、今回はインベーダーゲームを作ります。

ゲームを作るにあたっては、先にGPT-4oで仕様書を作り、その詳細な仕様書に基づいてo1-miniにコーディングしてもらうことで、より精度の高いゲームを開発します。
と言っても、プロンプトは非常に簡単なのですぐに試していただけます。

すぐに遊んでみたい方は、この画像をクリックすると、サーバにアップしてあるファイルが稼働して遊べます。↓

UFOも出ます

仕様書の作成

仕様書作成プロンプト

あなたはプロのゲーム制作者です。ゲーム制作に使用できるレベルの詳細なインベーダーゲームの仕様を書いてください。

仕様書は、GPT-4oで作成します。なぜなら、o1-miniの使用回数は1週間あたり50回に制限されているためです。
GPT-4oは、3時間あたり80回使用できます。

仕様書

インベーダーゲーム仕様書

ゲームの概要

プレイヤーは画面下部の自機を操作し、上空から迫り来る敵(エイリアン)を撃ち落として進行を阻止することが目的の2Dシューティングゲームです。敵を全滅させると次のレベルへ進み、敵の動きが速くなるなど、難易度が徐々に上がっていきます。自機が破壊されるか、敵が画面下部に到達するとゲームオーバーになります。


1. プラットフォーム

  • 対象プラットフォーム: PC, コンソール, モバイル

  • 開発環境: Unity (C#) / Unreal Engine (C++) / Phaser (JavaScript)など


2. 基本システム

2.1. ゲーム画面構成

  • 画面解像度: 1920x1080(HD)を基準とする。アスペクト比は16:9。

  • エリア: 画面は上から順に「エイリアンエリア」「障害物エリア」「プレイヤーエリア」に分かれる。

    • エイリアンエリア: 敵が配置され、徐々にプレイヤー側に迫ってくる。

    • 障害物エリア: プレイヤーの弾や敵の弾を遮る障害物が設置されている。障害物は攻撃を受けると徐々に壊れていく。

    • プレイヤーエリア: プレイヤーの自機が左右に移動し、弾を発射する。


2.2. 操作方法

  • 自機の移動:

    • 左右方向に移動可能(X軸のみ)

    • キーボードの左右キーまたは、A/Dキーで操作(PCの場合)

    • モバイルではタッチスライドによる操作

    • コントローラーの左右スティック、またはD-padで移動(コンソール)

  • 射撃:

    • プレイヤーは1種類の弾を発射可能。

    • キーボードのスペースキーまたはコントローラーのボタンで射撃。

    • モバイルではタッチ操作による射撃ボタンを配置。


2.3. 敵(エイリアン)

  • 配置: 敵は5行×11列(計55体)のマトリクス状に配置される。

  • 移動パターン: 敵は一斉に左右に移動し、端に達すると縦に1段下がる。移動速度は敵の数が減るごとに速くなる。

  • 攻撃: ランダムなタイミングで、一定の敵が下方向に弾を発射する。

  • 種類: 敵は複数種類存在し、得点や外見が異なる。

    • 標準エイリアン: 一般的な敵。基本得点。

    • 強化エイリアン: 移動速度や耐久力が高い。高得点。

    • UFO(ボーナス敵): 上部を横切る特殊な敵。プレイヤーが撃破すると高得点。


3. システム仕様

3.1. ラウンド進行

  • ラウンドクリア条件: すべての敵を撃破するとラウンドクリア。

  • 次ラウンドへの移行: 敵の数や速度、攻撃頻度が増加する次のラウンドに進む。

  • 難易度上昇要素:

    • 敵の移動速度が増加。

    • 敵の弾発射頻度が上昇。

    • 障害物の耐久力が低下。


3.2. ゲームオーバー条件

  • 敵が画面下部まで到達した場合。

  • プレイヤーの自機がすべて破壊された場合(ライフが0になる)。

  • ゲームオーバー時にはスコアとメインメニューへの遷移が表示される。


3.3. ライフシステム

  • 初期ライフ: プレイヤーは初期状態で3ライフを持つ。

  • ライフ減少: 敵の弾や敵自体に自機が接触するとライフが1つ減少。

  • ライフ追加: 一定のスコアに達するとライフが1つ追加される。


3.4. スコアシステム

  • 基本スコア: 敵を撃破するごとに得点が加算される。

    • 標準エイリアン: 100点

    • 強化エイリアン: 200点

    • UFO: 500点

  • ハイスコア: ゲームオーバー後にハイスコアが保存され、メインメニューに表示。


3.5. 障害物

  • 配置: 画面中ほどに4つの障害物が設置されている。

  • 破壊: 障害物はプレイヤーと敵の弾で破壊される。各障害物には耐久力が設定されており、一定回数の攻撃で消滅する。

  • 再生成: 新しいラウンド開始時に障害物は再生成される。


4. ビジュアルおよびサウンド

4.1. ビジュアル

  • グラフィックスタイル: レトロなピクセルアート風のデザイン。または、モダンな2Dスタイル。

  • エフェクト: 弾の発射、敵の爆発、自機の破壊時には専用のエフェクト(閃光、爆発)が表示される。


4.2. サウンド

  • BGM: ラウンドごとに異なるBGMがループ再生される。敵の数が減るとBGMが速くなる演出。

  • 効果音:

    • 弾発射音、敵撃破音、自機破壊音

    • UFO出現時の特殊効果音

  • ボリュームコントロール: BGMと効果音はそれぞれ個別にオン/オフおよびボリューム調整が可能。


5. UI設計

5.1. メインメニュー

  • 項目:

    • プレイ開始

    • オプション(サウンド設定、操作設定)

    • ハイスコア

    • 終了


5.2. ゲーム画面UI

  • スコア表示: 画面上部に現在のスコアとハイスコアを表示。

  • ライフ表示: 画面左下に残りライフをアイコンで表示。

  • ラウンド表示: 現在のラウンドを右上に表示。


6. 拡張機能

6.1. マルチプレイヤーモード

  • 協力プレイ: 2人のプレイヤーが同時に参加し、協力して敵を撃破する。ライフとスコアは共有。

  • 対戦プレイ: 2人のプレイヤーが別々に敵を倒し、どちらが多くのスコアを稼げるか競うモード。

6.2. スペシャルウェポン

  • 特定の条件を満たすと、自機に強力な武器(連射可能なレーザー、爆発弾など)が一時的に追加される。


7. 技術仕様

7.1. フレームレート

  • 目標フレームレート: 60fps

7.2. 物理エンジン

  • 基本的な当たり判定は矩形(AABB)で処理。

  • 弾と敵、弾と障害物、自機と敵の衝突判定。

7.3. 外部ライブラリ

  • パーティクルエフェクト: エフェクト強化のために外部ライブラリ(例: Unityのパーティクルシステム)を使用。


この仕様書を基に、ゲームの設計、プログラミング、グラフィックデザイン、サウンドデザインなど各フェーズに進行できます。また、ゲームバランスや追加要素は開発途中でテスト・調整を繰り返しながら仕上げる形となります。

o1-miniにモデルを切り替え

次に、モデルを切り替えて以下のプロンプトを入力します。今回は、Webアプリケーションとして作りたいので、プロンプトではそのような指定をしています。

プロンプト

上記の使用をもとに、HTML、CSS、JSでできる範囲で、コードを実装してください。シングルHTMLファイルアプリケーションで作ります。

o1-miniの出力

以下に、シングルHTMLファイルとして実装可能なインベーダーゲームのコードを提供します。このコードは、HTML、CSS、JavaScriptを使用して基本的なゲーム機能を実現しています。以下のコードをコピーして `.html` ファイルとして保存し、ブラウザで開くことでゲームをプレイできます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>インベーダーゲーム</title>
    <style>
        /* リセットスタイル */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        /* ゲームキャンバスのスタイル */
        body {
            background-color: #000;
            color: #fff;
            font-family: Arial, sans-serif;
            overflow: hidden;
        }

        #gameCanvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }

        /* メインメニューのスタイル */
        #mainMenu {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
        }

        #mainMenu button {
            display: block;
            width: 200px;
            margin: 10px auto;
            padding: 10px;
            font-size: 18px;
            cursor: pointer;
        }

        /* ゲームオーバー画面のスタイル */
        #gameOverScreen {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            display: none;
        }

        #gameOverScreen button {
            display: block;
            width: 200px;
            margin: 10px auto;
            padding: 10px;
            font-size: 18px;
            cursor: pointer;
        }

        /* スコア表示のスタイル */
        #scoreBoard {
            position: absolute;
            top: 10px;
            left: 10px;
            font-size: 18px;
        }

        /* ライフ表示のスタイル */
        #lifeBoard {
            position: absolute;
            top: 10px;
            right: 10px;
            font-size: 18px;
        }

        /* ラウンド表示のスタイル */
        #roundBoard {
            position: absolute;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 18px;
        }
    </style>
</head>
<body>
    <!-- メインメニュー -->
    <div id="mainMenu">
        <h1>インベーダーゲーム</h1>
        <button onclick="startGame()">プレイ開始</button>
        <button onclick="showHighScore()">ハイスコア</button>
        <button onclick="closeGame()">終了</button>
    </div>

    <!-- ゲームオーバー画面 -->
    <div id="gameOverScreen">
        <h1>ゲームオーバー</h1>
        <p id="finalScore">スコア: 0</p>
        <button onclick="restartGame()">もう一度プレイ</button>
        <button onclick="returnToMenu()">メインメニューへ</button>
    </div>

    <!-- スコア、ライフ、ラウンド表示 -->
    <div id="scoreBoard">スコア: 0</div>
    <div id="lifeBoard">ライフ: ♥♥♥</div>
    <div id="roundBoard">ラウンド: 1</div>

    <!-- ゲームキャンバス -->
    <canvas id="gameCanvas" width="800" height="600"></canvas>

    <script>
        // ゲームの初期設定
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const mainMenu = document.getElementById('mainMenu');
        const gameOverScreen = document.getElementById('gameOverScreen');
        const finalScoreElem = document.getElementById('finalScore');

        const scoreBoard = document.getElementById('scoreBoard');
        const lifeBoard = document.getElementById('lifeBoard');
        const roundBoard = document.getElementById('roundBoard');

        let gameInterval;
        let enemyShootInterval;
        let ufoInterval;

        // ゲームの状態
        let gameState = 'menu'; // 'menu', 'playing', 'gameover'

        // プレイヤーの設定
        const player = {
            width: 50,
            height: 30,
            x: canvas.width / 2 - 25,
            y: canvas.height - 50,
            speed: 5,
            dx: 0,
            bullets: [],
            canShoot: true,
            shootCooldown: 500, // ミリ秒
            lives: 3,
            score: 0,
            round: 1
        };

        // 敵の設定
        const enemyRows = 5;
        const enemyCols = 11;
        const enemyWidth = 40;
        const enemyHeight = 30;
        const enemyPadding = 20;
        const enemyOffsetTop = 50;
        const enemyOffsetLeft = 50;
        let enemies = [];
        let enemyDirection = 1; // 1: 右, -1: 左
        let enemySpeed = 1;

        // UFOの設定
        const ufos = [];
        const ufoSpeed = 2;

        // キー入力の管理
        const keys = {
            left: false,
            right: false,
            space: false
        };

        // 高スコアの管理
        let highScore = localStorage.getItem('highScore') || 0;

        // ゲームの初期化
        function init() {
            // 初期スコアとライフ
            player.score = 0;
            player.lives = 3;
            player.round = 1;

            // 初期敵の配置
            enemies = [];
            for(let row = 0; row < enemyRows; row++) {
                for(let col = 0; col < enemyCols; col++) {
                    const enemy = {
                        x: enemyOffsetLeft + col * (enemyWidth + enemyPadding),
                        y: enemyOffsetTop + row * (enemyHeight + enemyPadding),
                        width: enemyWidth,
                        height: enemyHeight,
                        type: 'standard',
                        alive: true
                    };
                    enemies.push(enemy);
                }
            }

            // 初期スピード
            enemySpeed = 1;

            // UFOの初期化
            ufos.length = 0;
        }

        // メインゲームループ
        function gameLoop() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            update();
            draw();
            if (player.lives <= 0 || enemiesReachedBottom()) {
                endGame();
            }
            gameInterval = requestAnimationFrame(gameLoop);
        }

        // 更新処理
        function update() {
            // プレイヤーの移動
            player.x += player.dx;
            // 境界チェック
            if (player.x < 0) player.x = 0;
            if (player.x + player.width > canvas.width) player.x = canvas.width - player.width;

            // プレイヤーの射撃
            if (keys.space && player.canShoot) {
                player.bullets.push({
                    x: player.x + player.width / 2 - 2.5,
                    y: player.y,
                    width: 5,
                    height: 10,
                    dy: -7
                });
                player.canShoot = false;
                setTimeout(() => {
                    player.canShoot = true;
                }, player.shootCooldown);
            }

            // 更新プレイヤーの弾
            player.bullets.forEach((bullet, index) => {
                bullet.y += bullet.dy;
                // 弾が画面外に出たら削除
                if (bullet.y + bullet.height < 0) {
                    player.bullets.splice(index, 1);
                }
            });

            // 敵の移動
            let shiftDown = false;
            enemies.forEach(enemy => {
                if (enemy.alive) {
                    enemy.x += enemySpeed * enemyDirection;
                    // 画面端に達したら下に移動し方向を反転
                    if (enemy.x + enemy.width > canvas.width - enemyOffsetLeft || enemy.x < enemyOffsetLeft) {
                        shiftDown = true;
                    }
                }
            });

            if (shiftDown) {
                enemyDirection *= -1;
                enemies.forEach(enemy => {
                    if (enemy.alive) {
                            enemy.y += enemyHeight;
                    }
                });
            }

            // 敵の自動射撃
            if (!enemyShootInterval) {
                enemyShootInterval = setInterval(enemyShoot, 1000);
            }

            // 更新敵の弾
            enemies.forEach(enemy => {
                if (enemy.alive && Math.random() < 0.001 * player.round) { // 射撃確率をラウンドに応じて増加
                    enemyBullets.push({
                        x: enemy.x + enemy.width / 2 - 2.5,
                        y: enemy.y + enemy.height,
                        width: 5,
                        height: 10,
                        dy: 4
                    });
                }
            });

            // 敵の弾の更新
            enemyBullets.forEach((bullet, index) => {
                bullet.y += bullet.dy;
                if (bullet.y > canvas.height) {
                    enemyBullets.splice(index, 1);
                }
            });

            // UFOの移動
            ufos.forEach((ufo, index) => {
                ufo.x += ufo.dy;
                if (ufo.x > canvas.width) {
                    ufos.splice(index, 1);
                }
            });

            // 障害物の追加や他の要素はここに追加できます

            // 衝突判定
            checkCollisions();

            // 更新UI
            updateUI();
        }

        // 描画処理
        function draw() {
            // プレイヤーの描画
            ctx.fillStyle = '#00f';
            ctx.fillRect(player.x, player.y, player.width, player.height);

            // プレイヤーの弾の描画
            ctx.fillStyle = '#fff';
            player.bullets.forEach(bullet => {
                ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
            });

            // 敵の描画
            ctx.fillStyle = '#0f0';
            enemies.forEach(enemy => {
                if (enemy.alive) {
                    ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
                }
            });

            // 敵の弾の描画
            ctx.fillStyle = '#f00';
            enemyBullets.forEach(bullet => {
                ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
            });

            // UFOの描画
            ctx.fillStyle = '#ff0';
            ufos.forEach(ufo => {
                ctx.fillRect(ufo.x, ufo.y, ufo.width, ufo.height);
            });
        }

        // 衝突判定
        function checkCollisions() {
            // プレイヤーの弾と敵の衝突
            player.bullets.forEach((bullet, bIndex) => {
                enemies.forEach((enemy, eIndex) => {
                    if (enemy.alive && isColliding(bullet, enemy)) {
                        enemy.alive = false;
                        player.score += 100; // 標準エイリアンの得点
                        player.bullets.splice(bIndex, 1);
                    }
                });
            });

            // 敵の弾とプレイヤーの衝突
            enemyBullets.forEach((bullet, bIndex) => {
                if (isColliding(bullet, player)) {
                    player.lives -= 1;
                    enemyBullets.splice(bIndex, 1);
                }
            });

            // 敵とプレイヤーの衝突
            enemies.forEach(enemy => {
                if (enemy.alive && isColliding(enemy, player)) {
                    player.lives = 0;
                }
            });

            // UFOとプレイヤーの衝突
            ufos.forEach((ufo, uIndex) => {
                if (isColliding(ufo, player)) {
                    player.lives = 0;
                }
            });

            // 全ての敵が倒された場合
            if (enemies.every(enemy => !enemy.alive)) {
                player.round += 1;
                init(); // 新しいラウンドの初期化
            }
        }

        // 衝突判定のヘルパー関数
        function isColliding(rect1, rect2) {
            return rect1.x < rect2.x + rect2.width &&
                   rect1.x + rect1.width > rect2.x &&
                   rect1.y < rect2.y + rect2.height &&
                   rect1.y + rect1.height > rect2.y;
        }

        // 敵の射撃処理
        let enemyBullets = [];
        function enemyShoot() {
            enemies.forEach(enemy => {
                if (enemy.alive && Math.random() < 0.01) { // 射撃確率
                    enemyBullets.push({
                        x: enemy.x + enemy.width / 2 - 2.5,
                        y: enemy.y + enemy.height,
                        width: 5,
                        height: 10,
                        dy: 4
                    });
                }
            });
        }

        // UFOの生成
        function spawnUFO() {
            const ufo = {
                x: -50,
                y: 50 + Math.random() * 100,
                width: 50,
                height: 20,
                dy: ufoSpeed
            };
            ufos.push(ufo);
        }

        // ランダムにUFOを生成
        function startUFOs() {
            ufoInterval = setInterval(spawnUFO, 10000); // 10秒ごとにUFO出現
        }

        // ランダムにUFOを生成し始める
        startUFOs();

        // 敵が画面下部に到達したかの判定
        function enemiesReachedBottom() {
            return enemies.some(enemy => enemy.alive && enemy.y + enemy.height >= player.y);
        }

        // UIの更新
        function updateUI() {
            scoreBoard.textContent = `スコア: ${player.score}`;
            lifeBoard.textContent = `ライフ: ${'♥'.repeat(player.lives)}`;
            roundBoard.textContent = `ラウンド: ${player.round}`;
        }

        // ゲームの開始
        function startGame() {
            gameState = 'playing';
            mainMenu.style.display = 'none';
            gameOverScreen.style.display = 'none';
            init();
            gameLoop();
        }

        // ゲームの終了
        function endGame() {
            gameState = 'gameover';
            cancelAnimationFrame(gameInterval);
            clearInterval(enemyShootInterval);
            clearInterval(ufoInterval);
            enemyShootInterval = null;
            ufoInterval = null;

            // ハイスコアの更新
            if (player.score > highScore) {
                highScore = player.score;
                localStorage.setItem('highScore', highScore);
            }

            // ゲームオーバー画面の表示
            finalScoreElem.textContent = `スコア: ${player.score}`;
            gameOverScreen.style.display = 'block';
        }

        // ゲームの再スタート
        function restartGame() {
            gameOverScreen.style.display = 'none';
            startGame();
        }

        // メインメニューに戻る
        function returnToMenu() {
            gameOverScreen.style.display = 'none';
            mainMenu.style.display = 'block';
        }

        // 高スコア表示(仮)
        function showHighScore() {
            alert(`ハイスコア: ${highScore}`);
        }

        // ゲームを閉じる(仮)
        function closeGame() {
            alert('ゲームを終了します。');
        }

        // キー入力のイベントリスナー
        document.addEventListener('keydown', (e) => {
            if (e.code === 'ArrowLeft' || e.code === 'KeyA') {
                keys.left = true;
                player.dx = -player.speed;
            }
            if (e.code === 'ArrowRight' || e.code === 'KeyD') {
                keys.right = true;
                player.dx = player.speed;
            }
            if (e.code === 'Space') {
                keys.space = true;
            }
        });

        document.addEventListener('keyup', (e) => {
            if (e.code === 'ArrowLeft' || e.code === 'KeyA') {
                keys.left = false;
                if (keys.right) {
                    player.dx = player.speed;
                } else {
                    player.dx = 0;
                }
            }
            if (e.code === 'ArrowRight' || e.code === 'KeyD') {
                keys.right = false;
                if (keys.left) {
                    player.dx = -player.speed;
                } else {
                    player.dx = 0;
                }
            }
            if (e.code === 'Space') {
                keys.space = false;
            }
        });

        // タッチ入力の管理(モバイル対応)
        let touchStartX = null;
        canvas.addEventListener('touchstart', (e) => {
            const touch = e.touches[0];
            touchStartX = touch.clientX;
        });

        canvas.addEventListener('touchmove', (e) => {
            if (touchStartX !== null) {
                const touch = e.touches[0];
                const deltaX = touch.clientX - touchStartX;
                player.x += deltaX * 0.1; // 移動量を調整
                touchStartX = touch.clientX;
                // 境界チェック
                if (player.x < 0) player.x = 0;
                if (player.x + player.width > canvas.width) player.x = canvas.width - player.width;
            }
        });

        canvas.addEventListener('touchend', (e) => {
            touchStartX = null;
        });

        // タッチによる射撃
        // 画面右下に射撃ボタンを配置
        const shootButton = document.createElement('button');
        shootButton.textContent = '射撃';
        shootButton.style.position = 'absolute';
        shootButton.style.bottom = '20px';
        shootButton.style.right = '20px';
        shootButton.style.padding = '10px 20px';
        shootButton.style.fontSize = '16px';
        shootButton.style.opacity = '0.5';
        shootButton.style.backgroundColor = '#fff';
        shootButton.style.border = 'none';
        shootButton.style.borderRadius = '5px';
        shootButton.style.cursor = 'pointer';
        shootButton.style.display = 'none'; // 初期は非表示

        document.body.appendChild(shootButton);

        // タッチデバイスの場合のみ表示
        if ('ontouchstart' in window || navigator.maxTouchPoints > 0) {
            shootButton.style.display = 'block';
            shootButton.addEventListener('touchstart', () => {
                keys.space = true;
            });
            shootButton.addEventListener('touchend', () => {
                keys.space = false;
            });
        }

        // ウィンドウのリサイズに対応
        window.addEventListener('resize', () => {
            // 必要に応じてキャンバスサイズを調整
        });

        // ゲームの開始
        init();
    </script>
</body>
</html>

コードの説明

1. HTML構造

  • メインメニュー: ゲーム開始、ハイスコア表示、終了ボタンを含む。

  • ゲームオーバー画面: スコア表示と再スタート、メインメニューに戻るボタンを含む。

  • スコア、ライフ、ラウンド表示: ゲーム中にリアルタイムで更新される情報。

  • ゲームキャンバス: ゲームの描画領域。

  • 射撃ボタン: モバイルデバイス向けに画面右下に配置。

2. CSSスタイル

  • リセットスタイル: マージンやパディングをリセット。

  • キャンバスとUI要素のスタイル: 中央配置、フォント設定、色設定など。

  • ボタンのスタイル: 見やすく操作しやすいデザイン。

3. JavaScript機能

  • ゲームの初期設定: プレイヤー、敵、弾、UFOの設定。

  • メインゲームループ (`gameLoop`): ゲームの更新と描画を繰り返す。

  • 更新処理 (`update`):

    • プレイヤーの移動と射撃。

    • 敵の移動と射撃。

    • UFOの生成と移動。

    • 衝突判定。

    • UIの更新。

  • 描画処理 (`draw`): プレイヤー、敵、弾、UFOをキャンバスに描画。

  • 衝突判定 (`checkCollisions`): 弾と敵、弾とプレイヤー、敵とプレイヤーの衝突を検出。

  • UIの更新 (`updateUI`): スコア、ライフ、ラウンドを表示。

  • イベントリスナー:

    • キーボード入力(左右移動、射撃)。

    • タッチ入力(モバイルデバイス向けのスライド移動と射撃ボタン)。

  • ゲームの状態管理: メインメニュー、プレイ中、ゲームオーバーの切り替え。

4. 拡張可能なポイント

  • 敵の種類: 標準エイリアン以外の強化エイリアンやUFOの種類を追加。

  • 障害物の追加: プレイヤーと敵の弾を遮る障害物を設置し、耐久力を持たせる。

  • スコアシステムの拡張: 特定の条件でスコアボーナスやライフ追加を実装。

  • パワーアップ: スペシャルウェポンやライフ増加などのパワーアップアイテムを追加。

  • マルチラウンドの管理: ラウンドが進むごとに敵の数や速度を調整。

  • 音声効果: 効果音やBGMを追加してゲームの雰囲気を向上。

この基本的な実装を基に、さらに詳細な機能やビジュアル、サウンドを追加することで、仕様に沿ったプロフェッショナルなインベーダーゲームを作成することができます。

使い方

このコードを、メモ帳を開いて"invador.html"と名前をつけて保存すると、HTMLファイルが出来上がりますので、これをクリックするとブラウザが開いて、ゲームが始まります。

上記のコードを元に、画面を縦長に修正した完成版のファイルはこちらです。ダウンロードして遊んでみてください。

このファイルをそのままサーバにあっぷしたものはこちら。以下をクリックするとダウンロードしなくても遊べます。

まとめ

このコードの文字数は、17300文字でした。
GPT-4oは、4000字程度の出力なので、o1-miniでは、かなり出力の分量が増えました。
それによって、コードのクオリティも上がったのかもしれません。

【重版決定】AIアプリをプログラミング不要で開発する書籍

GPTsを自分で作って世界に公開したい方はこちら!


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