見出し画像

chatGPTでノーコード開発 ブロック崩しを作成

chatGPT4でブロック崩しを作ってみました。何回かchatGPTと言葉(プロンプト)を交わすだけで一切コードは書かずにブロック崩しができました。
最初はJavaScriptで、その後Pythonに書き直してもらいました。


以下A.がプロンプト Q.がchatGPTの回答です。
A.ブロック崩しというゲームは何ですか
Q.ブロック崩し(Breakout)は、1976年にAtari社が開発したアーケードゲームです。このゲームの目的は、画面上の横に並んだブロックをすべて消すことです。プレイヤーは、画面下部の「パドル」を左右に動かして、跳ね返ってくる「ボール」を操作します。ボールがブロックに当たると、そのブロックが消え、プレイヤーはポイントを獲得します。ボールが画面下に落ちると、プレイヤーはライフを失います。プレイヤーのライフがすべてなくなるか、画面上のすべてのブロックを消してクリアするまでゲームが続きます。

ブロック崩しは、その後さまざまなバージョンや派生作品が登場し、ビデオゲームの歴史の中で重要な役割を果たしました。また、このゲームはプログラミングの教材や練習としても使われることがあります。
A.ブロック崩しのユースケースをplantUMLで記述して頂けますか。

Q.PlantUMLは、UML(Unified Modeling Language)を使ってシステムやソフトウェアの構造を描画するための言語です。ただし、ブロック崩しゲームのような具体的なゲームのユースケースを表現するのには、テキストベースのPlantUMLよりも、実際のソースコードやグラフィックスを使った説明の方が適切かもしれません。

それでも、PlantUMLを使ってブロック崩しの基本的なユースケースを表現することができます。以下に例を示します。

@startuml
left to right direction

actor Player

usecase "Move Paddle" as UC1
usecase "Bounce Ball" as UC2
usecase "Break Blocks" as UC3
usecase "Earn Points" as UC4
usecase "Lose Life" as UC5
usecase "Clear Level" as UC6

Player --> UC1
Player --> UC2
Player --> UC3
Player --> UC4
Player --> UC5
Player --> UC6
@enduml


この図では、ブロック崩しの基本的なユースケースが示されています。プレイヤーはパドルを動かし(UC1)、ボールを跳ね返す(UC2)、ブロックを壊す(UC3)、ポイントを獲得する(UC4)、ライフを失う(UC5)、そしてレベルをクリアする(UC6)ことができます。ただし、これはあくまで基本的なユースケースであり、実際のゲームではさらに詳細な要素が含まれることがあります。

A.上記を元にシーケンス図をPlantUMLで記述して頂けますか。

Q.ブロック崩しのシーケンス図をPlantUMLで記述することができます。以下に、ゲームの基本的なシーケンスを示す例を提供します。

@startuml
participant Player as P
participant Paddle as Pa
participant Ball as B
participant Block as Bl
participant GameLogic as GL

P -> Pa : Move Paddle
P -> B : Bounce Ball
B -> Bl : Collide with Block
Bl -> GL : Block Destroyed
GL -> P : Update Score

P -> B : Ball Missed
GL -> P : Lose Life

GL -> P : Clear Level

@enduml

このシーケンス図では、ブロック崩しゲームの基本的なフローが示されています。プレイヤー(Player)はパドル(Paddle)を動かし、ボール(Ball)を跳ね返します。ボールがブロック(Block)と衝突すると、ブロックが破壊され、ゲームロジック(GameLogic)がプレイヤーにスコアを更新するよう通知します。

もしボールがパドルによってキャッチされずに画面下に落ちると、ゲームロジックはプレイヤーにライフを失うよう通知します。また、すべてのブロックが破壊されると、ゲームロジックはプレイヤーにレベルクリアを通知します。

このシーケンス図はあくまで基本的なフローを示す例です。実際のゲームでは、より詳細な要素やインタラクションが含まれることがあります。また、ゲームロジックをさらに細かく表現するために、状態遷移図やクラス図を追加することもできます。

