【js小游戏&案例】纯前端实现飞机大战,附带源码

2023-11-18

技能:

使用html js css实现飞机大战小游戏

需求:

我军飞机左右移动,并且按空格 可以发射炮弹,敌方飞机从上往下飞,接触到我方炮弹 飞机被歼灭,我军接触到敌军飞机也将会被歼灭,我方飞机吃到道具可以增加弹道

思路:

初始化:初始创建我方飞机,用定时器定时创建敌方飞机,敌方飞机位置由random()随机生成

移动:飞机样式使用position: absolute,然后监听键盘被按事件 用left位置来移动我方飞机,敌军飞机也有定时器 定时向下移动

发射炮弹:创建炮弹跟创建敌军类似,区别是炮弹的位置是根据我方飞机的位置进行初始化的,而敌军飞机位置是随机的

敌军歼灭:通过getBoundingClientRect()获取位置信息 来判断是否接触到;我军歼灭类似

能量小球:产生小球跟敌军类似,休改下样式就好了

效果图:

 全部代码:

<!DOCTYPE html>
<html>

<head>
    <title>飞机大战</title>
    <style>
        html,
        body {
            margin: 0;
            padding: 0;
        }

        /* 游戏边框 */
        .game-board {
            width: 400px;
            height: 600px;
            border: 1px solid black;
            position: relative;
            overflow: hidden;
        }

        /* 我方飞机 */
        .player {
            width: 50px;
            height: 50px;
            background-color: blue;
            position: absolute;
            bottom: 0;
        }

        /* 敌方飞机 */
        .enemy {
            width: 30px;
            height: 30px;
            background-color: red;
            position: absolute;
            top: 0;
        }

        /* 子弹 */
        .bullet {
            width: 2px;
            height: 10px;
            background-color: black;
            position: absolute;
        }

        /* 分数 */
        .score {
            font-size: 18px;
            position: absolute;
            top: 10px;
            right: 10px;
        }

        /* 能量小球 */
        .power-up {
            width: 20px;
            height: 20px;
            background-color: green;
            position: absolute;
        }
    </style>
</head>

