使用js和canvas实现简单的网页打砖块小游戏

玩法介绍

点击开始游戏后,使用键盘上的←→控制移动,小球会不停移动,板子触碰小球时会反弹,碰撞到砖块时会摧毁砖块,如果没有用板子接住小球就游戏失败
在这里插入图片描述

代码实现

代码比较简单,直接阅读注释即可,复制即用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Breakout Game</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
        canvas {
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 1;
            background-color: #000;
        }
        .start-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            text-align: center;
            z-index: 2;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
        }
        button {
            font-size: 24px;
            padding: 10px 20px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <div class="start-screen">
        <h1>Breakout Game</h1>
        <button id="startButton">Start Game</button>
    </div>
    <canvas id="gameCanvas" width="800" height="600"></canvas>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');

        // 设置 Canvas 为全屏
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        // 游戏状态
        let paddle = { x: canvas.width / 2 - 50, y: canvas.height - 50, width: 200, height: 10 };
        let ball = { x: canvas.width / 2, y: canvas.height - 100, radius: 10, dx: 2, dy: -2 };
        let bricks = [];
        let score = 0;

        // 初始化砖块
        function initBricks() {
            const brickWidth = 70;
            const brickHeight = 20;
            const brickCount = 5;
            const brickRow = 10;
            for (let row = 0; row < brickRow; row++) {
                for (let col = 0; col < brickCount; col++) {
                    bricks.push({
                        x: col * (brickWidth + 10) + 150,
                        y: row * (brickHeight + 5) + 50,
                        width: brickWidth,
                        height: brickHeight
                    });
                }
            }
        }

        // 绘制砖块
        function drawBricks() {
            bricks.forEach(brick => {
                ctx.fillStyle = '#0f0';
                ctx.fillRect(brick.x, brick.y, brick.width, brick.height);
            });
        }

        // 绘制拍子
        function drawPaddle() {
            ctx.fillStyle = '#0f0';
            ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
        }

        // 绘制球
        function drawBall() {
            ctx.beginPath();
            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
            ctx.fillStyle = '#f00';
            ctx.fill();
            ctx.closePath();
        }

        // 检查碰撞
        function checkCollision() {
            // 检查球是否撞到砖块
            bricks.forEach((brick, index) => {
                if (
                    ball.x + ball.radius > brick.x &&
                    ball.x - ball.radius < brick.x + brick.width &&
                    ball.y + ball.radius > brick.y &&
                    ball.y - ball.radius < brick.y + brick.height
                ) {
                    ball.dy = -ball.dy;
                    bricks.splice(index, 1);
                    score++;
                }
            });

            // 检查球是否撞到墙壁
            if (ball.x + ball.radius > canvas.width || ball.x - ball.radius < 0) {
                ball.dx = -ball.dx;
            }
            if (ball.y - ball.radius < 0) {
                ball.dy = -ball.dy;
            }

            // 检查球是否撞到拍子
            if (
                ball.x + ball.radius > paddle.x &&
                ball.x - ball.radius < paddle.x + paddle.width &&
                ball.y + ball.radius > paddle.y &&
                ball.y - ball.radius < paddle.y + paddle.height
            ) {
                ball.dy = -ball.dy;
            }

            // 检查球是否掉出屏幕
            if (ball.y + ball.radius > canvas.height) {
                alert('Game Over!');
                location.reload();
            }
        }

        // 更新游戏状态
        function update() {
            ball.x += ball.dx;
            ball.y += ball.dy;
        }

        // 渲染游戏画面
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            drawBricks();
            drawPaddle();
            drawBall();
        }

        // 游戏主循环
        function gameLoop() {
            update();
            checkCollision();
            draw();
            requestAnimationFrame(gameLoop);
        }

        // 键盘事件
        function handleKeyPress(event) {
            if (event.key === 'ArrowLeft') {
                paddle.x -= 15;
            }
            if (event.key === 'ArrowRight') {
                paddle.x += 15;
            }
        }

        // 开始按钮事件
        document.getElementById('startButton').addEventListener('click', () => {
            const startScreen = document.querySelector('.start-screen');
            startScreen.style.display = 'none';

            // 添加键盘事件监听
            document.addEventListener('keydown', handleKeyPress);

            initBricks();
            gameLoop();
        });

        // 游戏结束时移除键盘事件监听
        window.addEventListener('beforeunload', () => {
            document.removeEventListener('keydown', handleKeyPress);
        });
    </script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/891281.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

