实现弹弹球小游戏

游戏概述

“弹弹球”小游戏通过HTML5 Canvas、CSS7以及JavaScript实现。

玩家使用键盘控制挡板,反弹小球,避免小球掉落。

游戏界面为粉色,小球速度和颜色会随机变化。

使用工具

本篇文章有用到GPT-4o代码纠错,国内可稳定使用,感兴趣的大佬试试363Ai工具箱

 

游戏玩法

  1. 控制挡板:使用键盘上的左右箭头键,移动挡板接住反弹的小球。
  2. 目标:尽可能长时间地保持小球在画布上方反弹。
  3. 失败条件:小球未被接住时,屏幕会显示“哈哈!你真笨!”,提示玩家重新尝试。

 

实现步骤

HTML结构

HTML部分定义了游戏的基本结构,包括画布、按钮和消息显示区。

代码展示:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        /* 样式在这里定义 */
    </style>
    <title>弹弹球游戏</title>
</head>
<body>
    <div id="message">哈哈!你真笨!</div>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <button id="startButton">开始</button>
    <button id="endButton">结束</button>
    <script>
        /* JavaScript代码在这里定义 */
    </script>
</body>
</html>

运行界面:

 

解释:HTML页面包含一个canvas元素用于游戏绘制,两个按钮用于控制游戏开始和结束,还有一个显示失败信息的div。 

CSS样式

代码展示:

body {
    margin: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-color: pink;
}
canvas {
    background: pink;
    display: block;
    border: 3px solid #fff;
}
#message {
    position: absolute;
    color: white;
    font-size: 48px;
    display: none;
}
button {
    margin: 10px;
    padding: 10px 20px;
    font-size: 16px;
}

 解释:页面使用粉色背景,canvas也为粉色。按钮样式简单,居中显示。

#message在游戏失败时显示信息。

JavaScript实现

JavaScript负责游戏的动态逻辑,包括小球和挡板的运动、碰撞检测和用户交互。

const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const message = document.getElementById('message');
const startButton = document.getElementById('startButton');
const endButton = document.getElementById('endButton');

function randomSpeed() {
    return (Math.random() * 4 + 2) * (Math.random() < 0.5 ? 1 : -1);
}

let ball = {
    x: canvas.width / 2,
    y: canvas.height / 2,
    dx: randomSpeed(),
    dy: randomSpeed(),
    radius: 10,
    color: '#00FFFF'
};

let paddle = {
    width: 100,
    height: 10,
    x: canvas.width / 2 - 50,
    color: '#FFFFFF', // 白色挡板
    speed: 10 // 减慢速度
};

let rightPressed = false;
let leftPressed = false;
let animationId;
let isRunning = false;

 

解释:

  • 元素获取:获取canvas和按钮元素。
  • 随机速度函数:randomSpeed函数为小球生成随机速度。
  • 对象初始化:定义ball和paddle对象,包含位置、速度和颜色属性。

 

绘制函数

负责在Canvas上绘制小球和挡板。

function drawBall() {
    ctx.beginPath();
    ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
    ctx.fillStyle = ball.color;
    ctx.fill();
    ctx.closePath();
}

function drawPaddle() {
    ctx.beginPath();
    ctx.rect(paddle.x, canvas.height - paddle.height, paddle.width, paddle.height);
    ctx.fillStyle = paddle.color;
    ctx.fill();
    ctx.closePath();
}

解释:drawBall和drawPaddle函数在Canvas上绘制小球和挡板。

运动和碰撞逻辑

处理小球和挡板的运动逻辑及碰撞检测。

function movePaddle() {
    if (rightPressed && paddle.x < canvas.width - paddle.width) {
        paddle.x += paddle.speed;
    }
    if (leftPressed && paddle.x > 0) {
        paddle.x -= paddle.speed;
    }
}

function changeBallColor() {
    const colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#F3FF33'];
    ball.color = colors[Math.floor(Math.random() * colors.length)];
}

function updateBall() {
    ball.x += ball.dx;
    ball.y += ball.dy;

    if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
        ball.dx = -ball.dx;
        changeBallColor();
    }

    if (ball.y - ball.radius < 0) {
        ball.dy = -ball.dy;
        changeBallColor();
    } else if (ball.y + ball.radius > canvas.height - paddle.height) {
        if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
            ball.dy = -ball.dy;
            changeBallColor();
        } else {
            message.style.display = 'block';
            cancelAnimationFrame(animationId);
            isRunning = false;
        }
    }
}

解释:

  • 挡板移动:movePaddle根据键盘输入移动挡板。
  • 颜色变化:changeBallColor在小球碰撞时改变其颜色。
  • 更新逻辑:updateBall处理小球的运动和碰撞检测,碰撞后改变方向和颜色。

游戏循环

负责游戏的持续更新和重绘。

负责游戏的持续更新和重绘。

function draw() {
    if (!isRunning) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawBall();
    drawPaddle();
    movePaddle();
    updateBall();

    animationId = requestAnimationFrame(draw);
}

function resetGame() {
    ball.x = canvas.width / 2;
    ball.y = canvas.height / 2;
    ball.dx = randomSpeed();
    ball.dy = randomSpeed();
    message.style.display = 'none';
}

解释:

  • 游戏循环:draw函数负责游戏的持续更新和重绘。
  • 重置游戏:resetGame重置小球位置和速度,隐藏失败信息。

事件监听

处理用户输入和按钮点击事件。

