【前端|JS实战第1篇】使用JS来实现属于自己的贪吃蛇游戏!

在这里插入图片描述

前言

贪吃蛇游戏是经典的小游戏,也是学习前端JS的一个很好的练习项目。在本教程中,我们将使用 JavaScript 来逐步构建一个贪吃蛇游戏。我们会从创建游戏区域开始,逐步添加蛇的移动、食物的生成以及游戏逻辑等功能。


🚀 作者简介:程序员小豪,全栈工程师,热爱编程,曾就职于蔚来、腾讯,现就职于某互联网大厂,技术栈:Vue、React、Python、Java
🎈 本文收录于小豪的前端系列专栏,后续还会更新前端入门以及前端面试的一些相关文章,手把手带你从零学习前端到面试找工作,并如果有想进入前端领域工作的同学,这个前端专栏会对你有所帮助,欢迎关注起来呀
🌼 本人也会持续的去关注AIGC以及人工智能领域的一些动向并总结到博客中,大家感兴趣的可以关注一下我的人工智能专栏
🌊 云原生的入门学习系列,大家有兴趣的可以看一看

步骤1:创建文件

我们需要创建三个文件index.htmlstyles.cssscript.js,index.html用于放置我们界面dom,styles.css用于开发样式,script.js用于放置实现贪吃蛇的逻辑。
在这里插入图片描述

步骤2:创建游戏区域

首先,我们需要一个游戏区域来展示游戏。在 HTML 文件中创建一个

元素,用于表示游戏区域。然后,使用 CSS 来设置该元素的样式,使其成为一个矩形的游戏画布。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>贪吃蛇游戏</title><link rel="stylesheet" href="styles.css">
</head>
<body><div class="game-area"></div><script src="script.js"></script>
</body>
</html>
/* styles.css */
.game-area {width: 400px;height: 400px;border: 2px solid #000;
}

可以看到,我们在styles.css设置了这个游戏区域的宽度和高度为400px,还设置了一个2px的黑色边框
在这里插入图片描述

步骤3:初始化蛇的位置

在 script.js 文件中,我们将初始化蛇的初始位置。定义一个表示蛇身的数组,每个元素代表蛇的一个部分,然后设置蛇的初始位置。

// script.js
const gameArea = document.querySelector('.game-area');
const snake = [{ x: 2, y: 2 }]; // 初始位置// 初始化蛇的位置
function initializeSnake() {snake.forEach(segment => {const snakeSegment = document.createElement('div');snakeSegment.classList.add('snake');snakeSegment.style.left = segment.x * 20 + 'px';snakeSegment.style.top = segment.y * 20 + 'px';gameArea.appendChild(snakeSegment);});
}initializeSnake();
/* styles.css */
.snake {width: 20px;height: 20px;background-color: green;position: absolute;

知识点:

  • document.querySelector('.game-area')用于获取游戏区域的整个dom
  • 蛇的身体我们用一个数组来实现,每一截区域都有一个坐标
  • 我们根据snake这个数组用document.createElement('div')给蛇的每一截身体渲染一个div元素
  • 在styles.css里使用background-color: green;将蛇的身体设置为绿色
  • 在styles.css里使用position: absolute;设置蛇的每一截取的身体为绝对定位。然后通过js设置每一截身体的dom的lefttop,从而设置其位置
    在这里插入图片描述

步骤3:移动蛇

接下来,我们将实现蛇的移动功能。我们会添加一个监听键盘事件,当玩家按下方向键时,蛇将根据所选择的方向移动。

// script.js
let direction = "right"; // 初始方向document.addEventListener("keydown", (event) => {if (event.key === "ArrowUp" && direction !== "down") {direction = "up";} else if (event.key === "ArrowDown" && direction !== "up") {direction = "down";} else if (event.key === "ArrowLeft" && direction !== "right") {direction = "left";} else if (event.key === "ArrowRight" && direction !== "left") {direction = "right";}
});function moveSnake() {const head = { x: snake[0].x, y: snake[0].y };console.log(direction);// 根据方向更新蛇头位置if (direction === "up") {head.y--;} else if (direction === "down") {head.y++;} else if (direction === "left") {head.x--;} else if (direction === "right") {head.x++;}console.log(head);// 更新蛇的位置snake.unshift(head);// 移除蛇尾const removedSegment = snake.pop();// 更新蛇身的样式const newHead = document.createElement("div");newHead.classList.add("snake");newHead.style.left = head.x * 20 + "px";newHead.style.top = head.y * 20 + "px";gameArea.insertBefore(newHead, gameArea.firstChild);// 移除蛇尾的样式if (removedSegment) {const elementsToDelete = document.querySelectorAll(".snake");if (elementsToDelete.length > 0) {const lastElement = elementsToDelete[elementsToDelete.length - 1];gameArea.removeChild(lastElement);}}
}setInterval(moveSnake, 1000); // 每1000毫秒移动一次