抖音小游戏画图位置移动

文章目录 画图移动图形位置 画图 const canvas tt.createCanvas(); const context canvas.getContext(2d);context.width 500; context.height 500;let isPressing false; // 是否按下 let startX 0; let startY 0;context.fillStyle "#f00"; context.fillR…

骨传导耳机哪个牌子的最好?全面测评分享5大热门骨传导耳机

在当今快节奏的生活中&#xff0c;人们越来越重视健康与休闲的平衡&#xff0c;而音乐则是连接这两者的重要桥梁。对于经常进行户外活动或锻炼的人来说&#xff0c;传统入耳式耳机可能存在安全隐患&#xff0c;这时&#xff0c;骨传导耳机便成为了理想的选择。骨传导技术通过振…

82.【C语言】数据结构之顺序表

在软件开发中,存储列表常用顺序表或链表 1.线性表 定义:n个具有相同特性的数据元素的有限序列(相当于一条直线)(用数组存储),要求数据依次存储 2.分类 1.静态顺序表&#xff1a;使用定长数组存储元素 代码示例(写入Seqlist.h中) typedef int SLDataType;//将int重定义为SL…

Java:玩家打怪小游戏

今天&#xff0c;我们尝试用Java来做一个“打怪小游戏”&#xff0c;听名字就知道&#xff0c;我们是应该创建几个成员和怪物&#xff0c;还有知道知道成员和怪物的血量&#xff0c;一次攻击的伤害等等。。当然我们的游戏攻击模式是“回合制”&#xff08;其实是别的方法&#…

云开发 | 微信小程序云开发无法获取数据库数据

1.我在我的云数据库中创建了一个数据表&#xff08;即collection数据集&#xff09;userList,并且存入了两条用户信息数据 2. 想要通过按钮触发事件拿取数据库中数据并且打印在控制台时&#xff0c;获取数据失败&#xff0c;控制台无输出 3. 初始化 | 在开始使用数据库 API 进…

androidStudio编译导致的同名.so文件冲突问题解决

files found with path lib/arm64-v8a/libserial_port.so from inputs: ...\build\intermediates\library_jni\debug\jni\arm64-v8a\libserial_port.so C:\Users\...\.gradle\caches\transforms-3\...\jni\arm64-v8a\XXX.so 解决方式如下&#xff1a; 1.将gradle缓存文件删…

Linux系统——lvm逻辑卷

Linux系统——lvm逻辑卷 一、lvm逻辑卷1、lvm操作流程2、操作指令 二、逻辑卷操作1、创建逻辑卷1.1 /dev/cloud/openstack 5G xfs /cloud/openstack1.2 /dev/cloud/docker 10G ext4 /cloud/docker 2、逻辑卷扩容2.1 扩容流程2.2 需求一&#xff1a;扩容ext4文件系统的逻辑卷2.3…

新手给视频加字幕的方法有哪些?4种加字幕方法推荐!

在视频制作中&#xff0c;字幕不仅是传递信息的重要手段&#xff0c;还能增强视频的观感和专业性。对于新手来说&#xff0c;如何给视频添加字幕可能是一个挑战。本文将介绍字幕的类型、推荐添加字幕的工具&#xff0c;以及详细添加字幕方法&#xff0c;帮助新手轻松掌握视频字…

宠物咖啡馆业务自动化:SpringBoot框架的实现方法

3系统分析 3.1可行性分析 通过对本基于Spring Boot的宠物咖啡馆平台的设计与实现实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于Spring Boot的宠物咖啡馆…

微前端 Spa qiankun

简介 首先什么是微前端&#xff1f; 他是一个软件架构模式。借鉴了后端的为服务架构思想&#xff0c;是将复杂单一的前端进行拆分成多个可以独立开发、部署、维护的小型应用。不同的应用关注不同的业务。最终将其集成到一个主框架里面。简单来说就是先分后合。 传统前端开发的…

