目录

前言

一、游戏概览与技术选型

二、HTML 结构搭建和CSS样式美化

三、JavaScript 核心逻辑

1.变量声明与初始化

2.玩家飞机控制函数

3.射击与子弹管理函数

4.敌机生成与管理函数

5.碰撞检测与得分更新函数

6.游戏主循环与启动函数

四、完整代码


前言

        在前端开发的广阔天地里,利用 HTML、CSS 和 JavaScript 创造出富有互动性与趣味性的游戏,是一件极具挑战性与成就感的事情。今天,我将带大家深入解读一款纯前端飞机大战游戏的代码实现,从基础架构到核心逻辑,一步步揭示其背后的奥秘。

一、游戏概览与技术选型

        这款飞机大战游戏完全基于前端技术构建,无需后端服务器的支持,仅依靠 HTML 构建页面结构,CSS 负责样式呈现,JavaScript 掌控游戏的动态逻辑。这种纯前端的实现方式使得游戏能够在浏览器中直接运行,方便快捷,且易于分享与传播。

二、HTML 结构搭建和CSS样式美化

<!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>
        /* CSS 样式 */

        #game-board {
            width: 480px; /*  设置游戏面板的宽度为480像素 */
            height: 500px; /*  设置游戏面板的高度为500像素 */
            border: 1px solid black; /*  给游戏面板添加1像素的黑色边框 */
            position: relative; /*  设置相对定位,方便内部元素进行定位 */
            margin: 0 auto; /*  使游戏面板在页面中水平居中 */
        }

        #player {
            width: 50px; /*  设置玩家飞机元素的宽度为50像素 */
            height: 50px; /*  设置玩家飞机元素的高度为50像素 */
            background-color: red; /*  设置玩家飞机的背景颜色为红色 */
            position: absolute; /*  绝对定位,便于精确控制其在游戏面板中的位置 */
            bottom: 0; /*  将玩家飞机定位在游戏面板底部 */
            left: 50%; /*  初始水平位置在游戏面板的水平居中处 */
            transform: translateX(-50%); /*  通过水平平移使其精准居中,因为left: 50%是基于元素自身宽度的一半,需要微调 */
        }

       .bullet {
            width: 5px; /*  设置子弹元素的宽度为5像素 */
            height: 20px; /*  设置子弹元素的高度为20像素 */
            background-color: black; /*  设置子弹的背景颜色为黑色 */
            position: absolute; /*  绝对定位,用于后续控制其在游戏面板中的位置变化 */
        }

       .enemy {
            width: 40px; /*  设置敌机元素的宽度为40像素 */
            height: 40px; /*  设置敌机元素的高度为40像素 */
            background-color: blue; /*  设置敌机的背景颜色为蓝色 */
            position: absolute; /*  绝对定位,方便控制敌机在游戏面板的位置 */
        }

        #score {
            font-size: 24px; /*  设置得分显示的字体大小为24像素 */
            text-align: center; /*  使得分文本在其容器内居中显示 */
        }
    </style>
</head>

<body>
    <div id="game-board">
        <div id="player"></div>
        <div id="score">Score: 0</div>
    </div>
</body>
  •         在 HTML 部分,我们创建了一个 #game-board 的 div 元素作为游戏的主容器,它设定了游戏的整体尺寸(480px 宽,500px 高)并添加了边框,通过 margin: 0 auto 使其在页面中水平居中。#player 元素代表玩家的飞机,初始位置在游戏板底部居中,红色背景使其醒目。#score 元素则用于展示玩家的得分,位于游戏板上方居中,初始得分为 0。bullet 和 enemy 类分别定义了子弹和敌机的样式,它们的具体位置和动态效果将由 JavaScript 代码来控制。 
  •         对于 #game-board,其相对定位为内部绝对定位元素(如玩家飞机、子弹和敌机)提供了参照系。玩家飞机的样式不仅定义了其大小和颜色,还通过精确的定位属性(bottom: 0 和 left: 50% 结合 transform: translateX(-50%))确保其在底部水平居中。子弹和敌机的样式则分别规定了它们的尺寸和颜色,这些简单而有效的样式设置,为游戏构建了一个清晰、直观的视觉界面。