A.上記の状態遷移図をPlantUMLで記述頂けますか
Q.ブロック崩しゲームの状態遷移図をPlantUMLで記述することができます。以下に、ゲームの基本的な状態を示す例を提供します。

@startuml
[*] --> StartGame

state StartGame {
  [*] --> MainMenu
  MainMenu --> Play : Start Playing
}

state Play {
  [*] --> GameRunning
  GameRunning --> GamePaused : Pause Game
  GamePaused --> GameRunning : Resume Game
  GameRunning --> GameOver : Lose All Lives
  GameRunning --> LevelCleared : Clear Level
}

state GameOver {
  GameOver --> MainMenu : Restart
}

state LevelCleared {
  LevelCleared --> NextLevel : Advance to Next Level
  LevelCleared --> MainMenu : Restart
}

state NextLevel {
  [*] --> GameRunning : Start Next Level
}

@enduml

この状態遷移図では、ブロック崩しゲームの基本的な状態が示されています。ゲームは「StartGame」状態から始まり、メインメニュー(MainMenu)に遷移します。プレイヤーがゲームを開始すると、「Play」状態に入り、ゲームが実行中(GameRunning)となります。プレイヤーはゲームを一時停止(GamePaused)したり、再開(GameRunning)したりできます。

すべてのライフを失うと、「GameOver」状態に遷移し、プレイヤーはメインメニューに戻ってゲームをやり直すことができます。また、プレイヤーがレベルをクリアすると、「LevelCleared」状態に遷移し、次のレベルに進むか、メインメニューに戻ってゲームを再開することができます。

この状態遷移図はあくまで基本的な状態を示す例です。実際のゲームでは、より詳細な要素や状態が含まれることがあります。また、状態遷移図に加えて、シーケンス図やクラス図を使用することで、ゲームの構造や動作をさらに理解しやすくなります。


A.上記を元にクラス図をplantUMLで記述頂けますか

Q.ブロック崩しゲームのクラス図をPlantUMLで記述することができます。以下に、ゲームの基本的なクラスを示す例を提供します。

@startuml
class Game {
  -player: Player
  -paddle: Paddle
  -ball: Ball
  -blocks: List<Block>
  -gameState: GameState

  +startGame(): void
  +pauseGame(): void
  +resumeGame(): void
  +update(): void
}

class Player {
  -lives: int
  -score: int
  +loseLife(): void
  +addScore(points: int): void
}

class Paddle {
  -position: Point
  -velocity: Vector
  +move(deltaTime: float): void
}

class Ball {
  -position: Point
  -velocity: Vector
  +bounce(): void
  +move(deltaTime: float): void
}

class Block {
  -position: Point
  -size: Dimension
  -hitPoints: int
  +collideWithBall(ball: Ball): void
  +isDestroyed(): boolean
}

enum GameState {
  MainMenu,
  GameRunning,
  GamePaused,
  GameOver,
  LevelCleared
}

Game *-- Player
Game *-- Paddle
Game *-- Ball
Game *-- "1..*" Block
@enduml

このクラス図では、ブロック崩しゲームの基本的なクラスが示されています。Gameクラスは、プレイヤー、パドル、ボール、ブロック、およびゲーム状態(GameState)を管理します。Playerクラスは、プレイヤーのライフとスコアを管理します。PaddleBallクラスは、それぞれの位置と速度を管理します。Blockクラスは、ブロックの位置、サイズ、および耐久性(hitPoints)を管理します。

このクラス図はあくまで基本的なクラスを示す例です。実際のゲームでは、より詳細な要素やクラスが含まれることがあります。シーケンス図、状態遷移図、クラス図を組み合わせることで、ゲームの構造や動作を理解しやすくなります。また、実装に応じて、クラス図を拡張して追加のコンポーネントや関連を表現することができます。

A.あなたはプログラマです。上記を元にhtmlファイル1つでブロック崩しを実装して頂けますか。カーソルキーの左右でパドルを動かすようにして頂けますか。