在这个步骤中,我们使用了定时器来连续地移动蛇。通过按下方向键,你可以控制蛇的移动方向。

这里我们通过 gameArea.insertBefore(newHead, gameArea.firstChild);在gameArea的子节点的最前面插入一个新的节点,并通过gameArea.removeChild(lastElement);删除最后一个子节点。

最后,通过以下代码,来监听按键行为,来控制贪吃蛇前进方向:

document.addEventListener("keydown", (event) => {if (event.key === "ArrowUp" && direction !== "down") {direction = "up";} else if (event.key === "ArrowDown" && direction !== "up") {direction = "down";} else if (event.key === "ArrowLeft" && direction !== "right") {direction = "left";} else if (event.key === "ArrowRight" && direction !== "left") {direction = "right";}
});

在这里插入图片描述

步骤4:生成食物
接下来,我们将实现食物的生成功能。每当蛇吃掉食物后,我们将随机生成一个新的食物位置。

// script.js
let food = { x: 5, y: 5 }; // 初始食物位置function generateFood() {let foodItem = document.querySelectorAll(".food");if (foodItem.length >= 1) {gameArea.removeChild(foodItem[0]);}food.x = Math.floor(Math.random() * 20); // 随机生成 x 坐标food.y = Math.floor(Math.random() * 20); // 随机生成 y 坐标if (food.x <= 0) {food.x = 1;} else if (food.x >= 20) {food.x = 19;}if (food.y <= 0) {food.y = 1;} else if (food.y >= 20) {food.y = 19;}// 创建食物元素const foodElement = document.createElement("div");foodElement.classList.add("food");foodElement.style.left = food.x * 20 + "px";foodElement.style.top = food.y * 20 + "px";gameArea.appendChild(foodElement);
}generateFood();
/* styles.css */
.food {width: 20px;height: 20px;background-color: red;position: absolute;
}

在这里插入图片描述

步骤5:检测碰撞与游戏逻辑

最后,我们需要检测蛇是否与食物相撞以及是否撞墙,同时还需要处理游戏结束的情况。

// script.js
function checkCollision() {const head = snake[0];// 检查是否撞墙if (head.x < 0 || head.x >= 20 || head.y < 0 || head.y >= 20) {clearInterval(gameInterval); // 停止游戏alert("游戏结束!");return true;}// 检查是否与食物相撞console.log("head:", head.x, head.y);console.log("food:", food.x, food.y);if (head.x === food.x && head.y === food.y) {// 吃掉食物,增加蛇的长度let x, y;// 判断蛇尾增加的方向if (direction === "right") {x = snake[snake.length - 1].x - 1;y = snake[snake.length - 1].y;} else if (direction === "left") {x = snake[snake.length - 1].x + 1;y = snake[snake.length - 1].y;} else if (direction === "top") {x = snake[snake.length - 1].x;y = snake[snake.length - 1].y + 1;} else {x = snake[snake.length - 1].x;y = snake[snake.length - 1].y - 1;}snake.push({ x, y });const newTail = document.createElement("div");newTail.classList.add("snake");newTail.style.left = x * 20 + "px";newTail.style.top = y * 20 + "px";gameArea.appendChild(newTail);generateFood();}// 检查是否与自身相撞for (let i = 1; i < snake.length; i++) {if (head.x === snake[i].x && head.y === snake[i].y) {clearInterval(gameInterval); // 停止游戏alert("游戏结束!");return true;}}return false;
}let gameInterval = setInterval(() => {if (!checkCollision()) {moveSnake();}
}, 1000);

涉及知识点:

  • 通过direction来判断贪吃蛇吃到食物后变长的方向
  • alert是用于弹出提示框的JS api