【Unity - 屏幕截图】技术要点

在Unity中想要实现全屏截图或者截取某个对象区域的图片都是可以通过下面的函数进行截取 Texture2D/// <summary>/// <para>Reads the pixels from the current render target (the screen, or a RenderTexture), and writes them to the texture.</para>/…

【氮化镓】低温对p-GaN HEMT迁移率、阈值电压和亚阈值摆幅的影响

本期分享一篇低温对p-GaN HEMT 迁移率、阈值电压和亚阈值摆幅影响进行表征和建模的研究论文。文章作者Shivendra Kumar Singh、Thien Sao Ngo、Tian-Li Wu(通讯作者)和Yogesh Singh Chauhan,分别来资源中国台湾阳明交通大学国际半导体技术学院、印度理工学院坎普尔分校电气工…

(二)Python输入输出函数

一、输入函数 input函数&#xff1a;用户输入的数据&#xff0c;以字符串形式返回&#xff1b;若需数值类型&#xff0c;则进行类型转换。 xinput("请入你喜欢的蔬菜&#xff1a;") print(x) 二、输出函数 print函数 输出单一数值 x666 print(x) 输出混合类型…

专利开放许可与知识产权保护的关系是什么?

专利开放许可在一定程度上是对知识产权保护制度的补充和拓展。知识产权保护的核心目标是鼓励创新&#xff0c;通过赋予专利所有者一定期限内的独占权&#xff0c;使其能够从创新成果中获得经济回报&#xff0c;从而激励更多的创新投入。 专利开放许可则为专利的应用和传播提供了…

如何制作一个宠物店小程序

产品介绍&#xff1a; 出门在外随时都可以看到不少的居民养的有宠物&#xff0c;大多数都是以阿猫阿狗为主&#xff0c;可以所得宠物市场比较大&#xff0c;宠物数量已经统计到的就有上亿只。这么多的宠物肯定需要宠物粮食&#xff0c;宠物服务市场就出来了。 家里有宠…

Git的基本使用入门

参考&#xff1a;Git速查 git的基本概念 git常用命令大部分是基于三大分区来执行的。先来了解一些专有名词吧。 工作区&#xff0c;也叫 Working Directory暂存区&#xff0c;也叫 stage&#xff0c;index版本库&#xff0c;也叫本地仓库&#xff0c;commit History 将代码推…

从混乱到可控:非结构化数据在远程监造中的作用

一、背景远程数字监造&#xff0c;工业制造的新趋势 在光伏组件的生产过程中&#xff0c;其质量和安全性&#xff0c;对产品的整体效益来说至关重要。为保证最终效益&#xff0c;必须要有对生产过程的监造和生产完成的验收。 然而&#xff0c;传统的线下监造模式效率较低&…

facebook受众选择设置策略的最佳方式

在进行Facebookguanggao投放时&#xff0c;受众的选择是一个至关重要的步骤。正确的受众选择不仅能够帮助我们更好地定位目标用户&#xff0c;还能显著提高guanggao的转化率和投资回报率&#xff08;ROI&#xff09;。然而&#xff0c;受众选择的数量和范围同样是需要认真考虑的…

Mybatis全局配置介绍

【mybatis全局配置介绍】 mybatis-config.xml&#xff0c;是MyBatis的全局配置文件&#xff0c;包含全局配置信息&#xff0c;如数据库连接参数、插件等。整个框架中只需要一个即可。 1、mybatis全局配置文件是mybatis框架的核心配置&#xff0c;整个框架只需一个&#xff1b…

物联网IoT平台 | 物联网IoT平台的定义

物联网IoT平台&#xff1a;定义、发展与应用在当今信息化时代&#xff0c;物联网&#xff08;Internet of Things&#xff0c;简称IoT&#xff09;已经成为推动社会进步和产业升级的重要力量。物联网IoT平台&#xff0c;作为连接物理世界与数字世界的桥梁&#xff0c;正逐步改变…