三、JavaScript 核心逻辑

1.变量声明与初始化

// JavaScript 代码
    
    // 获取游戏面板元素,后续用于操作游戏面板内的各种元素以及获取面板相关属性(如宽高)
    let gameBoard = document.getElementById("game-board");
    // 获取代表玩家飞机的元素,用于控制玩家飞机的位置、样式等操作
    let player = document.getElementById("player");
    // 获取用于显示得分的元素,方便更新得分信息
    let scoreElement = document.getElementById("score");
    
    // 用于存储所有已发射的子弹元素,每个元素都是页面中的一个DOM节点,方便统一管理和操作
    let bullets = [];
    // 用于存储所有出现的敌机元素,同样每个元素是页面中的DOM节点,便于管理敌机的创建、移动和销毁等操作
    let enemies = [];
    // 用于记录玩家的得分,初始化为0,每当击中敌机时会相应增加
    let score = 0;

        首先,我们获取了游戏板、玩家飞机和得分元素的引用,这些引用将在后续的代码中频繁使用,用于操作和更新相应的元素。同时,初始化了三个重要的数组:bullets 用于存储所有发射的子弹,enemies 用于存放生成的敌机,score 则记录玩家的得分,初始值为 0。 

2.玩家飞机控制函数

// 函数用于移动玩家飞机,根据传入的方向参数来改变飞机的水平位置
    function movePlayer(direction) {
        // 获取玩家飞机当前的水平位置(left属性值),如果获取失败(可能是未设置过)则默认为0, parseInt用于将字符串类型的像素值转换为数字类型
        let currentPosition = parseInt(player.style.left) || 0;
    
        if (direction === "left") {
            currentPosition -= 20; // 如果方向是向左,将当前位置减少20像素,实现向左移动
        } else if (direction === "right") {
            currentPosition += 20; // 如果方向是向右,将当前位置增加20像素,实现向右移动
        }
    
        // 限制飞机移动范围在游戏板内,通过 Math.max确保不小于0(游戏板左侧边界),Math.min确保不大于游戏板宽度减去飞机自身宽度(游戏板右侧边界)
        currentPosition = Math.max(0, Math.min(currentPosition, gameBoard.offsetWidth - player.offsetWidth));
    
        player.style.left = currentPosition + "px"; // 更新玩家飞机的水平位置样式属性,将数字转换为带单位的像素值字符串
    }

   movePlayer 函数实现了玩家飞机的左右移动功能。通过获取玩家飞机当前的 left 样式值并转换为数字类型,根据传入的方向参数(left 或 right)来增减其水平位置。为了确保飞机不会移出游戏板边界,使用 Math.max 和 Math.min 函数对位置进行限制,最后更新玩家飞机的 left 样式属性,实现平滑的移动效果。 

3.射击与子弹管理函数