这样,我们就完成了一个简单的贪吃蛇游戏!通过上述步骤,我们从创建游戏区域、初始化蛇的位置,到实现蛇的移动、食物的生成,最终加入碰撞检测和游戏逻辑,完成了一个可玩的贪吃蛇游戏。

在这里插入图片描述

在这里插入图片描述

总结

通过这个项目,你不仅可以学习如何使用 JavaScript 来实现一个小游戏,还可以熟练学习js操作dom、数据的常用方法、定时器setInterval、css样式、事件监听器以及实现需求的逻辑思维等等知识,对前面学习的一些理论知识进行了实践,相信你跟着一套教程下来会对前面学习到的知识有更深的理解。
后续我们这个前端专栏还会讲述ES6、垃圾回收、js算法技巧、Vue入门实战、React实战、前端面试题等等文章,如果您感兴趣的话,欢迎点赞三连并关注我以及我的前端专栏,我们下期文章再见。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

韦东山-电子量产工具项目:业务系统

代码结构 所有代码都已通过测试跑通&#xff0c;其中代码结构如下&#xff1a; 一、include文件夹 1.1 common.h #ifndef _COMMON_H #define _COMMON_Htypedef struct Region {int iLeftUpX; //区域左上方的坐标int iLeftUpY; //区域左下方的坐标int iWidth; //区域宽…

java八股文面试[java基础]——String StringBuilder StringBuffer

String类型定义&#xff1a; final String 不可以继承 final char [] 不可以修改 String不可变的好处&#xff1a; hash值只需要算一次&#xff0c;当String作为map的key时&#xff0c; 不需要考虑hash改变 天然的线程安全 知识来源&#xff1a; 【基础】String、StringB…

Python web实战之细说 Django 的单元测试

关键词&#xff1a; Python Web 开发、Django、单元测试、测试驱动开发、TDD、测试框架、持续集成、自动化测试 大家好&#xff0c;今天&#xff0c;我将带领大家进入 Python Web 开发的新世界&#xff0c;深入探讨 Django 的单元测试。通过本文的实战案例和详细讲解&#xff…

ubuntu安装Microsoft Edge并设置为中文

1、下载 edge.deb 版本并安装 sudo dpkg -i microsoft-edg.deb 2. 设置默认中文显示 如果是通过.deb方式安装的&#xff1a; 打开默认安装路径下的microsoft-edge-dev文件&#xff0c;在文件最开头加上: export LANGUAGEZH-CN.UTF-8 &#xff0c;保存退出。 cd /opt/micr…

PHP8的字符串操作3-PHP8知识详解

今天继续分享字符串的操作&#xff0c;前面说到了字符串的去除空格和特殊字符&#xff0c;获取字符串的长度&#xff0c;截取字符串、检索字符串。 今天继续分享字符串的其他操作。如&#xff1a;替换字符串、分割和合成字符串。 5、替换字符串 替换字符串就是对指定字符串中…

【算法系列篇】滑动窗口

文章目录 前言什么是滑动窗口1.长度最小的子数组1.1 题目要求1.2 做题思路 1.3 Java代码实现2.无重复字符的最长子串2.1 题目要求2.2 做题思路2.3 Java代码实现 3.最大连续1的个数 III3.1 题目要求3.2 做题思路3.3 Java代码实现 4.将x减到0的最小操作数4.1 题目要求4.2 做题思路…

【仿写框架之仿写Tomact】四、封装HttpRequest对象(属性映射http请求报文)、HttpResponse对象(属性映射http响应报文)

文章目录 1、创建HttpRequest对象2、创建HttpResponse对象 1、创建HttpRequest对象 HttpRequest对象中的属性与HTTP协议中的内容对应&#xff0c;用于后序servlet从request中获取请求中的参数。 参照http请求报文&#xff1a; import java.io.BufferedReader; import java…

配置使用Gitee账号认证登录Grafana

三方社会化身份源 集成gitee第三方登录 第三方登录的原理 所谓第三方登录&#xff0c;实质就是 OAuth 授权。用户想要登录 A 网站&#xff0c;A 网站让用户提供第三方网站的数据&#xff0c;证明自己的身份。获取第三方网站的身份数据&#xff0c;就需要 OAuth 授权。 举例来…

