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

news2024/11/24 6:59:18

在这里插入图片描述

前言

贪吃蛇游戏是经典的小游戏,也是学习前端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.coloradmin.cn/o/903538.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tcl学习之路(五)(Vivado时序约束)

1.主时钟约束 主时钟通常是FPGA器件外部的板机时钟或FPGA的高速收发器输出数据的同步恢复时钟信号等。下面这句语法大家一定不会陌生。该语句用于对主时钟的名称、周期、占空比以及对应物理引脚进行约束。 create_clock -name <clock_name> -periood <period> -wa…

电影《孤注一掷》感触、计算机底层二进制与十进制的转换

今天&#xff0c;我与媳妇一同在商场吃完午餐&#xff0c;正值天空绵绵细雨。近期&#xff0c;听闻一部名为《孤注一掷》的电影&#xff0c;其主人公是一位程序员&#xff0c;故事情节围绕境外电信诈骗展开&#xff0c;引发了广泛的关注。身为一名程序员&#xff0c;我对与电信…

DSO 系列文章(2)——DSO点帧管理策略

文章目录 1.点所构成的残差Residual的管理1.1.前端残差的状态1.2.后端点的残差的状态1.3.点的某个残差的删除 2.点Point的管理2.1.如何删除点——点Point的删除2.2.边缘化时删除哪些点&#xff1f; 3.帧FrameHessian的管理 DSO代码注释&#xff1a;https://github.com/Cc19245/…

Vulnhub: DriftingBlues: 2靶机

kali&#xff1a;192.168.111.111 靶机&#xff1a;192.168.111.207 信息收集 端口扫描 nmap -A -sC -v -sV -T5 -p- --scripthttp-enum 192.168.111.207 80端口的/blog目录为wordpress wpscan收集wordpress用户和爆破密码 wpscan --url http://driftingblues.box/blog -e…

深入理解Linux内核--回收页框

页框回收算法 Linux中有一点很有意思&#xff0c;在为用户态进程与内核分配动态内存时&#xff0c;所作的检查是马马虎虎的。 比如&#xff0c;对单个用户所创建进程的RAM使用总量并不作严格检查(第三章的“进程资源限制”一节提到的限制只针对单个进程); 对内核使用的许多磁盘…

【数据结构】链表的回文结构

文章目录 &#x1f30f;引言&#x1f9ed;[链表的回文结构](https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&ru/activity/oj&qru/ta/2016test/question-ranking)&#x1f6a9;&#x1f6a9;题目描述&#xf…

学习网络编程No.3【socket理论实战】

引言&#xff1a; 北京时间&#xff1a;2023/8/12/15:32&#xff0c;自前天晚上更新完文章&#xff0c;看了一下鹅厂新出的《扫毒3》摆烂至现在&#xff0c;不知道是长大了&#xff0c;还是近年港片就那样&#xff0c;给我的感觉不是很好&#xff0c;也可能是国内市场对港片不…

XXL-JOB任务调度中心后台命令执行漏洞

漏洞描述 XXL-JOB任务调度中心后台存在命令执行漏洞,攻击者可在后台通过写入shell命令任务调度获取服务器控制权限 免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权…

AndroidAGP8.1.0和JDK 17迁移之旅

AndroidAGP8.1.0和JDK 17迁移之旅 前言&#xff1a; 由于我最近写demo的直接把之前的项目从AGP4.2.2升级到8.1.0引发了一些列问题&#xff0c;这里记录一下&#xff0c;前面讲解过迁移DSL方式遇到的问题&#xff0c;这次升级8.1.0也比之前顺利多了&#xff0c;想看DSL迁移的可…

Edge浏览器免费使用GPT3.5

搜索sider,安装Sidebar插件 注册账号即可每天免费使用30次。 Sider: ChatGPT侧边栏,GPT-4, 联网, 绘图

Excel VBA 复制除指定工作表外所有的工作表的内容到一张工作表中