// 函数用于发射子弹,创建一个新的子弹元素并添加到游戏面板中,同时将其添加到bullets数组进行管理
    function shoot() {
        // 创建一个新的div元素,用于表示子弹
        let bullet = document.createElement("div");
        bullet.className = "bullet"; // 为子弹元素添加对应的类名,以便应用CSS样式
        // 设置子弹的水平位置,使其在玩家飞机的中心位置,减去2.5像素是为了精准居中(因为子弹宽度为5像素)
        bullet.style.left = parseInt(player.style.left) + player.offsetWidth / 2 - 2.5 + "px";
        bullet.style.bottom = player.offsetHeight + "px"; // 设置子弹的垂直位置,在玩家飞机的上方(底部对齐)
        gameBoard.appendChild(bullet); // 将子弹元素添加到游戏面板中,使其在页面上显示出来
        bullets.push(bullet); // 将新创建的子弹元素添加到bullets数组中,方便后续统一管理
    }
    
    // 函数用于移动所有已发射的子弹,更新它们在游戏面板中的垂直位置
    function moveBullets() {
        bullets.forEach((bullet, bulletIndex) => {
            // 获取子弹当前的垂直位置(bottom属性值),如果获取失败则默认为0,同样进行类型转换
            let currentPosition = parseInt(bullet.style.bottom) || 0;
            currentPosition += 10; // 将子弹的垂直位置增加10像素,实现向上移动
    
            if (currentPosition >= gameBoard.offsetHeight) {
                // 如果子弹超出了游戏面板的高度(到达顶部边界),则从页面中移除该子弹元素
                bullet.remove();
                bullets.splice(bulletIndex, 1); // 同时从bullets数组中移除对应的元素,保持数组和页面元素的一致性
            } else {
                bullet.style.bottom = currentPosition + "px"; // 如果未超出边界,更新子弹的垂直位置样式属性
            }
        });
    }

   shoot 函数用于创建并发射子弹。当玩家按下空格键时,该函数被触发。它创建一个新的 div 元素作为子弹,设置其类名、初始位置(在玩家飞机中心上方),并将其添加到游戏板中,同时将子弹元素添加到 bullets 数组中以便后续管理。moveBullets 函数则负责更新子弹的位置,遍历 bullets 数组,使每个子弹向上移动(增加 bottom 样式值),一旦子弹移出游戏板顶部,就将其从页面和数组中移除,确保游戏资源的有效管理。 

4.敌机生成与管理函数

// 函数用于创建一个新的敌机元素,并添加到游戏面板中,同时将其添加到enemies数组进行管理
    function createEnemy() {
        let enemy = document.createElement("div");
        enemy.className = "enemy"; // 为敌机元素添加对应的类名,以便应用CSS样式
        // 设置敌机的水平位置,使其在游戏面板内随机出现(在游戏面板宽度减去敌机自身宽度的范围内随机取值)
        enemy.style.left = Math.random() * (gameBoard.offsetWidth - 40) + "px";
        enemy.style.top = "0px"; // 设置敌机的初始垂直位置在游戏面板顶部
        gameBoard.appendChild(enemy); // 将敌机元素添加到游戏面板中,使其在页面上显示出来
        enemies.push(enemy); // 将新创建的敌机元素添加到enemies数组中,方便后续统一管理
    }
    
    // 函数用于移动所有的敌机,更新它们在游戏面板中的垂直位置,实现敌机向下移动的效果
    function moveEnemies() {
        enemies.forEach((enemy, enemyIndex) => {
            // 获取敌机当前的垂直位置(top属性值),如果获取失败则默认为0,进行类型转换
            let currentPosition = parseInt(enemy.style.top) || 0;
            currentPosition += 5; // 将敌机的垂直位置增加5像素,实现向下移动
    
            if (currentPosition >= gameBoard.offsetHeight) {
                // 如果敌机超出了游戏面板的高度(到达底部边界),则从页面中移除该敌机元素
                enemy.remove();
                enemies.splice(enemyIndex, 1); // 同时从enemies数组中移除对应的元素,保持数组和页面元素的一致性
            } else {
                enemy.style.top = currentPosition + "px"; // 如果未超出边界,更新敌机的垂直位置样式属性
            }
        });
    }

   createEnemy 函数用于随机生成敌机。它创建一个新的敌机 div 元素,设置其类名和初始位置(在游戏板顶部随机水平位置),然后添加到游戏板并放入 enemies 数组。moveEnemies 函数负责移动敌机,使每个敌机向下移动(增加 top 样式值),当敌机移出游戏板底部时,将其从页面和数组中移除,模拟敌机的飞行和消失过程。 

5.碰撞检测与得分更新函数