ubuntu上使用osg3.2+osgearth2.9

一、介绍 在ubuntu上使用osgearth加载三维数字地球&#xff0c;首先要有osg和osgearth的库&#xff0c;这些可以直接使用apt-get下载安装&#xff0c;但是版本有些老&#xff0c;如果需要新版本的就需要自己编译。 #查看现有版本 sudo apt-cache madison openscenegraph #安装…

Python写一个创意五子棋游戏

前言 在本教程中&#xff0c;我们将使用Python写一个创意五子棋游戏 &#x1f4dd;个人主页→数据挖掘博主ZTLJQ的主页 个人推荐python学习系列&#xff1a; ☄️爬虫JS逆向系列专栏 - 爬虫逆向教学 ☄️python系列专栏 - 从零开始学python 首先 GomokuGame 类的构造函数 __ini…

小程序 CSS-in-JS 和原子化的另一种选择

小程序 CSS-in-JS 和原子化的另一种选择 小程序 CSS-in-JS 和原子化的另一种选择 介绍快速开始 pandacss 安装和配置 0. 安装和初始化 pandacss1. 配置 postcss2. 检查你的 panda.config.ts3. 修改 package.json 脚本4. 全局 css 注册 pandacss5. 配置的优化与别名 weapp-pand…

LeetCode 周赛上分之旅 #40 结合特征压缩的数位 DP 问题

⭐️ 本文已收录到 AndroidFamily&#xff0c;技术和职场问题&#xff0c;请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架&#xff0c;你的思考越抽象&#xff0c;它能覆盖的问题域就越广&#xff0c;理解难度…

07_缓存预热缓存雪崩缓存击穿缓存穿透

缓存预热&缓存雪崩&缓存击穿&缓存穿透 一、缓存预热 提前将数据从数据库同步到redis。 在程序启动的时候&#xff0c;直接将数据刷新到redis懒加载&#xff0c;用户访问的时候&#xff0c;第一次查询数据库&#xff0c;然后将数据写入redis 二、缓存雪崩 发生情…

Roxy-Wi 命令执行漏洞复现

漏洞描述 Roxy-WI是开源的一款用于管理 Haproxy、Nginx 和 Keepalived 服务器的 Web 界面 Roxy-WI 6.1.1.0 之前的版本存在安全漏洞,该漏洞源于系统命令可以通过 subprocess_execute 函数远程运行,远程攻击者利用该漏洞可以执行远程代码。 免责声明 技术文章仅供参考,任…

小程序前台Boot后台校园卡资金管理系统java web学校进销存食堂挂失jsp源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 小程序前台Boot后台校园卡资金管理系统 系统有2权限&…

Nuxt3_1_路由+页面+组件+资源+样式 使用及实例

1、 简介 1.1 开发必备 node版本 v16.10.0 我使用的是16.14.0编辑器推荐使用Volar Extension 的VS code插件Terminal 运行nuxt指令 1.2 环境搭建 安装项目&#xff1a; npx nuxilatest init [first_nuxt3]进入项目目录&#xff1a; cd [first_nuxt3]安装依赖&#xff1a;n…

【蓝桥杯】[递归]母牛的故事

原题链接&#xff1a;https://www.dotcpp.com/oj/problem1004.html 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 我们列一个年份和母牛数量的表格&#xff1a; 通过观察&#xff0c;找规律&#xff0c;我们发现&#xff1a; 当年份小于等于4时&…

如何在出差期间远程访问企业ERP系统?内网穿透解决您的难题!

文章目录 概述1.查看象过河服务端端口2.内网穿透3. 异地公网连接4. 固定公网地址4.1 保留一个固定TCP地址4.2 配置固定TCP地址 5. 使用固定地址连接 概述 ERP系统对于企业来说重要性不言而喻&#xff0c;不管是财务、生产、销售还是采购&#xff0c;都需要用到ERP系统来协助。…

JVM前世今生之JVM内存模型

JVM内存模型所指的是JVM运行时区域&#xff0c;该区域分为两大块 线程共享区域 堆内存、方法区&#xff0c;即所有线程都能访问该区域&#xff0c;随着虚拟机和GC创建和销毁 线程独占区域 虚拟机栈、本地方法栈、程序计数器&#xff0c;即每个线程都有自己独立的区域&#…