前端技术搭建弹珠小游戏(内附源码)


✨ 写在前面

上周我们实通过前端基础实现了小人逃脱,当然很多伙伴再评论区提出了想法,后续我们会考虑实现的,今天还是继续按照我们原定的节奏来带领大家完成一个弹珠游戏,功能也比较简单简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循序渐进从简单到复杂的过程,后续会带领大家用前端实现翻卡片、扫雷、贪吃蛇等有趣的小游戏,纯前端语言实现,都会陆续带给大家。欢迎大家订阅我们这份前端小游戏的专栏。


✨ 功能介绍

在这里插入图片描述

当玩家进入游戏页面后,可以看到一个有趣的弹珠游戏。玩家需要使用左右箭头键控制下方的挡板,以便接住从上方掉落的小球。如果球触碰到下方的边界线,游戏就结束了。玩家的目标是尽可能多地接住小球,并通过撞击顶部的砖块来获得高分。每次成功接住小球都会获得10分,每次碰撞砖块都会获得20分。玩家可以通过页面上的得分区域实时查看自己的得分。如果玩家成功消除所有的砖块,就会获得游戏胜利,并获得最终得分。当然你也可以通过修改游戏的参数来控制难度等级!


✨ 页面搭建

创建文件

首先呢我们创建我们的HTML文件,这里我就直接命名为 弹珠游戏.html 了,大家可以随意命名, 文件创建生成后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码结构,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 ! 我们敲击回车直接就会给我们生成基础版本的前端代码结构。

在这里插入图片描述

文档声明和编码设置: 在HTML文档的头部,使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。下面我就开始搭建我们的DOM结构了!

DOM结构搭建

  1. <h1>弹珠游戏</h1>:这是一个页面标题,显示在页面的最上方,用于告诉用户这是一个弹珠游戏页面。
  2. <div id="board">...</div>:这是一个游戏主板区域,游戏中所有的元素都会在这个区域内展示。其中包括了一个挡板、一个弹珠和一个砖块容器。
  3. <div id="paddle"></div>:这是一个挡板,用于接住从上方掉落的小球。玩家可以通过左右箭头键控制挡板的移动。
  4. <div id="ball"></div>:这是一个弹珠,会从上方掉落到挡板下方。玩家需要使用挡板接住弹珠,否则游戏就会结束。
  5. <div id="brick-container"></div>:这是一个砖块容器,用于展示顶部的砖块。玩家需要通过撞击顶部的砖块来获得高分。
  6. <div id="score">0</div>:这是一个得分区域,用于实时展示玩家的得分。当玩家成功接住小球或者碰撞砖块时,得分会随之增加,并在这个区域中实时更新。
<h1>弹珠游戏</h1>
<div id="board">
  <div id="paddle"></div>
  <div id="ball"></div>
  <div id="brick-container"></div>
</div>
<div id="score">0</div>

在这里插入图片描述


✨ 样式设置

我们看到了上面的的DOM已经搭建好了,但是很显然样式比较随意了,我们简单的来配置一下样式吧,其实我们本专栏也是想带领大家掌握一些逻辑所以样式方面我们就一切从简;这段CSS代码定义了弹珠游戏中各个元素的样式:

  • #board 定义了游戏面板的样式,包括宽度、高度、边框、相对定位和水平居中对齐。
  • #paddle 定义了球拍的样式,包括宽度、高度、背景颜色、绝对定位和贴着游戏面板底部。
  • #ball 定义了球的样式,包括宽度、高度、背景颜色和绝对定位。
  • .brick 定义了砖块的样式,包括宽度、高度、背景颜色、边框和绝对定位。
  • #brick-container 定义了砖块容器的样式,包括与游戏面板顶部的距离。
  • #score 定义了分数的样式,包括字体大小和居中对齐。
<style>
    #board {
        width: 480px;
        height: 320px;
        border: 1px solid black;
        position: relative;
        margin: 0 auto;
    }

    #paddle {
        width: 80px;
        height: 10px;
        background-color: black;
        position: absolute;
        bottom: 0;
    }

    #ball {
        width: 10px;
        height: 10px;
        background-color: red;
        position: absolute;
    }

    .brick {
        width: 75px;
        height: 20px;
        background-color: blue;
        border: 1px solid black;
        position: absolute;
    }

    #brick-container {
        margin-top: 30px;
    }

    #score {
        font-size: 24px;
        text-align: center;
    }