<body>
    <div class="game-board" id="game-board">
        <div class="score">分数: <span id="score">0</span></div>
    </div>

    <script>
        const gameBoard = document.getElementById('game-board');
        // 创建我方飞机
        const player = document.createElement('div');
        // 我军飞机初始位置
        let playerLeft = 175;
        player.style.left = `${playerLeft}px`;
        // 游戏是否结束
        let isGameOver = false;
        // 是否在发射子弹的状态
        let isShooting = false;
        // 初始化分数
        let score = 0;
        const scoreElement = document.getElementById('score');
        // 初始化我军飞机样式
        player.classList.add('player');
        gameBoard.appendChild(player);

        // 创造敌军飞机
        function createEnemy() {
            const enemy = document.createElement('div');
            // 随机位置
            let enemyLeft = Math.floor(Math.random() * 350);
            enemy.classList.add('enemy');
            enemy.style.left = `${enemyLeft}px`;
            gameBoard.appendChild(enemy);
            moveEnemy(enemy);
        }

        // 每30ms敌军就会向下移动五像素,如果到达边界就会取消移动 并且移除样式
        function moveEnemy(enemy) {
            let enemyTop = 0;
            let enemyInterval = setInterval(() => {
                if (enemyTop > 600 || isGameOver) {
                    clearInterval(enemyInterval);
                    // 出界 清除dom
                    gameBoard.removeChild(enemy);
                }

                enemy.style.top = `${enemyTop}px`;
                enemyTop += 5;

                // 如果两个接触到 就结束游戏
                if (checkCollision(player, enemy)) {
                    gameOver();
                }
            }, 30);
        }

        // 创建能量小球
        function createPowerUp() {
            const powerUp = document.createElement('div');
            // 随机水平位置
            let powerUpLeft = Math.floor(Math.random() * 350);
            powerUp.classList.add('power-up');
            powerUp.style.left = `${powerUpLeft}px`;
            gameBoard.appendChild(powerUp);

            movePowerUp(powerUp);
        }

        // 移动绿色小球
        // 每30ms绿色小球就会向下移动五像素,如果到达边界就会取消移动 并且移除样式
        function movePowerUp(powerUp) {
            let powerUpTop = 0;
            let powerUpInterval = setInterval(() => {
                if (powerUpTop > 600 || isGameOver) {
                    clearInterval(powerUpInterval);
                    // 出界 清除dom
                    gameBoard.removeChild(powerUp);
                }

                powerUp.style.top = `${powerUpTop}px`;
                powerUpTop += 5;

                // 我方飞机吃到绿色小球
                if (checkCollision(player, powerUp)) {
                    gameBoard.removeChild(powerUp);
                    powerUpEffect();
                }
            }, 30);
        }


        let isDoubleBullet = false;
        let numBullets = 1;

        // 新增函数,处理绿色小球效果
        function powerUpEffect() {
            isDoubleBullet = true;
            numBullets++;
        }

        // 创造子弹
        function createBullet(left, bottom) {
            // console.log(left, bottom)
            const bullet = document.createElement('div');
            bullet.classList.add('bullet');
            bullet.style.left = `${left + 25}px`;
            bullet.style.bottom = `50px`;
            gameBoard.appendChild(bullet);

            moveBullet(bullet);
        }
        // 子弹移动
        function moveBullet(bullet) {
            let bulletBottom = 50;
            let bulletInterval = setInterval(() => {
                if (bulletBottom > 600 || isGameOver) {
                    clearInterval(bulletInterval);
                    gameBoard.removeChild(bullet);
                }

                bullet.style.bottom = `${bulletBottom}px`;
                bulletBottom += 10;

                const enemies = document.querySelectorAll('.enemy');
                // 判断子弹是否接触到敌军飞机
                enemies.forEach(enemy => {
                    if (checkCollision(bullet, enemy)) {
                        clearInterval(bulletInterval);
                        gameBoard.removeChild(bullet);
                        gameBoard.removeChild(enemy);
                        increaseScore();
                    }
                });
            }, 30);
        }

        // 检测是否接触
        function checkCollision(a, b) {
            // getBoundingClientRect()是一个DOM元素对象的方法,用于获取该元素相对于视口(viewport)的位置和尺寸信息
            // 从而进行碰撞检测、位置计算等操作
            const aRect = a.getBoundingClientRect();
            const bRect = b.getBoundingClientRect();

            return !(
                // 我军飞机的top如果小于敌军的bottom 说明已经两机已经接触了
                aRect.top > bRect.bottom ||
                aRect.bottom < bRect.top ||
                aRect.right < bRect.left ||
                aRect.left > bRect.right
            );
        }

        // 游戏结束
        function gameOver() {
            isGameOver = true;
            // 移除gameBoard元素的所有子元素,即清空游戏面板
            while (gameBoard.firstChild) {
                gameBoard.removeChild(gameBoard.firstChild);
            }
            // 停止创造敌军飞机
            clearInterval(enemyInterval)
            gameBoard.innerHTML = '游戏结束!最终分数为: ' + score;
        }

        // 分数增加
        function increaseScore() {
            score++;
            scoreElement.textContent = score;

            if (score % 8 === 0) { // 每射杀十个敌方飞机,创建绿色小球
                createPowerUp();
            }
        }

        document.addEventListener('keydown', function (event) {
            // 空格键
            if (event.keyCode === 32 && !isGameOver) {
                // 发射与停止发射子弹
                if (!isShooting) {
                    isShooting = true;
                    shoot();
                }
            } else if (event.keyCode === 37) { // 左箭头键
                if (playerLeft > 0) playerLeft -= 10;
            } else if (event.keyCode === 39) { // 右箭头键
                if (playerLeft < 350) playerLeft += 10;
            }

            player.style.left = playerLeft + 'px';
        });

        // 控制发射子弹
        function shoot() {
            if (isShooting) {
                const plane = document.querySelector('.player');
                const planeLeft = parseInt(plane.style.left);
                const planeBottom = parseInt(plane.style.bottom);
                console.log(plane.style.left)

                // 增加子弹
                for (let i = 0; i < numBullets; i++) {
                    if (isDoubleBullet) {
                        createBullet(planeLeft - 5 + 10 * i , planeBottom);
                    } else {
                        createBullet(planeLeft, planeBottom);
                    }
                }
                // 设置发射子弹的频率,这里是每隔200毫秒发射一颗子弹
                setTimeout(shoot, 200);
            }
        }

        document.addEventListener('keyup', function (event) {
            if (event.keyCode === 32) { // 当松开空格键时,关闭发射状态
                isShooting = false;
            }
        });

        let enemyInterval = setInterval(createEnemy, 1000); // 每隔1秒创建一个敌方飞机
    </script>