document.addEventListener('keydown', (e) => {
    if (e.key === 'ArrowRight') {
        rightPressed = true;
    } else if (e.key === 'ArrowLeft') {
        leftPressed = true;
    }
});

document.addEventListener('keyup', (e) => {
    if (e.key === 'ArrowRight') {
        rightPressed = false;
    } else if (e.key === 'ArrowLeft') {
        leftPressed = false;
    }
});

startButton.addEventListener('click', () => {
    if (!isRunning) {
        resetGame();
        isRunning = true;
        draw();
    }
});

endButton.addEventListener('click', () => {
    isRunning = false;
    cancelAnimationFrame(animationId);
    message.style.display = 'none';
});

解释:

  • 键盘监听:监听左右箭头按键,控制挡板移动。
  • 按钮事件:监听开始和结束按钮,控制游戏状态。


以下是完整的代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            margin: 0;
            overflow: hidden;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: pink;
        }
        canvas {
            background: pink;
            display: block;
            border: 3px solid #fff;
        }
        #message {
            position: absolute;
            color: white;
            font-size: 48px;
            display: none;
        }
        button {
            margin: 10px;
            padding: 10px 20px;
            font-size: 16px;
        }
    </style>
    <title>弹弹球游戏</title>
</head>
<body>
    <div id="message">哈哈!你真笨!</div>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <button id="startButton">开始</button>
    <button id="endButton">结束</button>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const message = document.getElementById('message');
        const startButton = document.getElementById('startButton');
        const endButton = document.getElementById('endButton');

        function randomSpeed() {
            return (Math.random() * 4 + 2) * (Math.random() < 0.5 ? 1 : -1);
        }

        let ball = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            dx: randomSpeed(),
            dy: randomSpeed(),
            radius: 10,
            color: '#00FFFF'
        };

        let paddle = {
            width: 100,
            height: 10,
            x: canvas.width / 2 - 50,
            color: '#FFFFFF',
            speed: 10
        };

        let rightPressed = false;
        let leftPressed = false;
        let animationId;
        let isRunning = false;

        function drawBall() {
            ctx.beginPath();
            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
            ctx.fillStyle = ball.color;
            ctx.fill();
            ctx.closePath();
        }

        function drawPaddle() {
            ctx.beginPath();
            ctx.rect(paddle.x, canvas.height - paddle.height, paddle.width, paddle.height);
            ctx.fillStyle = paddle.color;
            ctx.fill();
            ctx.closePath();
        }

        function movePaddle() {
            if (rightPressed && paddle.x < canvas.width - paddle.width) {
                paddle.x += paddle.speed;
            }
            if (leftPressed && paddle.x > 0) {
                paddle.x -= paddle.speed;
            }
        }

        function changeBallColor() {
            const colors = ['#FF5733', '#33FF57', '#3357FF', '#FF33A8', '#F3FF33'];
            ball.color = colors[Math.floor(Math.random() * colors.length)];
        }

        function updateBall() {
            ball.x += ball.dx;
            ball.y += ball.dy;

            if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
                ball.dx = -ball.dx;
                changeBallColor();
            }

            if (ball.y - ball.radius < 0) {
                ball.dy = -ball.dy;
                changeBallColor();
            } else if (ball.y + ball.radius > canvas.height - paddle.height) {
                if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) {
                    ball.dy = -ball.dy;
                    changeBallColor();
                } else {
                    message.style.display = 'block';
                    cancelAnimationFrame(animationId);
                    isRunning = false;
                }
            }
        }

        function draw() {
            if (!isRunning) return;
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawBall();
            drawPaddle();
            movePaddle();
            updateBall();

            animationId = requestAnimationFrame(draw);
        }

        function resetGame() {
            ball.x = canvas.width / 2;
            ball.y = canvas.height / 2;
            ball.dx = randomSpeed();
            ball.dy = randomSpeed();
            message.style.display = 'none';
        }

        document.addEventListener('keydown', (e) => {
            if (e.key === 'ArrowRight') {
                rightPressed = true;
            } else if (e.key === 'ArrowLeft') {
                leftPressed = true;
            }
        });

        document.addEventListener('keyup', (e) => {
            if (e.key === 'ArrowRight') {
                rightPressed = false;
            } else if (e.key === 'ArrowLeft') {
                leftPressed = false;
            }
        });

        startButton.addEventListener('click', () => {
            if (!isRunning) {
                resetGame();
                isRunning = true;
                draw();
            }
        });

        endButton.addEventListener('click', () => {
            isRunning = false;
            cancelAnimationFrame(animationId);
            message.style.display = 'none';
        });
    </script>
</body>
</html>

代码解析

  • HTML:定义了游戏的基本结构,包括画布、按钮和消息显示区。
  • CSS:设置了页面样式,粉色背景,居中显示的按钮和消息。
  • JavaScript:
  •  初始化游戏元素和状态。
  • 定义小球和挡板的属性和行为。
  • 实现小球的随机速度和颜色变化。
  • 处理键盘输入以控制挡板移动。
  • 使用requestAnimationFrame实现动画循环。

  


运行界面:

 

 

学习收获

通过这个项目,初学者可以掌握:

  • HTML5 Canvas的基本用法
  • JavaScript中对象和方法的使用
  • 动画循环和用户交互的实现
  • 简单的碰撞检测和游戏逻辑

这不仅是一个娱乐项目,也是一个学习和实践编程的好机会。通过不断调整和优化代码,玩家可以深入理解游戏开发的基本概念,为未来更复杂的项目打下坚实基础。

感谢阅读!!!

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值