前端技术搭建贪吃蛇小游戏(内含源码)

news/2024/11/14 13:20:47/

The sand accumulates to form a pagoda

  • ✨ 写在前面
  • ✨ 功能介绍
  • ✨ 页面搭建
  • ✨ 样式设置
  • ✨ 逻辑部分


✨ 写在前面

上周我们实通过前端基础实现了井字游戏,今天还是继续按照我们原定的节奏来带领大家完成一个贪吃蛇游戏,功能也比较简单简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript在前端中的作用, 在前面的文章当中我们也提及到我们在本系列的专栏是循序渐进从简单到复杂的过程,后续会带领大家用前端实现翻卡片、扫雷等有趣的小游戏,纯前端语言实现,都会陆续带给大家。欢迎大家订阅我们这份前端小游戏的专栏。订阅链接:https://blog.csdn.net/jhxl_/category_12261013.html


✨ 功能介绍

以下是贪吃蛇小游戏的玩法和规则:游戏开始时,玩家控制一条小蛇在游戏区域内移动,通过吃食物来增加分数。小蛇的移动方向由玩家控制,可以使用键盘上的方向键来控制小蛇的移动方向。当小蛇吃到食物时,它会变长,并且玩家的分数会增加。如果小蛇撞到了游戏区域的边界或者自己的身体,游戏结束。

在这里插入图片描述

游戏区域内会随机生成食物,玩家需要控制小蛇吃到食物来增加分数。小蛇的身体会随着吃到的食物变长,玩家需要注意控制小蛇的移动方向,避免撞到自己的身体。游戏难度会逐渐增加,小蛇的移动速度会变快,玩家需要更加灵活地控制小蛇的移动方向。玩家可以通过吃到特殊的食物来获得额外的分数或者特殊能力,例如加速或者减速小蛇的移动速度。游戏结束后,玩家可以查看自己的得分,并且可以选择重新开始游戏或者退出游戏。希望这些规则能够帮助您了解贪吃蛇小游戏的玩法和规则。如果您有任何其他问题,可以随时联系我。


✨ 页面搭建

创建文件

首先呢我们创建我们的HTML文件,这里我就直接命名为 贪吃蛇.html 了,大家可以随意命名, 文件创建生成后我们通过编辑器打开,这里我用的是VScode, 然后初始化我们的代码结构,那在这里告诉大家一个快捷键,就是我们敲上我们英文的一个 ! 我们敲击回车直接就会给我们生成基础版本的前端代码结构。

在这里插入图片描述

文档声明和编码设置: 在HTML文档的头部,使用<!DOCTYPE>声明HTML文档类型,确保浏览器以正确的方式渲染网页内容。同时,设置UTF-8编码,以确保浏览器能够正确地解析和显示中文字符。下面我就开始搭建我们的DOM结构了!

DOM结构搭建

这段代码是贪吃蛇小游戏的DOM结构代码,它包含了游戏的各个元素和界面布局。具体来说:

<p>贪吃蛇</p>:这是一个段落元素,用于显示游戏的标题。<div class="gamBox">:这是一个div元素,用于包裹整个游戏界面。<div class="screen">:这是一个div元素,用于显示游戏区域。<div class="snake">:这是一个div元素,用于显示贪吃蛇。<div class="snake-head">:这是一个div元素,用于显示贪吃蛇的头部。<span>😡</span>:这是一个span元素,用于显示贪吃蛇头部的表情。<div class="snake-body">:这是一个div元素,用于显示贪吃蛇的身体。<div class="food">:这是一个div元素,用于显示食物。<span>🐷</span>:这是一个span元素,用于显示食物的图标。<div class="integral">:这是一个div元素,用于显示游戏的积分信息。<div>等级(grade)<span class="grade"></span></div>:这是一个div元素,用于显示游戏的等级信息。<div>分数(score)<span class="score"></span></div>:这是一个div元素,用于显示游戏的分数信息。

<body><p>贪吃蛇</p><div class="gamBox"><div class="screen"><div class="snake"><div class="snake-head"><span>😡</span></div><div class="snake-body"></div></div><div class="food"><span>🐷</span></div></div><div class="integral"><div>等级(grade)<span class="grade"></span></div><div>分数(score)<span class="score"></span></div></div></div></body>

在这里插入图片描述