// 函数用于检测子弹与敌机之间是否发生碰撞,如果发生碰撞则进行相应的处理(移除子弹和敌机,增加得分等)
    function detectCollision() {
        bullets.forEach((bullet, bulletIndex) => {
    
            enemies.forEach((enemy, enemyIndex) => {
                // 通过比较子弹和敌机的边界位置来判断是否发生碰撞,检测条件涵盖了上下左右四个方向的位置关系
                if (
                    bullet.offsetTop <= enemy.offsetTop + enemy.offsetHeight &&
                    bullet.offsetTop + bullet.offsetHeight >= enemy.offsetTop &&
                    bullet.offsetLeft <= enemy.offsetLeft + enemy.offsetWidth &&
                    bullet.offsetLeft + bullet.offsetWidth >= enemy.offsetLeft
                ) {
                    bullet.remove(); // 如果发生碰撞,从页面中移除子弹元素
                    bullets.splice(bulletIndex, 1); // 从bullets数组中移除对应的子弹元素
                    enemy.remove(); // 从页面中移除敌机元素
                    enemies.splice(enemyIndex, 1); // 从enemies数组中移除对应的敌机元素
                    score += 10; // 玩家得分增加10分
                    scoreElement.innerHTML = "Score: " + score; // 更新页面上显示的得分信息
                }
            });
        });
    }

           detectCollision 函数是游戏的核心逻辑之一,它负责检测子弹与敌机之间的碰撞。通过遍历 bullets 和 enemies 数组,比较每个子弹和敌机的边界位置关系,一旦检测到碰撞,就移除相应的子弹和敌机元素,并从数组中删除它们,同时增加玩家的得分并更新得分显示元素的内容,让玩家及时了解自己的游戏成果。 

6.游戏主循环与启动函数

// 游戏主循环函数,在每次循环中调用移动子弹、移动敌机和检测碰撞的函数,实现游戏的持续更新和逻辑处理
    function gameLoop() {
        moveBullets();
        moveEnemies();
        detectCollision();
    }
    
    // 函数用于启动游戏,初始化游戏相关的各种状态,包括得分、元素位置、清除已有的子弹和敌机等,并设置定时创建敌机和执行游戏主循环的定时器
    function startGame() {
        score = 0; // 将得分重置为0
        scoreElement.innerHTML = "Score: " + score; // 更新页面上显示的得分信息为0
    
        // 将玩家飞机的水平位置重新设置为游戏面板的水平居中处
        player.style.left = (gameBoard.offsetWidth - player.offsetWidth) / 2 + "px";
    
        // 移除所有已存在的子弹元素,并清空bullets数组
        bullets.forEach(bullet => bullet.remove());
        bullets = [];
    
        // 移除所有已存在的敌机元素,并清空enemies数组
        enemies.forEach(enemy => enemy.remove());
        enemies = [];
    
        // 设置每隔1000毫秒(1秒)创建一个新的敌机,不断增加游戏中的敌机数量,增加游戏难度
        setInterval(createEnemy, 1000);
        // 设置每隔30毫秒执行一次游戏主循环,实现游戏的流畅更新和逻辑处理,控制游戏的帧率
        setInterval(gameLoop, 30);
    }
    
    // 监听键盘按下事件,根据按下的不同按键来执行相应的游戏操作,如移动玩家飞机或发射子弹
    document.addEventListener("keydown", function (event) {
        if (event.code === "ArrowLeft") {
            movePlayer("left"); // 如果按下向左箭头键,调用函数向左移动玩家飞机
        } else if (event.code === "ArrowRight") {
            movePlayer("right"); // 如果按下向右箭头键,调用函数向右移动玩家飞机
        } else if (event.code === "Space") {
            shoot(); // 如果按下空格键,调用函数发射子弹
        }
    });
    
    startGame(); // 启动游戏,开始整个游戏流程

    gameLoop 函数作为游戏的主循环,在每次循环中依次调用 moveBulletsmoveEnemies 和 detectCollision 函数,实现子弹移动、敌机移动和碰撞检测的持续更新,保证游戏的动态运行。startGame 函数用于初始化游戏状态,重置得分、玩家飞机位置,清空子弹和敌机数组,然后设置两个定时器:一个每隔 1 秒调用 createEnemy 函数生成新的敌机,增加游戏难度;另一个每隔 30 毫秒调用 gameLoop 函数,控制游戏的帧率,使游戏运行更加流畅。最后,通过监听键盘按下事件,根据不同的按键触发相应的游戏操作函数,如玩家飞机移动和射击。 

