📝

Claude 3.5でインベーダーゲームを作った

に公開

生成AI(Claude 3.5)を使ってインベーダーゲームのプログラムを作ってもらいました。
追加の指示は2回だけである程度動くものができました。

完成したゲームのリンクは以下です。

完成したゲームのリンク

https://claude.site/artifacts/6486bc33-cd6b-415f-862b-2ac1732d5d46

指示したプロンプト

指示したプロンプトを順に並べます。

htmlのcanvasでスペースインベーダーを作って
ゲームオーバーしたらエンターキーでリスタートできるようにして
すべての敵を倒したらクリアにして

完成したプログラム

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>スペースインベーダー</title>
    <style>
        canvas {
            border: 2px solid black;
            display: block;
            margin: 0 auto;
            background-color: black;
        }
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="600" height="400"></canvas>

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

        // ゲーム状態を初期化する関数
        function resetGame() {
            // プレイヤーの設定
            player.x = canvas.width / 2 - 25;
            player.y = canvas.height - 50;

            // 敵の再初期化
            enemies.length = 0;
            initEnemies();

            // 弾のクリア
            bullets.length = 0;
            enemyBullets.length = 0;

            // ゲーム状態のリセット
            gameOver = false;
            gameClear = false;
            score = 0;

            // ゲームループの再開
            gameLoop();
        }

        // プレイヤーの設定
        const player = {
            x: canvas.width / 2 - 25,
            y: canvas.height - 50,
            width: 50,
            height: 20,
            speed: 5,
            color: 'green'
        };

        // 敵の設定
        const enemies = [];
        const enemyWidth = 40;
        const enemyHeight = 20;
        const enemyRows = 5;
        const enemyCols = 10;
        const enemyColor = 'red';

        // 弾の設定
        const bullets = [];
        const enemyBullets = [];

        // ゲーム状態
        let gameOver = false;
        let gameClear = false;
        let score = 0;

        // 敵の初期化
        function initEnemies() {
            for (let row = 0; row < enemyRows; row++) {
                for (let col = 0; col < enemyCols; col++) {
                    enemies.push({
                        x: col * (enemyWidth + 10) + 50,
                        y: row * (enemyHeight + 10) + 50,
                        width: enemyWidth,
                        height: enemyHeight,
                        speed: 1
                    });
                }
            }
        }

        // プレイヤーの描画
        function drawPlayer() {
            ctx.fillStyle = player.color;
            ctx.fillRect(player.x, player.y, player.width, player.height);
        }

        // 敵の描画
        function drawEnemies() {
            ctx.fillStyle = enemyColor;
            enemies.forEach(enemy => {
                ctx.fillRect(enemy.x, enemy.y, enemy.width, enemy.height);
            });
        }

        // 弾の描画
        function drawBullets() {
            ctx.fillStyle = 'white';
            bullets.forEach(bullet => {
                ctx.fillRect(bullet.x, bullet.y, 5, 10);
            });
            enemyBullets.forEach(bullet => {
                ctx.fillRect(bullet.x, bullet.y, 5, 10);
            });
        }

        // 敵の移動
        function moveEnemies() {
            let hitEdge = false;
            enemies.forEach(enemy => {
                enemy.x += enemy.speed;
                if (enemy.x + enemy.width > canvas.width || enemy.x < 0) {
                    hitEdge = true;
                }
            });

            if (hitEdge) {
                enemies.forEach(enemy => {
                    enemy.speed *= -1;
                    enemy.y += 20;
                });
            }
        }

        // 衝突判定
        function checkCollisions() {
            // プレイヤーの弾と敵の衝突
            bullets.forEach((bullet, bulletIndex) => {
                enemies.forEach((enemy, enemyIndex) => {
                    if (
                        bullet.x < enemy.x + enemy.width &&
                        bullet.x + 5 > enemy.x &&
                        bullet.y < enemy.y + enemy.height &&
                        bullet.y + 10 > enemy.y
                    ) {
                        bullets.splice(bulletIndex, 1);
                        enemies.splice(enemyIndex, 1);
                        score += 10;
                    }
                });
            });

            // すべての敵を倒したかチェック
            if (enemies.length === 0) {
                gameClear = true;
            }

            // 敵の弾とプレイヤーの衝突
            enemyBullets.forEach((bullet, bulletIndex) => {
                if (
                    bullet.x < player.x + player.width &&
                    bullet.x + 5 > player.x &&
                    bullet.y < player.y + player.height &&
                    bullet.y + 10 > player.y
                ) {
                    gameOver = true;
                }
            });

            // 敵がプレイヤーに到達
            enemies.forEach(enemy => {
                if (enemy.y + enemy.height > player.y) {
                    gameOver = true;
                }
            });
        }

        // 敵の弾発射
        function enemyShoot() {
            if (Math.random() < 0.02 && enemies.length > 0) {
                const randomEnemy = enemies[Math.floor(Math.random() * enemies.length)];
                enemyBullets.push({
                    x: randomEnemy.x + randomEnemy.width / 2,
                    y: randomEnemy.y + randomEnemy.height,
                    speed: 3
                });
            }
        }

        // ゲームループ
        function gameLoop() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            if (!gameOver && !gameClear) {
                drawPlayer();
                drawEnemies();
                drawBullets();
                moveEnemies();
                checkCollisions();
                enemyShoot();

                // 弾の移動
                bullets.forEach((bullet, index) => {
                    bullet.y -= 7;
                    if (bullet.y < 0) {
                        bullets.splice(index, 1);
                    }
                });

                enemyBullets.forEach((bullet, index) => {
                    bullet.y += bullet.speed;
                    if (bullet.y > canvas.height) {
                        enemyBullets.splice(index, 1);
                    }
                });

                // スコア表示
                ctx.fillStyle = 'white';
                ctx.font = '20px Arial';
                ctx.fillText(`スコア: ${score}`, 10, 30);

                requestAnimationFrame(gameLoop);
            } else if (gameOver) {
                // ゲームオーバー画面
                ctx.fillStyle = 'white';
                ctx.font = '40px Arial';
                ctx.fillText('ゲームオーバー', canvas.width / 2 - 120, canvas.height / 2);
                ctx.font = '20px Arial';
                ctx.fillText(`スコア: ${score}`, canvas.width / 2 - 50, canvas.height / 2 + 50);
                ctx.font = '15px Arial';
                ctx.fillText('Enterキーを押してリスタート', canvas.width / 2 - 100, canvas.height / 2 + 100);
            } else if (gameClear) {
                // ゲームクリア画面
                ctx.fillStyle = 'white';
                ctx.font = '40px Arial';
                ctx.fillText('ゲームクリア!', canvas.width / 2 - 120, canvas.height / 2);
                ctx.font = '20px Arial';
                ctx.fillText(`スコア: ${score}`, canvas.width / 2 - 50, canvas.height / 2 + 50);
                ctx.font = '15px Arial';
                ctx.fillText('Enterキーを押してリスタート', canvas.width / 2 - 100, canvas.height / 2 + 100);
            }
        }

        // キーボード入力
        document.addEventListener('keydown', (e) => {
            if (!gameOver && !gameClear) {
                if (e.key === 'ArrowLeft' && player.x > 0) {
                    player.x -= player.speed;
                }
                if (e.key === 'ArrowRight' && player.x < canvas.width - player.width) {
                    player.x += player.speed;
                }
                if (e.key === ' ') {
                    bullets.push({
                        x: player.x + player.width / 2 - 2.5,
                        y: player.y,
                        speed: 7
                    });
                }
            } else {
                // ゲームオーバーまたはゲームクリア時にEnterキーでリスタート
                if (e.key === 'Enter') {
                    resetGame();
                }
            }
        });

        // ゲームの初期化
        initEnemies();
        gameLoop();
    </script>
</body>
</html>

CodePenでも公開しています。
以下のリンクからどうぞ。

Discussion