Q.HTMLファイル1つでブロック崩しゲームを作成するために、HTMLの<canvas>要素とJavaScriptを使用して実装します。以下に、カーソルキーの左右でパドルを操作できる簡単なブロック崩しゲームのコードを示します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Game</title>
    <style>
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const paddleWidth = 75;
        const paddleHeight = 10;
        const paddleY = canvas.height - paddleHeight;
        let paddleX = (canvas.width - paddleWidth) / 2;

        let rightPressed = false;
        let leftPressed = false;

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

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

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

        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;
            }
        }

        setInterval(draw, 10);
    </script>
</body>
</html>

このコードは、カーソルキーの左右でパドルを動かす基本的な機能が実装されたブロック崩しゲームです。ただし、ボールやブロックがまだ実装されていません。実際のゲームにするためには、ボールの動きや衝突判定、ブロックの生成と破壊などの機能を追加する必要があります。
A.ブロック崩しに足りていない機能をコードに追加頂けますか

Q.以下に、ボール、衝突判定、ブロックの生成と破壊などの機能が追加されたブロック崩しゲームのコードを示します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Game</title>
    <style>
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const paddleWidth = 75;
        const paddleHeight = 10;
        const paddleY = canvas.height - paddleHeight;
        let paddleX = (canvas.width - paddleWidth) / 2;

        let rightPressed = false;
        let leftPressed = false;

        const ballRadius = 10;
        let ballX = canvas.width / 2;
        let ballY = canvas.height - 30;
        let ballSpeedX = 2;
        let ballSpeedY = -2;

        const brickRowCount = 3;
        const brickColumnCount = 5;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 30;
        const brickOffsetLeft = 30;
        const bricks = [];

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

        function drawBall() {
            ctx.beginPath();
            ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawBricks() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    if (bricks[c][r].status == 1) {
                        let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
                        let 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 = "#fff";
                        ctx.fill();
                        ctx.closePath();
                    }
                }
            }
        }

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

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

            if (ballX + ballSpeedX < ballRadius || ballX + ballSpeedX > canvas.width - ballRadius) {
                ballSpeedX = -ballSpeedX;
            }

            if (ballY + ballSpeedY < ballRadius) {
                ballSpeedY = -ballSpeedY;
            } else if (ballY + ballSpeedY > canvas.height - ballRadius) {
                if (ballX > paddleX && ballX < paddleX + paddleWidth) {
                    ballSpeedY = -ballSpeedY;
                } else {
                    // Game Over
                    ballX = canvas.width / 2;
                    ballY = canvas.height - 30;
                    ballSpeedX = 2;
                    ballSpeedY = -2;
                    paddleX = (canvas.width - paddleWidth) / 2;
                }
            }

            ballX += ballSpeedX;
            ballY += ballSpeedY;

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

        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;
            }
        }

        setInterval(draw, 10);
    </script>
</body>
</html>

このコードは、ボールの衝突判定、ブロックの生成と破壊などの機能が追加されたブロック崩しゲームです。collisionDetection関数でブロックとボールの衝突判定を行い、衝突があった場合、ボールの反射とブロックの破壊を行います。また、ゲームオーバー時にボールとパドルの位置をリセットしています。