</style>

在这里插入图片描述

✨ 逻辑部分

上面我们搭建了基本的样式,下面呢我们就通过js代码,实现我们游戏的功能吧;我们首先呢 定义了一些变量,包括游戏板(board)、球拍(paddle)、弹珠(ball)、砖块数量(brickCount)、球拍的初始位置(paddleX)、弹珠的初始位置(ballX和ballY)等。定义了砖块的宽度、高度、边距以及偏移量等参数,以及砖块的行数(brickRowCount)和列数(brickColumnCount)。初始化了游戏板、球拍和弹珠的位置,并将球拍放在游戏板的底部,将弹珠放在游戏板的中央。初始化了砖块,通过循环创建砖块,并设置砖块的位置和样式。初始化了键盘事件,用于控制球拍的移动。开始游戏循环,每20毫秒执行一次update函数,用于更新游戏状态。下面我们就来编写update等几个函数;

let board, paddle, ball, brickCount;
let paddleX, ballX, ballY;
let brickWidth = 75, brickHeight = 20, brickPadding = 10, brickOffsetTop = 30, brickOffsetLeft = 30;
let brickRowCount = 3, brickColumnCount = 5;
let x = 3, y = -3;
let leftPressed, rightPressed;
let score = 0; // 定义分数

let gameLoop; // 定义全局变量gameLoop

function startGame() {
    // 初始化分数为0
    score = 0;
    document.getElementById("score").innerHTML = score;

    // 初始化游戏板和弹球
    board = document.getElementById("board");
    paddle = document.getElementById("paddle");
    ball = document.getElementById("ball");
    paddleX = board.offsetWidth / 2 - paddle.offsetWidth / 2;
    ballX = board.offsetWidth / 2 - ball.offsetWidth / 2;
    ballY = board.offsetHeight / 2 - ball.offsetHeight / 2;
    ball.style.left = ballX + "px";
    ball.style.top = ballY + "px";

    // 初始化砖块
    const brickContainer = document.getElementById("brick-container");
    brickContainer.innerHTML = "";
    brickCount = 0;
    for (let i = 0; i < brickRowCount; i++) {
        for (let j = 0; j < brickColumnCount; j++) {
            const brick = document.createElement("div");
            brick.className = "brick";
            brick.style.left = j * (brickWidth + brickPadding) + brickOffsetLeft + "px";
            brick.style.top = i * (brickHeight + brickPadding) + brickOffsetTop + "px";
            brickContainer.appendChild(brick);
            brickCount++;
        }
    }

    // 初始化键盘事件
    leftPressed = false;
    rightPressed = false;
    document.addEventListener("keydown", keyDownHandler, false);
    document.addEventListener("keyup", keyUpHandler, false);

    // 开始
    gameLoop = setInterval(update, 20);
}

下面我们要编写的代码就是游戏的核心代码,定义了三个函数:keyDownHandlerkeyUpHandlerupdate,分别对应键盘按下、键盘松开以及游戏状态的更新。这些函数都在 startGame 函数中被调用,用于初始化游戏并启动游戏循环。

keyDownHandlerkeyUpHandler 函数监听键盘事件。当键盘按下时,会检测按下的键是否是左箭头或右箭头,如果是则将相应的标志变量(leftPressedrightPressed)设置为 true。当键盘松开时,同样会检测松开的键是否是左箭头或右箭头,如果是则将相应的标志变量设置为 false

update 函数是游戏循环中最重要的函数之一,用于更新游戏状态并检测碰撞。在每次更新时,会首先更新球的位置,并检测球是否与边界相撞。如果球碰到了左右边界,则将其速度反向;如果球碰到了上边界,则将其纵向速度反向。如果球碰到了底部,则游戏结束。

接下来,该函数将检测球是否与挡板相撞。如果球碰到了挡板,则将其纵向速度反向,并将分数加10分。然后会实时更新分数。该函数也会检测球是否与砖块相撞。如果球碰到了砖块,则将其纵向速度反向,并将相应的砖块从游戏区域中移除,并将分数加20分。同样会实时更新分数。如果所有砖块都被消除,则游戏结束,弹出一个提示框,显示获得的分数,并重新开始游戏。