当我们有一张表里面有很多sheet 具有相同的表结构&#xff0c;如果需要汇总到一张表中&#xff0c;那么我们可以借助VBA 去实现汇总自动化 Sub 复制所有工作表内容()Dim ws As WorksheetDim targetSheet As WorksheetDim lastRow As Long 设置目标表格&#xff0c;即要将所有…

SpringMVC之@RequestMapping注解

文章目录 前言一、RequestMapping介绍二、详解&#xff08;末尾附源码&#xff0c;自行测试&#xff09;1.RequestMapping注解的位置2.RequestMapping注解的value属性3.RequestMapping注解的method属性4.RequestMapping注解的params属性&#xff08;了解&#xff09;5.RequestM…

课程项目设计--项目建立--宿舍管理系统--springboot后端

前要 项目设计–宿舍管理系统 文章目录 项目建立导入依赖配置文件配置目录结构config配置mybatis-plusswagger 生成实体、mapper和servicebaseEntity统一响应实例响应码接口响应码接口实现统一响应result统一分页响应 项目建立 太长了&#xff0c;修改一下 导入依赖 暂时先加…

Java 项目日志实例:Log4j2

点击下方关注我&#xff0c;然后右上角点击...“设为星标”&#xff0c;就能第一时间收到更新推送啦~~~ Apache Log4j 2 是对 Log4j 的升级&#xff0c;与其前身 Log4j 1.x 相比有了显着的改进&#xff0c;并提供了许多 Logback 可用的改进&#xff0c;同时支持 JCL 以及 SLF4J…

Word中对象方法(Methods)的理解及示例(上)

【分享成果&#xff0c;随喜正能量】奋斗没有终点,任何时候都是一个起点&#xff0c;沉潜是为了蓄势待发&#xff0c;沉潜是为了等待因缘。鲸豚沉潜于大海&#xff0c;幽兰深藏于山谷&#xff0c;能够经得起沉潜的人&#xff0c;才会有更高的成就。正如一年的树木只能当柴烧&am…

C++入门:函数缺省参数与函数重载

目录 1.函数缺省参数 1.1 缺省参数概念 1.2 缺省参数分类 2.函数重载 2.1 函数重载概念 2.2 C支持函数重载的原理 1.函数缺省参数 1.1 缺省参数概念 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时&#xff0c;如果没有指定实 参则采用该形参的…

Unity 之 RaycastHit(存储射线投射操作)

文章目录 总述具体使用场景 总述 RaycastHit 类是 Unity 中的一个结构&#xff0c;用于存储射线投射操作的结果。射线投射是一种常用的技术&#xff0c;用于检测场景中的碰撞、获取碰撞点、获取碰撞对象的信息等。RaycastHit 提供了关于射线与场景中对象的交互信息&#xff0c…

新型Windows内核池风水利用工具研究

引用 这篇文章的目的是介绍一种新型基于内核态分页内存和非分页内存的越界写入通用利用技术和相关工具复现. 文章目录 引用简介分页模式利用分析分页模式利用调试分析非分页模式利用分析非分页模式利用调试分析工具使用方法工具使用效果相关引用参与贡献 简介 笔者的在原作者利…

硕士研究生小论文写作方法

本人985硕博毕业-曾多次辅导本硕同学完成成毕设&#xff0c;下面分享一些经验 图为当年大论文外审结果&#xff01;&#xff01;&#xff01; 当撰写一篇硕士研究生的小论文时&#xff0c;以下是每个部分的写作方法的详细描述&#xff0c;&#xff1a; 摘要&#xff08;Abst…

零基础在家就可以做的副业,3个兼职项目推荐

做副业最需要注重的是什么&#xff1f;我觉得有收益&#xff0c;稳定&#xff0c;上手快&#xff0c;可以学到东西&#xff0c;下面3个副业适合新手快速变现的副业&#xff0c;大可以随便挑一两个尝试一下 第一个&#xff1a;在小红书的发手记 满5000粉丝们就可以申请品牌合作…