このコードを使用して、ブラウザでブロック崩しゲームをプレイできます。ただし、現在の実装では、すべてのブロックが破壊された場合やゲームオーバー時の処理が簡素化されています。以下に、すべてのブロックが破壊された場合の処理とゲームオーバー時のメッセージ表示を追加したコードを示します。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Game</title>
    <style>
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const paddleWidth = 75;
        const paddleHeight = 10;
        const paddleY = canvas.height - paddleHeight;
        let paddleX = (canvas.width - paddleWidth) / 2;

        let rightPressed = false;
        let leftPressed = false;

        const ballRadius = 10;
        let ballX = canvas.width / 2;
        let ballY = canvas.height - 30;
        let ballSpeedX = 2;
        let ballSpeedY = -2;

        const brickRowCount = 3;
        const brickColumnCount = 5;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 30;
        const brickOffsetLeft = 30;
        const bricks = [];
        let bricksLeft = brickRowCount * brickColumnCount;

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

        function drawBall() {
            ctx.beginPath();
            ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawBricks() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    if (bricks[c][r].status == 1) {
                        let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
                        let 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 = "#fff";
                        ctx.fill();
                        ctx.closePath();
                    }
                }
            }
        }

        function collisionDetection() {
            for (let c = 0; c < brickColumnCount; c++)
                for (let r = 0; r < brickRowCount; r++) {
                    let b = bricks[c][r];
                    if (b.status == 1) {
                        if (ballX > b.x && ballX < b.x + brickWidth && ballY > b.y && ballY < b.y + brickHeight) {
                            ballSpeedY = -ballSpeedY;
                            b.status = 0;
                            bricksLeft--;
                            if (bricksLeft == 0) {
                                alert("Congratulations! You've cleared all the bricks!");
                                document.location.reload();
                            }
                        }
                    }
                }
            }
        }

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

            if (ballX + ballSpeedX < ballRadius || ballX + ballSpeedX > canvas.width - ballRadius) {
                ballSpeedX = -ballSpeedX;
            }

            if (ballY + ballSpeedY < ballRadius) {
                ballSpeedY = -ballSpeedY;
            } else if (ballY + ballSpeedY > canvas.height - ballRadius) {
                if (ballX > paddleX && ballX < paddleX + paddleWidth) {
                    ballSpeedY = -ballSpeedY;
                } else {
                    // Game Over
                    alert("Game Over! Try again.");
                    document.location.reload();
                }
            }

            ballX += ballSpeedX;
            ballY += ballSpeedY;

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

        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;
            }
        }

        setInterval(draw, 10);
    </script>
</body>
</html>

このコードでは、すべてのブロックが破壊された場合にアラートで勝利メッセージが表示されるようになっており、ゲームオーバー時には、アラートでゲームオーバーメッセージが表示されるようになっています。どちらの場合も、メッセージを閉じるとゲームがリロードされ、再びプレイできます。

A.画面が真っ黒で何も表示されませでした。

Q.申し訳ありません。ご指摘いただいた問題を確認しました。以前のコードは分割されていたため、エラーが発生していました。以下に、改善された完全なHTMLファイルを示します。これをコピーして新しいHTMLファイルに貼り付け、ブラウザで開いてください。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Game</title>
    <style>
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const paddleWidth = 75;
        const paddleHeight = 10;
        const paddleY = canvas.height - paddleHeight;
        let paddleX = (canvas.width - paddleWidth) / 2;

        let rightPressed = false;
        let leftPressed = false;

        const ballRadius = 10;
        let ballX = canvas.width / 2;
        let ballY = canvas.height - 30;
        let ballSpeedX = 2;
        let ballSpeedY = -2;

        const brickRowCount = 3;
        const brickColumnCount = 5;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 30;
        const brickOffsetLeft = 30;
        const bricks = [];
        let bricksLeft = brickRowCount * brickColumnCount;

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

        function drawBall() {
            ctx.beginPath();
            ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawBricks() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    if (bricks[c][r].status == 1) {
                        let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
                        let 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 = "#fff";
                        ctx.fill();
                        ctx.closePath();
                    }
                }
            }
        }

        function collisionDetection() {
            for (let c = 0; c < brickColumnCount; c++) {
               
                for (let r = 0; r < brickRowCount; r++) {
                    let b = bricks[c][r];
                    if (b.status == 1) {
                        if (ballX > b.x && ballX < b.x + brickWidth && ballY > b.y && ballY < b.y + brickHeight) {
                            ballSpeedY = -ballSpeedY;
                            b.status = 0;
                            bricksLeft--;
                            if (bricksLeft == 0) {
                                alert("Congratulations! You've cleared all the bricks!");
                                document.location.reload();
                            }
                        }
                    }
                }
            }
        }

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

            if (ballX + ballSpeedX < ballRadius || ballX + ballSpeedX > canvas.width - ballRadius) {
                ballSpeedX = -ballSpeedX;
            }

            if (ballY + ballSpeedY < ballRadius) {
                ballSpeedY = -ballSpeedY;
            } else if (ballY + ballSpeedY > canvas.height - ballRadius) {
                if (ballX > paddleX && ballX < paddleX + paddleWidth) {
                    ballSpeedY = -ballSpeedY;
                } else {
                    // Game Over
                    alert("Game Over! Try again.");
                    document.location.reload();
                }
            }

            ballX += ballSpeedX;
            ballY += ballSpeedY;

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

        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;
            }
        }

        setInterval(draw, 10);
    </script>