function keyDownHandler(e) {
    if (e.keyCode === 37) {
        leftPressed = true;
    } else if (e.keyCode === 39) {
        rightPressed = true;
    }
}

function keyUpHandler(e) {
    if (e.keyCode === 37) {
        leftPressed = false;
    } else if (e.keyCode === 39) {
        rightPressed = false;
    }
}

function update() {
    // 更新球的位置
    ballX += x;
    ballY += y;
    ball.style.left = ballX + "px";
    ball.style.top = ballY + "px";

    // 判断球是否碰到边界
    if (ballX < 0 || ballX + ball.offsetWidth > board.offsetWidth) {
        x = -x;
    }
    if (ballY < 0) {
        y = -y;
    } else if (ballY + ball.offsetHeight > board.offsetHeight) {
        // 判断球是否碰到底部,游戏结束
        clearInterval(gameLoop);
        alert("游戏结束,你的得分是:" + score);
        startGame();
    }

    // 判断球是否碰到挡板
    if (ballY + ball.offsetHeight > board.offsetHeight - paddle.offsetHeight && ballX + ball.offsetWidth > paddleX && ballX < paddleX + paddle.offsetWidth) {
        y = -y;
        score += 10; // 碰到挡板加10分
        document.getElementById("score").innerHTML = score; // 实时更新分数
    }

    // 更新挡板位置
    if (leftPressed && paddleX > 0) {
        paddleX -= 5;
    } else if (rightPressed && paddleX + paddle.offsetWidth < board.offsetWidth) {
        paddleX += 5;
    }
    paddle.style.left = paddleX + "px";
    console.log(brickCount, 'hasdjhsdaf')
    // 判断球是否碰到砖块
    const bricks = document.getElementsByClassName("brick");
    for (let i = 0; i < bricks.length; i++) {
        const brick = bricks[i];
        if (ballY < brick.offsetTop + brickHeight && ballY + ball.offsetHeight > brick.offsetTop && ballX + ball.offsetWidth > brick.offsetLeft && ballX < brick.offsetLeft + brickWidth) {
            y = -y;
            brick.style.display = "none";
            brickCount--;
            score += 20; // 碰到砖块加20分
            document.getElementById("score").innerHTML = score; // 实时更新分数
            if (brickCount === 0) {
                clearInterval(gameLoop);
                alert("恭喜你赢得了游戏,你的得分是:" + score);
                startGame();
            }
        }
    }

}

startGame();

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #board {
            width: 480px;
            height: 320px;
            border: 1px solid black;
            position: relative;
            margin: 0 auto;
        }

        #paddle {
            width: 80px;
            height: 10px;
            background-color: black;
            position: absolute;
            bottom: 0;
        }

        #ball {
            width: 10px;
            height: 10px;
            background-color: red;
            position: absolute;
        }

        .brick {
            width: 75px;
            height: 20px;
            background-color: blue;
            border: 1px solid black;
            position: absolute;
        }

        #brick-container {
            margin-top: 30px;
        }

        #score {
            font-size: 24px;
            text-align: center;
        }
    </style>
</head>

<body>
    <h1>弹珠游戏</h1>
    <div id="board">
        <div id="paddle"></div>
        <div id="ball"></div>
        <div id="brick-container"></div>
    </div>
    <div id="score">0</div>
</body>

