The sand accumulates to form a pagoda
- ✨ 写在前面
- ✨ 功能介绍
- ✨ 页面搭建
- ✨ 样式设置
- ✨ 逻辑部分
✨ 写在前面
上周我们实通过前端基础实现了弹珠游戏,当然很多伙伴再评论区提出了想法,后续我们会考虑实现的,今天还是继续按照我们原定的节奏来带领大家完成一个飞机大战游戏,功能也比较简单简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循序渐进从简单到复杂的过程,后续会带领大家用前端实现翻卡片、扫雷、贪吃蛇等有趣的小游戏,纯前端语言实现,都会陆续带给大家。欢迎大家订阅我们这份前端小游戏的专栏。
✨ 功能介绍
飞机射击游戏是一款经典的射击游戏,让你化身为一名勇敢的飞行员,驾驶着一架战斗机,与敌机展开激烈的空中战斗。你的任务是摧毁敌机并尽可能获得高分。准备好挑战吧!控制飞机移动: 使用键盘上的左右箭头键来控制飞机左右移动,躲避敌机的攻击。发射子弹: 按下空格键发射子弹,瞄准并摧毁敌机。摧毁敌机: 当你的子弹与敌机发生碰撞时,敌机将被击中并炸毁,你将获得分数。注意躲避: 避免敌机的攻击,不要让敌机碰撞到你的飞机,否则游戏结束(这个功能留给大家实现哦)实时分数: 游戏界面会实时显示你的得分,挑战自己,争取创造最高分数。
准备好了吗?驾驶你的战斗机,击败所有敌人,成为空中的王者吧!当然你也可以通过修改游戏的参数来控制难度等级!
✨ 页面搭建
创建文件
首先呢我们创建我们的HTML文件,这里我就直接命名为 飞机大战.html
了,大家可以随意命名, 文件创建生成后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码结构,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 !
我们敲击回车直接就会给我们生成基础版本的前端代码结构。
文档声明和编码设置: 在HTML文档的头部,使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。下面我就开始搭建我们的DOM结构了!
DOM结构搭建
-
<div id="game-board">
:这是游戏的主要容器,包含了游戏中的所有元素,如玩家飞机、敌机和得分信息。 -
<div id="player">
:这是表示玩家飞机的元素,玩家将控制它来躲避敌机的攻击并射击敌机。 -
<div id="score">
:这是显示玩家得分的元素,初始值为 0,玩家击败敌机后,得分将实时更新并显示在这个元素中。
这段代码是游戏界面的基础结构,它创建了一个游戏板,包含了玩家飞机和得分信息,为游戏提供了一个可视化的界面。玩家将在这个界面上操控飞机,与敌机进行激烈的空战,尽可能地躲避敌机的攻击并击败敌机,以获得更高的得分。
<div id="game-board">
<div id="player"></div>
<div id="score">Score: 0</div>
</div>
✨ 样式设置
我们看到了上面的的DOM已经搭建好了,但是很显然样式比较随意了,我们简单的来配置一下样式吧,其实我们本专栏也是想带领大家掌握一些逻辑所以样式方面我们就一切从简;
-
#game-board
:定义游戏板的样式,设置了宽度、高度和边框,并将其定位为相对位置,并通过margin: 0 auto;
使其水平居中显示。 -
#player
:定义玩家飞机的样式,设置了宽度、高度和背景颜色。使用绝对定位,将其置于游戏板底部,并通过left: 50%; transform: translateX(-50%);
使其水平居中显示。 -
.bullet
:定义子弹的样式,设置了宽度、高度和背景颜色。使用绝对定位,用于表示玩家飞机发射的子弹。 -
.enemy
:定义敌机的样式,设置了宽度、高度和背景颜色。使用绝对定位,用于表示敌机。 -
#score
:定义得分信息的样式,设置了字体大小和居中对齐。
这段代码主要是为游戏界面中的各个元素定义了基本的样式,包括游戏板、玩家飞机、子弹和敌机。通过设置不同的样式,使得这些元素在游戏界面中能够以合适的尺寸和颜色进行显示,提供了良好的可视化效果,让玩家能够清晰地辨别游戏中的各个元素。
<style>
/* CSS 样式 */
#game-board {
width: 480px;
height: 500px;
border: 1px solid black;
position: relative;
margin: 0 auto;
}
#player {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.bullet {
width: 5px;
height: 20px;
background-color: black;
position: absolute;
}
.enemy {
width: 40px;
height: 40px;
background-color: blue;
position: absolute;
}
#score {
font-size: 24px;
text-align: center;
}
</style>
✨ 逻辑部分
上面我们搭建了基本的样式,下面呢我们就通过js代码,实现我们游戏的功能吧;首先,我们定义了一些变量:
gameBoard
:代表游戏板的 DOM 元素。
player
:代表玩家飞机的 DOM 元素。
scoreElement
:代表显示分数的 DOM 元素。
bullets
:用于存储子弹的数组。
enemies
:用于存储敌机的数组。
score
:表示当前的分数。
movePlayer(direction)
函数:用于移动玩家飞机的位置。根据传入的参数 direction
来判断向左还是向右移动,然后更新玩家飞机的位置。 shoot()
函数:用于发射子弹。创建一个子弹的 DOM 元素,设置其位置,并将其添加到游戏板中和 bullets
数组中。 moveBullets()
函数:用于移动子弹。遍历 bullets
数组中的每个子弹,更新其位置。如果子弹超出了游戏板的高度,则将其移除。 createEnemy()
函数:用于创建敌机。创建一个敌机的 DOM 元素,设置其位置,并将其添加到游戏板中和 enemies
数组中。
moveEnemies()
函数:用于移动敌机。遍历 enemies
数组中的每个敌机,更新其位置。如果敌机超出了游戏板的高度,则将其移除。 detectCollision()
函数:用于检测碰撞。遍历子弹和敌机数组,判断是否发生了碰撞。如果碰撞发生,则移除相应的子弹和敌机,并增加分数。 gameLoop()
函数:游戏循环函数,用于持续更新子弹、敌机的位置,并检测碰撞。startGame()
函数:游戏开始函数,用于初始化游戏状态,包括重置分数、玩家飞机位置,清空子弹和敌机数组,以及设置定时器调用 createEnemy
和 gameLoop
函数。
监听键盘事件,当按下箭头左键时调用 movePlayer("left")
,按下箭头右键时调用movePlayer("right")
,按下空格键时调用 shoot()
。 最后,调用 startGame()
函数来启动游戏。通过这些函数和事件监听,游戏可以实现玩家飞机的移动、子弹的发射、敌机的创建和移动,以及碰撞的检测和分数的更新。玩家需要使用箭头键控制飞机移动,通过发射子弹来摧毁敌机,并且在游戏循环中持续检测碰撞和更新分数。游戏的目标是尽可能地摧毁更多的敌机,获得高分。
<script>
// JavaScript 代码
let gameBoard = document.getElementById("game-board");
let player = document.getElementById("player");
let scoreElement = document.getElementById("score");
let bullets = [];
let enemies = [];
let score = 0;
function movePlayer(direction) {
let currentPosition = parseInt(player.style.left) || 0;
if (direction === "left") {
currentPosition -= 20;
} else if (direction === "right") {
currentPosition += 20;
}
// 限制飞机移动范围在游戏板内
currentPosition = Math.max(0, Math.min(currentPosition, gameBoard.offsetWidth - player.offsetWidth));
player.style.left = currentPosition + "px";
}
function shoot() {
let bullet = document.createElement("div");
bullet.className = "bullet";
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);
}
function moveBullets() {
bullets.forEach((bullet, bulletIndex) => {
let currentPosition = parseInt(bullet.style.bottom) || 0;
currentPosition += 10;
if (currentPosition >= gameBoard.offsetHeight) {
bullet.remove();
bullets.splice(bulletIndex, 1);
} else {
bullet.style.bottom = currentPosition + "px";
}
});
}
function createEnemy() {
let enemy = document.createElement("div");
enemy.className = "enemy";
enemy.style.left = Math.random() * (gameBoard.offsetWidth - 40) + "px";
enemy.style.top = "0px";
gameBoard.appendChild(enemy);
enemies.push(enemy);
}
function moveEnemies() {
enemies.forEach((enemy, enemyIndex) => {
let currentPosition = parseInt(enemy.style.top) || 0;
currentPosition += 5;
if (currentPosition >= gameBoard.offsetHeight) {
enemy.remove();
enemies.splice(enemyIndex, 1);
} 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);
enemy.remove();
enemies.splice(enemyIndex, 1);
score += 10;
scoreElement.innerHTML = "Score: " + score;
}
});
});
} function gameLoop() {
moveBullets();
moveEnemies();
detectCollision();
}
function startGame() {
score = 0;
scoreElement.innerHTML = "Score: " + score;
player.style.left = (gameBoard.offsetWidth - player.offsetWidth) / 2 + "px";
bullets.forEach(bullet => bullet.remove());
bullets = [];
enemies.forEach(enemy => enemy.remove());
enemies = [];
setInterval(createEnemy, 1000);
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>
完整代码
<!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;
height: 500px;
border: 1px solid black;
position: relative;
margin: 0 auto;
}
#player {
width: 50px;
height: 50px;
background-color: red;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.bullet {
width: 5px;
height: 20px;
background-color: black;
position: absolute;
}
.enemy {
width: 40px;
height: 40px;
background-color: blue;
position: absolute;
}
#score {
font-size: 24px;
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");
let bullets = [];
let enemies = [];
let score = 0;
function movePlayer(direction) {
let currentPosition = parseInt(player.style.left) || 0;
if (direction === "left") {
currentPosition -= 20;
} else if (direction === "right") {
currentPosition += 20;
}
// 限制飞机移动范围在游戏板内
currentPosition = Math.max(0, Math.min(currentPosition, gameBoard.offsetWidth - player.offsetWidth));
player.style.left = currentPosition + "px";
}
function shoot() {
let bullet = document.createElement("div");
bullet.className = "bullet";
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);
}
function moveBullets() {
bullets.forEach((bullet, bulletIndex) => {
let currentPosition = parseInt(bullet.style.bottom) || 0;
currentPosition += 10;
if (currentPosition >= gameBoard.offsetHeight) {
bullet.remove();
bullets.splice(bulletIndex, 1);
} else {
bullet.style.bottom = currentPosition + "px";
}
});
}
function createEnemy() {
let enemy = document.createElement("div");
enemy.className = "enemy";
enemy.style.left = Math.random() * (gameBoard.offsetWidth - 40) + "px";
enemy.style.top = "0px";
gameBoard.appendChild(enemy);
enemies.push(enemy);
}
function moveEnemies() {
enemies.forEach((enemy, enemyIndex) => {
let currentPosition = parseInt(enemy.style.top) || 0;
currentPosition += 5;
if (currentPosition >= gameBoard.offsetHeight) {
enemy.remove();
enemies.splice(enemyIndex, 1);
} 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);
enemy.remove();
enemies.splice(enemyIndex, 1);
score += 10;
scoreElement.innerHTML = "Score: " + score;
}
});
});
} function gameLoop() {
moveBullets();
moveEnemies();
detectCollision();
}
function startGame() {
score = 0;
scoreElement.innerHTML = "Score: " + score;
player.style.left = (gameBoard.offsetWidth - player.offsetWidth) / 2 + "px";
bullets.forEach(bullet => bullet.remove());
bullets = [];
enemies.forEach(enemy => enemy.remove());
enemies = [];
setInterval(createEnemy, 1000);
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>
本期推荐
✨
原创不易,还希望各位大佬支持一下
\textcolor{blue}{原创不易,还希望各位大佬支持一下}
原创不易,还希望各位大佬支持一下👍
点赞,你的认可是我创作的动力!
\textcolor{green}{点赞,你的认可是我创作的动力!}
点赞,你的认可是我创作的动力!⭐️
收藏,你的青睐是我努力的方向!
\textcolor{green}{收藏,你的青睐是我努力的方向!}
收藏,你的青睐是我努力的方向!✏️
评论,你的意见是我进步的财富!
\textcolor{green}{评论,你的意见是我进步的财富!}
评论,你的意见是我进步的财富!