</body>
</html>

このコードを使用してブロック崩しゲームを実行すると、パドル、ボール、ブロックが表示され、ゲームが開始されます。左右のキーでパドルを操作し、すべてのブロックを消すか、ボールが画面下端に触れるとゲームが終了します。勝利時とゲームオーバー時には、それぞれのアラートメッセージが表示されます。
A.ボールが下に落ちた時の判定がおかしいようです。ボールが床に触れてから完全に隠れるまで何度もアラートが表示されます

Q.すみません、ミスがありました。ボールが床に触れた時の判定を修正しました。以下のコードでは、ボールが床に触れた瞬間に1回だけアラートが表示されるようになっています。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Game</title>
    <style>
        canvas {
            display: block;
            margin: 0 auto;
            background-color: #000;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="480" height="320"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        const paddleWidth = 75;
        const paddleHeight = 10;
        const paddleY = canvas.height - paddleHeight;
        let paddleX = (canvas.width - paddleWidth) / 2;

        let rightPressed = false;
        let leftPressed = false;

        const ballRadius = 10;
        let ballX = canvas.width / 2;
        let ballY = canvas.height - 30;
        let ballSpeedX = 2;
        let ballSpeedY = -2;

        const brickRowCount = 3;
        const brickColumnCount = 5;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 30;
        const brickOffsetLeft = 30;
        const bricks = [];
        let bricksLeft = brickRowCount * brickColumnCount;

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

        function drawBall() {
            ctx.beginPath();
            ctx.arc(ballX, ballY, ballRadius, 0, Math.PI * 2);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = "#fff";
            ctx.fill();
            ctx.closePath();
        }

        function drawBricks() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    if (bricks[c][r].status == 1) {
                        let brickX = (c * (brickWidth + brickPadding)) + brickOffsetLeft;
                        let 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 = "#fff";
                        ctx.fill();
                        ctx.closePath();
                    }
                }
            }
        }

        function collisionDetection() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    let b = bricks[c][r];
                    if (b.status == 1) {
                        if (ballX > b.x && ballX < b.x + brickWidth && ballY > b.y && ballY < b.y + brickHeight) {
                            ballSpeedY = -ballSpeedY;
                            b.status = 0;
                            bricksLeft--;
                            if (bricksLeft == 0) {
                                alert("Congratulations! You've cleared all the bricks!");
                                document.location.reload();
                            }
                        }
                    }
                }
            }
        }

        function gameOver() {
            alert("Game Over! Try again.");
            document.location.reload();
        }

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

            if (ballX + ballSpeedX < ballRadius || ballX + ballSpeedX > canvas.width - ballRadius) {
                ballSpeedX = -ballSpeedX;
            }

            if (ballY + ballSpeedY < ballRadius) {
                ballSpeedY = -ballSpeedY;
            } else if (ballY + ballSpeedY > canvas.height - ballRadius) {
                if (ballX > paddleX && ballX < paddleX + paddleWidth) {
                    ballSpeedY = -ballSpeedY;
                } else {
                    // Game Over
                    clearInterval(gameInterval);
                    setTimeout(gameOver, 10);
                }
            }

            ballX += ballSpeedX;
            ballY += ballSpeedY;

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

        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;
            }
        }

        const gameInterval = setInterval(draw, 10);
    </script>