四、完整代码

<!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>
        /* CSS 样式 */

        #game-board {
            width: 480px; /*  设置游戏面板的宽度为480像素 */
            height: 500px; /*  设置游戏面板的高度为500像素 */
            border: 1px solid black; /*  给游戏面板添加1像素的黑色边框 */
            position: relative; /*  设置相对定位,方便内部元素进行定位 */
            margin: 0 auto; /*  使游戏面板在页面中水平居中 */
        }

        #player {
            width: 50px; /*  设置玩家飞机元素的宽度为50像素 */
            height: 50px; /*  设置玩家飞机元素的高度为50像素 */
            background-color: red; /*  设置玩家飞机的背景颜色为红色 */
            position: absolute; /*  绝对定位,便于精确控制其在游戏面板中的位置 */
            bottom: 0; /*  将玩家飞机定位在游戏面板底部 */
            left: 50%; /*  初始水平位置在游戏面板的水平居中处 */
            transform: translateX(-50%); /*  通过水平平移使其精准居中,因为left: 50%是基于元素自身宽度的一半,需要微调 */
        }

       .bullet {
            width: 5px; /*  设置子弹元素的宽度为5像素 */
            height: 20px; /*  设置子弹元素的高度为20像素 */
            background-color: black; /*  设置子弹的背景颜色为黑色 */
            position: absolute; /*  绝对定位,用于后续控制其在游戏面板中的位置变化 */
        }

       .enemy {
            width: 40px; /*  设置敌机元素的宽度为40像素 */
            height: 40px; /*  设置敌机元素的高度为40像素 */
            background-color: blue; /*  设置敌机的背景颜色为蓝色 */
            position: absolute; /*  绝对定位,方便控制敌机在游戏面板的位置 */
        }

        #score {
            font-size: 24px; /*  设置得分显示的字体大小为24像素 */
            text-align: center; /*  使得分文本在其容器内居中显示 */
        }
    </style>
</head>

<body>
    <div id="game-board">
        <div id="player"></div>
        <div id="score">Score: 0</div>
    </div>