</body>

</html>

有其他问题 欢迎大家评论留言

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【js小游戏&案例】纯前端实现飞机大战,附带源码 的相关文章

  • 如何在createQueryBuilder中使用通配符?

    在我的存储库类中 我使用 public function getItemsByTag tag qb this gt createQueryBuilder c gt select c gt where c tags LIKE bipolar
  • 在 OpenXML 中应用数字格式

    我正在尝试使用 OpenXML 从头开始 创建 Excel 电子表格 并且一切正常 将实际值转储到实际单元格中 但现在我正在尝试将数字格式应用于列 但遇到了问题 我有styles xml看起来像这样
  • 如何使盒子阴影显示在容器中的下一个元素上?

    请看这段代码 http codepen io Varin pen kkGgVd http codepen io Varin pen kkGgVd div class container div class outside2 div clas
  • 如何在odoo中重写js函数

    我想加载 shop checkout url 函数是 odoo define change info order website sale change info order function require use strict oe w
  • 如何在 Angular 2 中订阅 DOMContentLoaded 事件?

    我正在将 UI 主题从 Angular 1 移植到 Angular 2 在第 1 个版本中 我有 viewContentLoaded事件 我想将其重新制作为 Angular 2 我正在尝试使用 HostListener DOMContent
  • 使用 Swift 解析框架

    有人尝试过将 Parse Framework 与 swift 一起使用吗 只要添加桥接文件 您就可以使用 swift 和 Objective C 代码 这是我的查询 从 Parse 返回的 对象 数组正确地包含了我的所有数据 但该方法在将
  • 使用 CDI+JSF 使会话失效不起作用

    我正在尝试在我的应用程序中实现注销 所以我这样做了 public String logout try FacesContext facesContext FacesContext getCurrentInstance ExternalCon
  • NV_path_rendering替代方案[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我刚刚观看了 Siggraph 2012 的一个非常令人印象深刻的演示 http nvidia fullviewmedia com sig
  • 使用 OpenLayers 动态添加自定义标记到地图

    我想让用户在地图上添加自定义标记以及每个标记的描述 任何提示 任何教程的链接都会非常有用 您可以注册一个函数来在地图上 点击 事件 当用户单击它时 会自动添加该标记 尝试这样的事情 map is your map created using
  • git stash 和编辑帅哥

    我完全喜欢git add p and git stash但我偶尔会遇到以下问题 该问题是通过以下命令序列重现的 git add p my file 然后我手动编辑大块 using e 因为 git 建议的分割不适合我 git stash k
  • 如何在 yii 中设置 cron 作业

    我是 yii 的新手 我正在做一个项目 我写了一个向客户发送自动提醒的功能 假设这个函数位于 url http somedomain com index php somecontroller someaction 我想为此网址设置 cron
  • 如何在运行时更改 UIMenu 内 UIAction 的状态?

    如何更改 UIAction 的状态 目标是切换 UIMenu 内 UIAction 旁边的状态复选标记 更改 UIAction 的state通过存储在视图控制器中的引用似乎根本不会改变状态 我错过了什么吗 View Controller i
  • PDO 返回不正确但重复的数据。密钥不在数据库中。

    我刚开始使用 pdo 语句 所以可能是一些简单的东西 我还没有在 php net 上读过 查询数据库时我收到重复的结果 Result 0 gt Array umeta id gt 31 0 gt 31 user id gt 2 1 gt 2
  • 在Java的System.out中以表格格式输出

    我正在从数据库获取结果 并希望将数据作为 Java 标准输出中的表输出 我尝试过使用 t 但我想要的第一列的长度变化很大 有没有办法将其显示在类似输出的漂亮表格中 Use System out format http java sun co
  • Shap - 颜色条不显示在摘要图中

    显示summary plot时 不显示颜色条 shap summary plot shap values X train 我尝试过改变plot size 当绘图较高时 会出现颜色条 但它非常小 看起来不应该 shap summary plo
  • 将元素添加到 D3 圆包节点

    我正在尝试制作一个可缩放的圆形包装图 我希望每个子圆圈包含一个较小的图表 该图表始终具有相同的结构 即 4 列 只有条形的高度会改变 我尝试添加一个简单的rect到目前为止我的图表 但矩形没有添加到圆圈中并且是静态的 JS var marg
  • FindAsync 很慢,但是延迟加载很快

    在我的代码中 我曾经使用加载相关实体await FindAsync 希望我能更好地遵守 C 异步指南 var activeTemplate await exec DbContext FormTemplates FindAsync exec
  • 截断段落前 100 个字符并隐藏段落的其余内容,以通过更多/更少链接显示/隐藏其余内容

    我有一个超过 500 个字符的段落 我只想获取最初的 100 个字符并隐藏其余部分 我还想在 100 个字符旁边插入 更多 链接 单击更多链接时 整个段落应显示并编辑文本 更多 到 更少 单击 更少 时 它应切换行为 段落是动态生成的 我无
  • 同时有两个操作栏(底部和向上)?

    我需要制作两个操作栏 顺便说一下我正在使用actionBarSherlock 所以我真正需要的是在正常操作栏上放置一个 欢迎屏幕 开关 并添加两个正常的 ActionBar 操作选项 与我需要的类似的是 Gmail 和地图 如下所示 htt
  • 如何使用反应本机在数字键盘上添加“完成”按钮

    我在react native中使用数字键盘 我想在单击完成按钮时隐藏键盘 因为我想在键盘上方添加完成按钮 是否有可能像IOS应用程序一样隐藏键盘 任何帮助非常感激 我不确定这是否正是您想要的 但您可以使用 prop returnKeyTyp

随机推荐

  • angular新建组件的组成部分

    主要分为三个组成部分 一 一个ts文件 用来处理数据和功能的 初始会有一个inport 和一个 component 二 一个html文件 用来书写页面的内容 初始会有一个标签 三 一个css文件 用来书写页面样式 初始是一个空文件夹 转载于
  • redis 主从哨兵模式搭建

    一 REDIS主从模式 搭建三个节点 同一个机器 三个端口 安装包 wget http download redis io releases redis 5 0 7 tar gz 安装步骤 https blog csdn net whg18
  • 【Linux】Linux和Window下\r与\n的区别、git命令行的使用

    作者 小卢 专栏 Linux Git 喜欢的话 世间因为少年的挺身而出 而更加瑰丽 人民日报 目录 1 回车换行符在Window下和在Linux下的区别 1 1回车换行符 1 2 行缓冲区打印 1 3进度条小程序 2 git命令行的使用 2
  • JAVA SM2 数字证书生成

    文章目录 Before Start Build with Maven QuickStart 生成自签名公私钥对 证书签名算法算法提供者 设置证书信息 标识信息构造 DN 获取扩展密钥用途构造 可选 证书信息构造 X 509格式证书对象生成
  • C语言版通讯录——动态存储(进阶版)

    前言 之前 我出了一期关于通讯录管理系统的项目实现 里面可以实现通讯录人员的增添改查显示以及排序统计功能 但那种只是以静态开辟内存的方式进行编写 大小固定死 若是达到上限便不可以再进行添加 这次优化 我会将静态存储改为动态存储 达到可以永久
  • idea双击启动无效,idea卡顿问题

    idea双击启动无效 大概率是关机时没有正确关闭idea 再次开机导致无法正常启动idea 1 通过任务管理器杀死idea进程后重启idea 2 需要修改配置 打开 以各自电脑实际为准 C Program Files JetBrains I
  • OpenResty简介、编译安装、新增 sticky模块(再编译)、升级

    OpenResty 也被称为 ngx openresty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 其内部集成了大量精良的 Lua 库 第三方的Nginx模块和大部分系统依赖包 用于方便地搭建能够处理超高并发 扩展性极高的
  • 找不到boost/noncopyable.hpp问题

    本人在vs2013使用boost库的时候 提示找不到boost noncopyable hpp文件 在百度和贴吧上找了很多资料 安装没出问题 只是在包含include的路径是为D boost 1 56 0 boost 本人将boost库直接
  • c++ 友元

    c 类中可以用friend关键字来声明友元 友元可以是另一个类或者类外的其他函数 友元只具有单向性例如 在类A中将类B声明为友元B可以查看A中的所有成员 而A不能查看B的私有成员 同理将一个函数声明为友元时这个函数也可以访问类中的所有成员
  • 6、微信小程序的布局

    文章目录 前言 一 传统基本布局 1 盒子模型 2 显示方式Display 3 定位position 4 溢出属性Overflow 5 浮动Float 6 对齐 二 Flex弹性布局 1 基本属性 2 使用示例 前言 wxss 指的是 We
  • (转)42个超实用的Google Chrome 插件,值得你拥有,建议收藏!

    每日英文 When friends ignore you don t be sad everyone has his own life who can not always be with you 当朋友忽略你时 不要伤心 每个人都有自己的
  • MySql语句查询某一级节点的所有子节点

    MySql语句查询某一级节点的所有子节点 在日常项目中 我们总能用到树型结构的数据 我们用代码去进行查询是比较麻烦的 这里提供一种sql语句查询父节点和子节点的方法 说明 只能当前节点查出所有子节点 不包含与当前节点平级的节点 且子节点是全
  • 事务,不只ACID

    1 什么是事务 应用在运行时可能会发生数据库 硬件的故障 应用与数据库的网络连接断开或多个客户端端并发修改数据导致预期之外的数据覆盖问题 为了提高应用的可靠性和数据的一致性 事务应运而生 从概念上讲 事务是应用程序将多个读写操作组合成一个逻
  • 微信h5分享好友和朋友圈功能

    在开发公众号H5项目时 如果想和小程序一样有分享朋友圈和好友功能时发现会不一样 开发微信小程序时做分享有会有onShareAppMessage 这个方法 因为H5有许多限制 所以在做微信H5分享时就比较麻烦了 首先明确一点 微信H5分享是没
  • Disruptor 详解

    Disruptor 详解 想了解一个项目 最好的办法就是 把它的源码搞到本地自己捣鼓 在网上看了 N 多人对 Disruptor 速度的吹捧 M 多人对它的机制分析 就连 Disruptor 官方文档中 也 NB 哄哄自诩 At LMAX
  • Netty学习17-Netty的可视化

    学习第41节 Netty 可视化方案 Console 日志定时输出 JMX 实时展示 ELKK TIG etc ChannelHandler Sharable public class MetricsHandler extends Chan
  • 08-----查找某个文件的路径

    1 使用find命令查找 关于find这个命令 非常强大 它可以根据文件大小 属性 用户 文件名等去查找匹配的文件 这里不再解释 这里只是列出常用的方法 查找某个文件并不输出错误 find name GetInfo 2 gt dev nul
  • 【Arthas】Arthas retransform动态重新加载类

    1 概述 转载 Arthas retransform动态重新加载类 2 开篇 Arthas提供retransform命令来重新加载已加载的类 通过该命令可以在有限制的反编译已加载的类重新修改后生成class文件重新加载 在测试环境中可以尝试
  • springboot参数配置

    全局配置文件 application properties 配置文件 先准备两个pojo实体类Pet和Person Component 用于将Person类作为Bean注入到spring容器中 ConfigurationProperties
  • 【js小游戏&案例】纯前端实现飞机大战,附带源码

    技能 使用html js css实现飞机大战小游戏 需求 我军飞机左右移动 并且按空格 可以发射炮弹 敌方飞机从上往下飞 接触到我方炮弹 飞机被歼灭 我军接触到敌军飞机也将会被歼灭 我方飞机吃到道具可以增加弹道 思路 初始化 初始创建我方飞