</body>
</html>

この修正されたコードでは、ボールが床に触れた瞬間に1回だけゲームオーバーのアラートが表示されます。gameInterval をクリアし、ゲームオーバー関数を setTimeout を使って呼び出しています。これにより、アラートが繰り返し表示される問題が解決されます。


(注記)完成しました

続き


A.このプログラムをpythonで書けますでしょうか
Q.Pythonでブロック崩しゲームを作成するためには、Pygameというライブラリを使用します。まず、Pygameをインストールしてください。

pip install pygame



その後、以下のPythonコードでブロック崩しゲームを実装できます。

import pygame
import sys

pygame.init()

# 画面設定
width, height = 480, 320
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Breakout Game')

# カラー設定
white = (255, 255, 255)
black = (0, 0, 0)

# パドル設定
paddle_width, paddle_height = 75, 10
paddle_x, paddle_y = (width - paddle_width) // 2, height - paddle_height
paddle_speed = 7

# ボール設定
ball_radius = 10
ball_x, ball_y = width // 2, height - 30
ball_speed_x, ball_speed_y = 2, -2

# ブロック設定
brick_rows, brick_columns = 3, 5
brick_width, brick_height = 75, 20
brick_padding = 10
brick_offset_top, brick_offset_left = 30, 30
bricks = [[1] * brick_rows for _ in range(brick_columns)]
bricks_left = brick_rows * brick_columns

clock = pygame.time.Clock()

def draw_paddle():
    pygame.draw.rect(screen, white, (paddle_x, paddle_y, paddle_width, paddle_height))

def draw_ball():
    pygame.draw.circle(screen, white, (ball_x, ball_y), ball_radius)

def draw_bricks():
    for c in range(brick_columns):
        for r in range(brick_rows):
            if bricks[c][r] == 1:
                brick_x = c * (brick_width + brick_padding) + brick_offset_left
                brick_y = r * (brick_height + brick_padding) + brick_offset_top
                pygame.draw.rect(screen, white, (brick_x, brick_y, brick_width, brick_height))

def collision_detection():
    global ball_speed_y, bricks_left
    for c in range(brick_columns):
        for r in range(brick_rows):
            if bricks[c][r] == 1:
                brick_x = c * (brick_width + brick_padding) + brick_offset_left
                brick_y = r * (brick_height + brick_padding) + brick_offset_top
                if ball_x > brick_x and ball_x < brick_x + brick_width and ball_y > brick_y and ball_y < brick_y + brick_height:
                    ball_speed_y = -ball_speed_y
                    bricks[c][r] = 0
                    bricks_left -= 1
                    if bricks_left == 0:
                        print("Congratulations! You've cleared all the bricks!")
                        pygame.quit()
                        sys.exit()

while True:
    screen.fill(black)
    draw_paddle()
    draw_ball()
    draw_bricks()
    collision_detection()

    ball_x += ball_speed_x
    ball_y += ball_speed_y

    if ball_x - ball_radius < 0 or ball_x + ball_radius > width:
        ball_speed_x = -ball_speed_x

    if ball_y - ball_radius < 0:
        ball_speed_y = -ball_speed_y
    elif ball_y + ball_radius > height:
        if paddle_x <= ball_x <= paddle_x + paddle_width:
            ball_speed_y = -ball_speed_y
        else:
            print("Game Over! Try again.")
            pygame.quit()
            sys.exit()

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        paddle_x -= paddle_speed
        if paddle_x < 0:
            paddle_x = 0
    if keys[pygame.K_RIGHT]:
        paddle_x += paddle_speed
        if paddle_x + paddle_width > width:
            paddle_x = width - paddle_width

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    pygame.display.flip()
    clock.tick(60)

(注記)こちらも問題なく動きました。



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