🎮ArcadeLab

宇宙ブロック崩し

by AtomicOwl82
586 lines9.0 KB
▶ Play
```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>宇宙ブロック崩し</title>

<style>
    * {
        box-sizing: border-box;
    }

    html, body {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
    }

    body {
        background: #05051a;
        color: white;
        font-family: sans-serif;
        text-align: center;
    }

    h1 {
        margin: 6px 0;
        font-size: clamp(20px, 4vw, 28px);
    }

    #info {
        font-size: clamp(14px, 3vw, 18px);
        margin: 4px;
    }

    #game {
        background: linear-gradient(#08082b, #15154a);
        border: 3px solid white;
        display: block;
        margin: 0 auto;

        width: min(800px, calc(100vw - 20px));
        height: auto;
        aspect-ratio: 4 / 3;
    }

    #help {
        margin: 4px;
        font-size: clamp(12px, 2.5vw, 16px);
    }

    button {
        font-size: 16px;
        padding: 6px 16px;
        cursor: pointer;
    }
</style>
</head>

<body>

<h1>👽 宇宙ブロック崩し 🚀</h1>

<div id="info">
    ❤️ 残機: <span id="lives">3</span>
    
    🎁 復活: <span id="revive">0</span>
</div>

<canvas id="game" width="800" height="600"></canvas>

<p id="help">
    ← → キーでパドルを動かそう! 宇宙人の攻撃にも注意!
</p>

<button onclick="location.reload()">もう一度遊ぶ</button>

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

let paddle = {
    x: 350,
    y: 550,
    width: 100,
    height: 15,
    speed: 8
};

let balls = [
    {
        x: 400,
        y: 530,
        dx: 4,
        dy: -4,
        radius: 8
    }
];

let keys = {};

let lives = 3;
let revive = 0;

let gameOver = false;
let clear = false;

let alien = {
    x: 380,
    y: 40,
    width: 40,
    height: 30,
    dx: 2
};

let alienShots = [];

let blocks = [];

const rows = 5;
const cols = 10;

const blockWidth = 70;
const blockHeight = 25;
const blockGap = 7;

for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {

        blocks.push({
            x: 20 + c * (blockWidth + blockGap),
            y: 90 + r * (blockHeight + blockGap),
            width: blockWidth,
            height: blockHeight,
            alive: true
        });

    }
}

document.addEventListener("keydown", function(e) {

    keys[e.key] = true;

    if (
        e.key === "ArrowLeft" ||
        e.key === "ArrowRight"
    ) {
        e.preventDefault();
    }

});

document.addEventListener("keyup", function(e) {
    keys[e.key] = false;
});

function randomItem(ball) {

    let chance = Math.floor(Math.random() * 5);

    if (chance === 0) {

        balls.push({
            x: ball.x,
            y: ball.y,
            dx: -ball.dx,
            dy: ball.dy,
            radius: 8
        });

    }

    else if (chance === 1) {

        revive = 1;

        document.getElementById("revive").textContent = revive;

    }

    else if (chance === 2) {

        // 何もなし

    }

    else if (chance === 3) {

        ball.dx *= 1.7;
        ball.dy *= 1.7;

        setTimeout(function() {

            ball.dx *= 0.59;
            ball.dy *= 0.59;

        }, 5000);

    }

    else if (chance === 4) {

        ball.dx *= 0.6;
        ball.dy *= 0.6;

        setTimeout(function() {

            ball.dx *= 1.67;
            ball.dy *= 1.67;

        }, 10000);

    }
}

function loseBall(index) {

    if (balls.length > 1) {

        balls.splice(index, 1);

        return;
    }

    if (revive > 0) {

        revive = 0;

        document.getElementById("revive").textContent = revive;

        balls[0].x =
            paddle.x + paddle.width / 2;

        balls[0].y =
            paddle.y - 15;

        balls[0].dx = 4;
        balls[0].dy = -4;

        return;
    }

    lives--;

    document.getElementById("lives").textContent = lives;

    if (lives <= 0) {

        gameOver = true;

    }

    else {

        balls[0].x =
            paddle.x + paddle.width / 2;

        balls[0].y =
            paddle.y - 15;

        balls[0].dx = 4;
        balls[0].dy = -4;
    }
}

function update() {

    if (gameOver || clear) {
        return;
    }

    // パドル

    if (keys["ArrowLeft"]) {
        paddle.x -= paddle.speed;
    }

    if (keys["ArrowRight"]) {
        paddle.x += paddle.speed;
    }

    if (paddle.x < 0) {
        paddle.x = 0;
    }

    if (
        paddle.x + paddle.width >
        canvas.width
    ) {

        paddle.x =
            canvas.width - paddle.width;

    }

    // 宇宙人

    alien.x += alien.dx;

    if (
        alien.x < 0 ||
        alien.x + alien.width >
        canvas.width
    ) {

        alien.dx *= -1;

    }

    // 宇宙人の攻撃

    if (Math.random() < 0.015) {

        alienShots.push({

            x:
                alien.x +
                alien.width / 2,

            y:
                alien.y +
                alien.height,

            dy: 5

        });

    }

    for (
        let i = alienShots.length - 1;
        i >= 0;
        i--
    ) {

        let shot = alienShots[i];

        shot.y += shot.dy;

        if (
            shot.x > paddle.x &&
            shot.x < paddle.x + paddle.width &&
            shot.y > paddle.y &&
            shot.y < paddle.y + paddle.height
        ) {

            alienShots.splice(i, 1);

            lives--;

            document.getElementById("lives")
                .textContent = lives;

            if (lives <= 0) {
                gameOver = true;
            }

            continue;
        }

        if (shot.y > canvas.height) {

            alienShots.splice(i, 1);

        }
    }

    // ボール

    for (
        let i = balls.length - 1;
        i >= 0;
        i--
    ) {

        let ball = balls[i];

        ball.x += ball.dx;
        ball.y += ball.dy;

        // 左右の壁

        if (
            ball.x - ball.radius < 0 ||
            ball.x + ball.radius >
            canvas.width
        ) {

            ball.dx *= -1;

        }

        // 上の壁

        if (ball.y - ball.radius < 0) {

            ball.dy *= -1;

        }

        // パドル

        if (
            ball.y + ball.radius >= paddle.y &&
            ball.y + ball.radius <=
                paddle.y + paddle.height &&
            ball.x >= paddle.x &&
            ball.x <=
                paddle.x + paddle.width &&
            ball.dy > 0
        ) {

            ball.dy =
                -Math.abs(ball.dy);

            let hitPosition =
                (ball.x - paddle.x) /
                paddle.width - 0.5;

            ball.dx =
                hitPosition * 10;

        }

        // ボールが落ちた

        if (
            ball.y - ball.radius >
            canvas.height
        ) {

            loseBall(i);

            continue;
        }

        // ブロック

        for (let block of blocks) {

            if (!block.alive) {
                continue;
            }

            if (
                ball.x + ball.radius >
                    block.x &&
                ball.x - ball.radius <
                    block.x + block.width &&
                ball.y + ball.radius >
                    block.y &&
                ball.y - ball.radius <
                    block.y + block.height
            ) {

                block.alive = false;

                ball.dy *= -1;

                randomItem(ball);

                break;
            }
        }
    }

    // 全ブロック破壊

    if (
        blocks.every(
            block => !block.alive
        )
    ) {

        clear = true;

    }
}

function draw() {

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

    // 星

    ctx.fillStyle = "white";

    for (let i = 0; i < 50; i++) {

        let x =
            (i * 157) %
            canvas.width;

        let y =
            (i * 83) %
            canvas.height;

        ctx.fillRect(
            x,
            y,
            2,
            2
        );

    }

    // ブロック

    for (let block of blocks) {

        if (!block.alive) {
            continue;
        }

        ctx.fillStyle =
            "#39d9ff";

        ctx.fillRect(
            block.x,
            block.y,
            block.width,
            block.height
        );

    }

    // パドル

    ctx.fillStyle = "white";

    ctx.fillRect(
        paddle.x,
        paddle.y,
        paddle.width,
        paddle.height
    );

    // ボール

    for (let ball of balls) {

        ctx.beginPath();

        ctx.arc(
            ball.x,
            ball.y,
            ball.radius,
            0,
            Math.PI * 2
        );

        ctx.fillStyle =
            "#ffff00";

        ctx.fill();

        ctx.closePath();

    }

    // 宇宙人

    ctx.fillStyle =
        "#72ff72";

    ctx.fillRect(
        alien.x,
        alien.y,
        alien.width,
        alien.height
    );

    ctx.fillStyle = "black";

    ctx.fillRect(
```

Game Source: 宇宙ブロック崩し

Creator: AtomicOwl82

Libraries: none

Complexity: complex (586 lines, 9.0 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-atomicowl82" to link back to the original. Then publish at arcadelab.ai/publish.