</body>
<script>
    // JavaScript 代码
    
    // 获取游戏面板元素,后续用于操作游戏面板内的各种元素以及获取面板相关属性(如宽高)
    let gameBoard = document.getElementById("game-board");
    // 获取代表玩家飞机的元素,用于控制玩家飞机的位置、样式等操作
    let player = document.getElementById("player");
    // 获取用于显示得分的元素,方便更新得分信息
    let scoreElement = document.getElementById("score");
    
    // 用于存储所有已发射的子弹元素,每个元素都是页面中的一个DOM节点,方便统一管理和操作
    let bullets = [];
    // 用于存储所有出现的敌机元素,同样每个元素是页面中的DOM节点,便于管理敌机的创建、移动和销毁等操作
    let enemies = [];
    // 用于记录玩家的得分,初始化为0,每当击中敌机时会相应增加
    let score = 0;
    
    // 函数用于移动玩家飞机,根据传入的方向参数来改变飞机的水平位置
    function movePlayer(direction) {
        // 获取玩家飞机当前的水平位置(left属性值),如果获取失败(可能是未设置过)则默认为0, parseInt用于将字符串类型的像素值转换为数字类型
        let currentPosition = parseInt(player.style.left) || 0;
    
        if (direction === "left") {
            currentPosition -= 20; // 如果方向是向左,将当前位置减少20像素,实现向左移动
        } else if (direction === "right") {
            currentPosition += 20; // 如果方向是向右,将当前位置增加20像素,实现向右移动
        }
    
        // 限制飞机移动范围在游戏板内,通过 Math.max确保不小于0(游戏板左侧边界),Math.min确保不大于游戏板宽度减去飞机自身宽度(游戏板右侧边界)
        currentPosition = Math.max(0, Math.min(currentPosition, gameBoard.offsetWidth - player.offsetWidth));
    
        player.style.left = currentPosition + "px"; // 更新玩家飞机的水平位置样式属性,将数字转换为带单位的像素值字符串
    }
    
    // 函数用于发射子弹,创建一个新的子弹元素并添加到游戏面板中,同时将其添加到bullets数组进行管理
    function shoot() {
        // 创建一个新的div元素,用于表示子弹
        let bullet = document.createElement("div");
        bullet.className = "bullet"; // 为子弹元素添加对应的类名,以便应用CSS样式
        // 设置子弹的水平位置,使其在玩家飞机的中心位置,减去2.5像素是为了精准居中(因为子弹宽度为5像素)
        bullet.style.left = parseInt(player.style.left) + player.offsetWidth / 2 - 2.5 + "px";
        bullet.style.bottom = player.offsetHeight + "px"; // 设置子弹的垂直位置,在玩家飞机的上方(底部对齐)
        gameBoard.appendChild(bullet); // 将子弹元素添加到游戏面板中,使其在页面上显示出来
        bullets.push(bullet); // 将新创建的子弹元素添加到bullets数组中,方便后续统一管理
    }
    
    // 函数用于移动所有已发射的子弹,更新它们在游戏面板中的垂直位置
    function moveBullets() {
        bullets.forEach((bullet, bulletIndex) => {
            // 获取子弹当前的垂直位置(bottom属性值),如果获取失败则默认为0,同样进行类型转换
            let currentPosition = parseInt(bullet.style.bottom) || 0;
            currentPosition += 10; // 将子弹的垂直位置增加10像素,实现向上移动
    
            if (currentPosition >= gameBoard.offsetHeight) {
                // 如果子弹超出了游戏面板的高度(到达顶部边界),则从页面中移除该子弹元素
                bullet.remove();
                bullets.splice(bulletIndex, 1); // 同时从bullets数组中移除对应的元素,保持数组和页面元素的一致性
            } else {
                bullet.style.bottom = currentPosition + "px"; // 如果未超出边界,更新子弹的垂直位置样式属性
            }
        });
    }
    
    // 函数用于创建一个新的敌机元素,并添加到游戏面板中,同时将其添加到enemies数组进行管理
    function createEnemy() {
        let enemy = document.createElement("div");
        enemy.className = "enemy"; // 为敌机元素添加对应的类名,以便应用CSS样式
        // 设置敌机的水平位置,使其在游戏面板内随机出现(在游戏面板宽度减去敌机自身宽度的范围内随机取值)
        enemy.style.left = Math.random() * (gameBoard.offsetWidth - 40) + "px";
        enemy.style.top = "0px"; // 设置敌机的初始垂直位置在游戏面板顶部
        gameBoard.appendChild(enemy); // 将敌机元素添加到游戏面板中,使其在页面上显示出来
        enemies.push(enemy); // 将新创建的敌机元素添加到enemies数组中,方便后续统一管理
    }
    
    // 函数用于移动所有的敌机,更新它们在游戏面板中的垂直位置,实现敌机向下移动的效果
    function moveEnemies() {
        enemies.forEach((enemy, enemyIndex) => {
            // 获取敌机当前的垂直位置(top属性值),如果获取失败则默认为0,进行类型转换
            let currentPosition = parseInt(enemy.style.top) || 0;
            currentPosition += 5; // 将敌机的垂直位置增加5像素,实现向下移动
    
            if (currentPosition >= gameBoard.offsetHeight) {
                // 如果敌机超出了游戏面板的高度(到达底部边界),则从页面中移除该敌机元素
                enemy.remove();
                enemies.splice(enemyIndex, 1); // 同时从enemies数组中移除对应的元素,保持数组和页面元素的一致性
            } else {
                enemy.style.top = currentPosition + "px"; // 如果未超出边界,更新敌机的垂直位置样式属性
            }
        });
    }
    
    // 函数用于检测子弹与敌机之间是否发生碰撞,如果发生碰撞则进行相应的处理(移除子弹和敌机,增加得分等)
    function detectCollision() {
        bullets.forEach((bullet, bulletIndex) => {
    
            enemies.forEach((enemy, enemyIndex) => {
                // 通过比较子弹和敌机的边界位置来判断是否发生碰撞,检测条件涵盖了上下左右四个方向的位置关系
                if (
                    bullet.offsetTop <= enemy.offsetTop + enemy.offsetHeight &&
                    bullet.offsetTop + bullet.offsetHeight >= enemy.offsetTop &&
                    bullet.offsetLeft <= enemy.offsetLeft + enemy.offsetWidth &&
                    bullet.offsetLeft + bullet.offsetWidth >= enemy.offsetLeft
                ) {
                    bullet.remove(); // 如果发生碰撞,从页面中移除子弹元素
                    bullets.splice(bulletIndex, 1); // 从bullets数组中移除对应的子弹元素
                    enemy.remove(); // 从页面中移除敌机元素
                    enemies.splice(enemyIndex, 1); // 从enemies数组中移除对应的敌机元素
                    score += 10; // 玩家得分增加10分
                    scoreElement.innerHTML = "Score: " + score; // 更新页面上显示的得分信息
                }
            });
        });
    }
    
    // 游戏主循环函数,在每次循环中调用移动子弹、移动敌机和检测碰撞的函数,实现游戏的持续更新和逻辑处理
    function gameLoop() {
        moveBullets();
        moveEnemies();
        detectCollision();
    }
    
    // 函数用于启动游戏,初始化游戏相关的各种状态,包括得分、元素位置、清除已有的子弹和敌机等,并设置定时创建敌机和执行游戏主循环的定时器
    function startGame() {
        score = 0; // 将得分重置为0
        scoreElement.innerHTML = "Score: " + score; // 更新页面上显示的得分信息为0
    
        // 将玩家飞机的水平位置重新设置为游戏面板的水平居中处
        player.style.left = (gameBoard.offsetWidth - player.offsetWidth) / 2 + "px";
    
        // 移除所有已存在的子弹元素,并清空bullets数组
        bullets.forEach(bullet => bullet.remove());
        bullets = [];
    
        // 移除所有已存在的敌机元素,并清空enemies数组
        enemies.forEach(enemy => enemy.remove());
        enemies = [];
    
        // 设置每隔1000毫秒(1秒)创建一个新的敌机,不断增加游戏中的敌机数量,增加游戏难度
        setInterval(createEnemy, 1000);
        // 设置每隔30毫秒执行一次游戏主循环,实现游戏的流畅更新和逻辑处理,控制游戏的帧率
        setInterval(gameLoop, 30);
    }
    
    // 监听键盘按下事件,根据按下的不同按键来执行相应的游戏操作,如移动玩家飞机或发射子弹
    document.addEventListener("keydown", function (event) {
        if (event.code === "ArrowLeft") {
            movePlayer("left"); // 如果按下向左箭头键,调用函数向左移动玩家飞机
        } else if (event.code === "ArrowRight") {
            movePlayer("right"); // 如果按下向右箭头键,调用函数向右移动玩家飞机
        } else if (event.code === "Space") {
            shoot(); // 如果按下空格键,调用函数发射子弹
        }
    });
    
    startGame(); // 启动游戏,开始整个游戏流程
</script>

</html>

运行结果:

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