✨ 样式设置

我们看到了上面的的DOM已经搭建好了,但是页面什么都看不出来,下面我们简单的来配置一下样式吧,其实我们本专栏也是想带领大家掌握一些逻辑所以样式方面我们就一切从简;

*:设置所有元素的样式。margin: 0;和padding: 0;:将所有元素的外边距和内边距设置为0。box-sizing: border-box;:将元素的盒模型设置为border-box。p:设置段落元素的样式。text-align: center;:将段落元素的文本居中对齐。font-size: 23px;和font-weight: 600;:设置段落元素的字体大小和字体粗细。.gamBox:设置游戏界面的样式,包括宽度、高度、边框、背景颜色、圆角、布局等。.integral:设置游戏积分信息的样式,包括宽度、高度、布局、字体大小、字体粗细等。.screen:设置游戏区域的样式,包括宽度、高度、边框、位置等。.snake:设置贪吃蛇的样式,包括头部和身体的样式。.food:设置食物的样式,包括宽度、高度、字体大小、位置等。

<style>* {margin: 0;padding: 0;box-sizing: border-box;}p {text-align: center;font-size: 23px;font-weight: 600;}.gamBox {width: 500px;height: 500px;border: 10px solid #393c1b;margin: 20px auto;background-color: #b6b327;border-radius: 20px;display: flex;flex-direction: column;justify-content: space-around;align-items: center;}/* //下方等级、得分盒子/ */.integral {width: 398px;height: 25px;display: flex;justify-content: space-between;font-size: 16px;font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande","Lucida Sans", Arial, sans-serif;font-weight: 700;}/* //屏幕样式 */.screen {width: 400px;height: 400px;border: 1px solid #000;position: relative;}/* //蛇的样式 */.snake .snake-head {width: 20px;height: 20px;border: 1px solid #4d7d2b;background-color: #000;position: absolute;top: 0;left: 0;}.snake span {font-size: 17px;position: absolute;left: -2.7px;top: -3px;}.snake-body>div {position: absolute;top: 0;left: 0;width: 20px;height: 20px;border: 1px solid #4d7d2b;background-color: #000;}/* //食物的样式 */.food {width: 20px;height: 20px;font-size: 8px;text-align: left;position: absolute;top: 10px;left: 0;}.food span {font-size: 17px;position: absolute;left: -1.7px;top: -2px;}
</style>

在这里插入图片描述

✨ 逻辑部分

上面我们搭建了基本的样式,下面呢我们就通过js代码,实现我们游戏的功能吧,下面是对代码的简化解释:

  • foundationNumber:基础倍数,用于移动和食物随机位置计算。
  • maxGrade:最大等级。

以下是函数的作用:

  • randomNumber(min, max):生成指定范围内的随机整数。
  • changeFoodSeat():改变食物的位置。
  • changeScore():改变分数和等级。
  • handleWatchEnter(e):处理按键事件,控制蛇的移动和吃食物。
  • throttle(fn, wait):函数节流,用于控制蛇的移动速度。
  • init():初始化游戏,设置初始状态和界面。

以下是变量的作用:

  • direction:蛇的移动方向。
  • snakeLength:蛇身体的长度数组。
  • snakeSeat:蛇头的位置。
  • foodSeat:食物的位置。
  • register:存储分数和等级的对象。

在页面加载完成后,监听键盘按下事件,根据按键改变移动方向。然后调用 init 函数初始化游戏。在 init 函数中,设置蛇头位置,清空蛇身体,显示等级和分数,改变食物位置,并调用 handleWatchEnter 函数开始处理蛇的移动。在 handleWatchEnter 函数中,根据移动方向更新蛇身体的位置,判断是否吃到食物并处理相关逻辑,检测是否碰到墙壁或自身,更新蛇头位置,最后通过递归调用自身实现连续移动。整体代码实现了贪吃蛇游戏的逻辑,包括蛇的移动、食物的生成和吃食物的判定,以及游戏结束的条件判断。

<script>/**** 公用变量* @foundationNumber 基础倍数:移动、食物随机位置量的倍数* @maxGrade 最大的等级*/const foundationNumber = 20const maxGrade = 10/**** 食物相关*/const randomNumber = (min, max) => {return Math.floor(Math.random() * (max - min)) + min}let foodSeat = {top: 20,left: 20}const changeFoodSeat = () => {foodSeat.top = randomNumber(0, 20) * foundationNumberfoodSeat.left = randomNumber(0, 20) * foundationNumberdocument.querySelector('.food').style.cssText = 'left:' + foodSeat.left + 'px;top:' + foodSeat.top + 'px'}/**** 等级、分数相关*/let register = {score: 0,grade: 1}const changeScore = () => {register.score++if (register.grade < 10) {register.grade = Math.ceil(register.score / 10)}document.querySelector('.grade').innerText = register.gradedocument.querySelector('.score').innerText = register.score}/**** 蛇相关*/let direction = ''//移动方向let snakeLength = []let snakeSeat = {top: 0,left: 0}const handleWatchEnter = e => {let previousTop = snakeSeat.toplet previousLeft = snakeSeat.left//通过便利每个身体部分来进行移动snakeLength.forEach((ele, index) => {let temporaryTop = ele.toplet temporaryLeft = ele.leftele.top = previousTopele.left = previousLeftpreviousTop = temporaryToppreviousLeft = temporaryLeftdocument.querySelectorAll('.snake-body>div')[index].style.cssText = 'left:' + ele.left + 'px;top:' + ele.top + 'px'});switch (direction) {case 'ArrowUp':snakeSeat.top -= 20break;case 'ArrowLeft':snakeSeat.left -= 20break;case 'ArrowRight':snakeSeat.left += 20break;case 'ArrowDown':snakeSeat.top += 20break;}if (snakeSeat.top == foodSeat.top && snakeSeat.left == foodSeat.left) {changeScore()changeFoodSeat()snakeLength.push({top: previousTop,left: previousLeft})var div = document.createElement('div');div.style.left = previousLeft + 'px';div.style.top = previousTop + 'px';div.class = 'bodyItem'document.querySelector('.snake-body').appendChild(div)}if (snakeSeat.top < 0 || snakeSeat.left < 0 || snakeSeat.left > 380 || snakeSeat.top > 380) {alert('撞墙身亡')snakeSeat.top = 0snakeSeat.left = 0direction = ''snakeLength = []init()return}let bodySeats = snakeLength.map(item => JSON.stringify(item))if ((bodySeats.indexOf(JSON.stringify({ top: snakeSeat.top, left: snakeSeat.left })) != -1)) {alert('把自己撞死了')snakeSeat.top = 0snakeSeat.left = 0snakeLength = []direction = ''init()return}document.querySelector('.snake-head').style.cssText = 'left:' + snakeSeat.left + 'px;top:' + snakeSeat.top + 'px'setTimeout(() => {handleWatchEnter()}, 400 - (register.grade - 1) * 15);}//函数节流const throttle = (fn, wait) => {var timer = null;return function () {var _this = this;var args = arguments;if (!timer) {timer = setTimeout(function () {fn.apply(_this, args);timer = null;}, wait);}}}const init = () => {document.querySelector('.snake-head').style.cssText = 'left:' + 0 + 'px;top:' + 0 + 'px'document.querySelector('.snake-body').innerHTML = ""document.querySelector('.grade').innerText = register.gradedocument.querySelector('.score').innerText = register.scorechangeFoodSeat()handleWatchEnter()}document.addEventListener('keydown', (e) => {if ((e.code == 'ArrowUp' && direction != 'ArrowDown') || (e.code == 'ArrowLeft' && direction != 'ArrowRight') || (e.code == 'ArrowRight' && direction != 'ArrowLeft') || (e.code == 'ArrowDown' && direction != 'ArrowUp')) {direction = e.code}});init()</script>

完整代码


<!-- Author profile:欢迎您朋友,感谢你的认可,我是几何心凉CSDN博客专家、内容合伙人、新星计划导师,Vue技能树构建者、阿里云社区专家博主,前端领域优质创作者致力于新技术的推广与优秀技术的普及。可提供简历、就业指导服务CSDN博客:https://blog.csdn.net/JHXL_公众号:#几何心凉的核心圈--><!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>凉哥的简易版贪吃蛇</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}p {text-align: center;font-size: 23px;font-weight: 600;}.gamBox {width: 500px;height: 500px;border: 10px solid #393c1b;margin: 20px auto;background-color: #b6b327;border-radius: 20px;display: flex;flex-direction: column;justify-content: space-around;align-items: center;}/* //下方等级、得分盒子/ */.integral {width: 398px;height: 25px;display: flex;justify-content: space-between;font-size: 16px;font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande","Lucida Sans", Arial, sans-serif;font-weight: 700;}/* //屏幕样式 */.screen {width: 400px;height: 400px;border: 1px solid #000;position: relative;}/* //蛇的样式 */.snake .snake-head {width: 20px;height: 20px;border: 1px solid #4d7d2b;background-color: #000;position: absolute;top: 0;left: 0;}.snake span {font-size: 17px;position: absolute;left: -2.7px;top: -3px;}.snake-body>div {position: absolute;top: 0;left: 0;width: 20px;height: 20px;border: 1px solid #4d7d2b;background-color: #000;}/* //食物的样式 */.food {width: 20px;height: 20px;font-size: 8px;text-align: left;position: absolute;top: 10px;left: 0;}.food span {font-size: 17px;position: absolute;left: -1.7px;top: -2px;}</style>
</head><body><p>贪吃蛇</p><div class="gamBox"><div class="screen"><div class="snake"><div class="snake-head"><span>😡</span></div><div class="snake-body"></div></div><div class="food"><span>🐷</span></div></div><div class="integral"><div>等级(grade)<span class="grade"></span></div><div>分数(score)<span class="score"></span></div></div></div></body><script>/**** 公用变量* @foundationNumber 基础倍数:移动、食物随机位置量的倍数* @maxGrade 最大的等级*/const foundationNumber = 20const maxGrade = 10/**** 食物相关*/const randomNumber = (min, max) => {return Math.floor(Math.random() * (max - min)) + min}let foodSeat = {top: 20,left: 20}const changeFoodSeat = () => {foodSeat.top = randomNumber(0, 20) * foundationNumberfoodSeat.left = randomNumber(0, 20) * foundationNumberdocument.querySelector('.food').style.cssText = 'left:' + foodSeat.left + 'px;top:' + foodSeat.top + 'px'}/**** 等级、分数相关*/let register = {score: 0,grade: 1}const changeScore = () => {register.score++if (register.grade < 10) {register.grade = Math.ceil(register.score / 10)}document.querySelector('.grade').innerText = register.gradedocument.querySelector('.score').innerText = register.score}/**** 蛇相关*/let direction = ''//移动方向let snakeLength = []let snakeSeat = {top: 0,left: 0}const handleWatchEnter = e => {let previousTop = snakeSeat.toplet previousLeft = snakeSeat.left//通过便利每个身体部分来进行移动snakeLength.forEach((ele, index) => {let temporaryTop = ele.toplet temporaryLeft = ele.leftele.top = previousTopele.left = previousLeftpreviousTop = temporaryToppreviousLeft = temporaryLeftdocument.querySelectorAll('.snake-body>div')[index].style.cssText = 'left:' + ele.left + 'px;top:' + ele.top + 'px'});switch (direction) {case 'ArrowUp':snakeSeat.top -= 20break;case 'ArrowLeft':snakeSeat.left -= 20break;case 'ArrowRight':snakeSeat.left += 20break;case 'ArrowDown':snakeSeat.top += 20break;}if (snakeSeat.top == foodSeat.top && snakeSeat.left == foodSeat.left) {changeScore()changeFoodSeat()snakeLength.push({top: previousTop,left: previousLeft})var div = document.createElement('div');div.style.left = previousLeft + 'px';div.style.top = previousTop + 'px';div.class = 'bodyItem'document.querySelector('.snake-body').appendChild(div)}if (snakeSeat.top < 0 || snakeSeat.left < 0 || snakeSeat.left > 380 || snakeSeat.top > 380) {alert('撞墙身亡')snakeSeat.top = 0snakeSeat.left = 0direction = ''snakeLength = []init()return}let bodySeats = snakeLength.map(item => JSON.stringify(item))if ((bodySeats.indexOf(JSON.stringify({ top: snakeSeat.top, left: snakeSeat.left })) != -1)) {alert('把自己撞死了')snakeSeat.top = 0snakeSeat.left = 0snakeLength = []direction = ''init()return}document.querySelector('.snake-head').style.cssText = 'left:' + snakeSeat.left + 'px;top:' + snakeSeat.top + 'px'setTimeout(() => {handleWatchEnter()}, 400 - (register.grade - 1) * 15);}//函数节流const throttle = (fn, wait) => {var timer = null;return function () {var _this = this;var args = arguments;if (!timer) {timer = setTimeout(function () {fn.apply(_this, args);timer = null;}, wait);}}}const init = () => {document.querySelector('.snake-head').style.cssText = 'left:' + 0 + 'px;top:' + 0 + 'px'document.querySelector('.snake-body').innerHTML = ""document.querySelector('.grade').innerText = register.gradedocument.querySelector('.score').innerText = register.scorechangeFoodSeat()handleWatchEnter()}document.addEventListener('keydown', (e) => {if ((e.code == 'ArrowUp' && direction != 'ArrowDown') || (e.code == 'ArrowLeft' && direction != 'ArrowRight') || (e.code == 'ArrowRight' && direction != 'ArrowLeft') || (e.code == 'ArrowDown' && direction != 'ArrowUp')) {direction = e.code}});init()</script></html>

本期推荐

原创不易,还希望各位大佬支持一下 \textcolor{blue}{原创不易,还希望各位大佬支持一下} 原创不易,还希望各位大佬支持一下

👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!

⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!

✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!


http://www.ppmy.cn/news/101123.html

相关文章

ChatGPT 与我合力开发 xargin blog archive 插件:曹大博客的新奇探险

之前写的批量删除 chatGPT 对话的插件[1]&#xff0c;最近我收到了一个五星好评&#xff1a; 虽然不赚钱&#xff0c;交个朋友嘛&#xff0c;还是挺高兴的。而且借助 chatGPT&#xff0c;我是在与全世界的用户交流&#xff0c;想想就激动。 最近我发现自己让 chatGPT 帮忙写前端…

【JavaSE】Java基础语法(二十八):HashSet集合

文章目录 1. HashSet集合概述和特点2. HashSet集合的基本应用3. 哈希值4. HashSet集合存储学生对象并遍历【应用】 1. HashSet集合概述和特点 底层数据结构是哈希表存取无序不可以存储重复元素没有索引,不能使用普通for循环遍历 2. HashSet集合的基本应用 存储字符串并遍历 …

linux系统使用HTTP代理方法

在Linux系统中使用HTTP代理方法&#xff0c;可以通过设置环境变量来实现。具体步骤如下&#xff1a; 1. 打开终端&#xff0c;输入以下命令&#xff1a; export http_proxyhttp://代理服务器IP地址:端口号 其中&#xff0c;代理服务器IP地址和端口号需要替换成你所使用的代理…

84.Rem和max-width如何工作

max-width 首先我们先看普通的width是什么样的效果&#xff01; 首先给个测试的div <div class"test">TEST</div>● 然后CSS给定一个宽度 .test {width: 1000px;background-color: red;padding: 100px; }如上图&#xff0c;不管你的浏览器窗口如何改变…

【优化调度】基于改进遗传算法的公交车调度排班优化的研究与实现(Matlab代码实现)

目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 1 概述 本文对当前公交企业调度系统进行了分析&#xff0c;建立了公交排班的数学模型。本文基于数据挖掘分析的结果上&#xff0c;使用截面客流量数据对模型进行约束&#xff0c;得出了公交客流出行的空间分布规律。再以…

分享几封好用的外贸人催单模版

给外贸人说在前面&#xff1a; 虽然说是催单模版&#xff0c;但是请带入你们公司产品&#xff0c;你们客户具体情况来套入&#xff0c;不能一模一样&#xff0c;再好的模版&#xff0c;再好的话术&#xff0c;大家一起用&#xff0c;就成了毫无价值的废料。 请灵活运用&#…

c# cad 二次开发 类库 块的操作

c# cad 二次开发 类库 块的操作 using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System; using System.Collections.G…

Linux之进程地址空间

文章目录 前言一、是什么1.例子2.感性的理解虚拟地址空间3.现象的具体解释4.写时拷贝 二、为什么三、怎么办总结 前言 内存区域划分&#xff1a; 在学习C/C时我们都有接触过内存区域划分这个概念&#xff0c;也知道它表示的是程序加载到内存中不同的数据所分布的不同的区域&a…