<script>
    let board, paddle, ball, brickCount;
    let paddleX, ballX, ballY;
    let brickWidth = 75, brickHeight = 20, brickPadding = 10, brickOffsetTop = 30, brickOffsetLeft = 30;
    let brickRowCount = 3, brickColumnCount = 5;
    let x = 3, y = -3;
    let leftPressed, rightPressed;
    let score = 0; // 定义分数

    let gameLoop; // 定义全局变量gameLoop

    function startGame() {
        // 初始化分数为0
        score = 0;
        document.getElementById("score").innerHTML = score;

        // 初始化游戏板和弹球
        board = document.getElementById("board");
        paddle = document.getElementById("paddle");
        ball = document.getElementById("ball");
        paddleX = board.offsetWidth / 2 - paddle.offsetWidth / 2;
        ballX = board.offsetWidth / 2 - ball.offsetWidth / 2;
        ballY = board.offsetHeight / 2 - ball.offsetHeight / 2;
        ball.style.left = ballX + "px";
        ball.style.top = ballY + "px";

        // 初始化砖块
        const brickContainer = document.getElementById("brick-container");
        brickContainer.innerHTML = "";
        brickCount = 0;
        for (let i = 0; i < brickRowCount; i++) {
            for (let j = 0; j < brickColumnCount; j++) {
                const brick = document.createElement("div");
                brick.className = "brick";
                brick.style.left = j * (brickWidth + brickPadding) + brickOffsetLeft + "px";
                brick.style.top = i * (brickHeight + brickPadding) + brickOffsetTop + "px";
                brickContainer.appendChild(brick);
                brickCount++;
            }
        }

        // 初始化键盘事件
        leftPressed = false;
        rightPressed = false;
        document.addEventListener("keydown", keyDownHandler, false);
        document.addEventListener("keyup", keyUpHandler, false);

        // 开始
        gameLoop = setInterval(update, 20);
    }

    function keyDownHandler(e) {
        if (e.keyCode === 37) {
            leftPressed = true;
        } else if (e.keyCode === 39) {
            rightPressed = true;
        }
    }

    function keyUpHandler(e) {
        if (e.keyCode === 37) {
            leftPressed = false;
        } else if (e.keyCode === 39) {
            rightPressed = false;
        }
    }

    function update() {
        // 更新球的位置
        ballX += x;
        ballY += y;
        ball.style.left = ballX + "px";
        ball.style.top = ballY + "px";

        // 判断球是否碰到边界
        if (ballX < 0 || ballX + ball.offsetWidth > board.offsetWidth) {
            x = -x;
        }
        if (ballY < 0) {
            y = -y;
        } else if (ballY + ball.offsetHeight > board.offsetHeight) {
            // 判断球是否碰到底部,游戏结束
            clearInterval(gameLoop);
            alert("游戏结束,你的得分是:" + score);
            startGame();
        }

        // 判断球是否碰到挡板
        if (ballY + ball.offsetHeight > board.offsetHeight - paddle.offsetHeight && ballX + ball.offsetWidth > paddleX && ballX < paddleX + paddle.offsetWidth) {
            y = -y;
            score += 10; // 碰到挡板加10分
            document.getElementById("score").innerHTML = score; // 实时更新分数
        }

        // 更新挡板位置
        if (leftPressed && paddleX > 0) {
            paddleX -= 5;
        } else if (rightPressed && paddleX + paddle.offsetWidth < board.offsetWidth) {
            paddleX += 5;
        }
        paddle.style.left = paddleX + "px";
        console.log(brickCount, 'hasdjhsdaf')
        // 判断球是否碰到砖块
        const bricks = document.getElementsByClassName("brick");
        for (let i = 0; i < bricks.length; i++) {
            const brick = bricks[i];
            if (ballY < brick.offsetTop + brickHeight && ballY + ball.offsetHeight > brick.offsetTop && ballX + ball.offsetWidth > brick.offsetLeft && ballX < brick.offsetLeft + brickWidth) {
                y = -y;
                brick.style.display = "none";
                brickCount--;
                score += 20; // 碰到砖块加20分
                document.getElementById("score").innerHTML = score; // 实时更新分数
                if (brickCount === 0) {
                    clearInterval(gameLoop);
                    alert("恭喜你赢得了游戏,你的得分是:" + score);
                    startGame();
                }
            }
        }

    }

    startGame();
</script>

</html>

本期推荐

《写作之光:自媒体写作方法与运营实践》从自媒体写作的基础知识讲起,结合自媒体创作者的实际运营经历,重点介绍了今日头条、知乎、小红书等平台的运营与变现方法,让读者系统地理解这些自媒体平台的创作技巧与变现思路。

在这里插入图片描述

原创不易,还希望各位大佬支持一下

textcolor{blue}{原创不易,还希望各位大佬支持一下}

原创不易,还希望各位大佬支持一下

👍

点赞,你的认可是我创作的动力!

textcolor{green}{点赞,你的认可是我创作的动力!}

点赞,你的认可是我创作的动力!

⭐️

收藏,你的青睐是我努力的方向!

textcolor{green}{收藏,你的青睐是我努力的方向!}

收藏,你的青睐是我努力的方向!

✏️

评论,你的意见是我进步的财富!

textcolor{green}{评论,你的意见是我进步的财富!}

评论,你的意见是我进步的财富!

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>