JavaScript+ Canvas开发趣味小游戏《贪吃蛇》

一、效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、《贪吃蛇》基本实现思路

在这里插入图片描述

  1. 蛇头部分+蛇身体部分:采用对象形式来存储坐标,并将每个坐标对象放到一个snake数组中,方便使用。设置每个方格宽度30px,高度30px画布高度600px,宽度600px
    a.新蛇头newHead等于旧蛇头oldHead的x坐标或者y坐标+1
    b.蛇的头部+身体部分,每次更新(动起来)的规律:每次将蛇的身体部分的最后1个方块(尾部)删除,然后在蛇的头部的前面增加1个方块:该新增的方块(newHead)的坐标与原来头部方块(oldHead)的坐标关系为 newHead等于旧蛇头oldHead的x坐标或者y坐标+1
    在这里插入图片描述

  2. 蛇吃食物
    a.当蛇头的坐标与食物的坐标重合的时候,表示食物被吃掉了。判断标准为:蛇头的x,y坐标都与食物的x,y坐标重合
    此时,要做两件事情:
    1)isEated 变为 true,此时就会重新生成一个食物坐标
    2)让蛇增加一节长度。但是,前面的1.b里提到,关于蛇动起来的规律中,每次更新画布都会把蛇的身体部分(尾巴)删掉1个方块,也就是当蛇没有吃到食物时,删除一节。所以,在这里蛇吃到食物时,只要不删除最后一节,也就相当于蛇吃到食物增加了一节了

  3. 绘制食物
    a.食物有默认位置
    b.食物没有被吃掉之前,不会动
    c.只有食物被吃掉后,才会随机再生成一个

  4. 绘制贪吃蛇
    在这里插入图片描述
    在这里插入图片描述
    a.贪吃蛇随着画布的 擦除->重绘的过程,会动起来(即改变贪吃蛇的坐标),这就是让蛇能够动起来的原理。这里需要配合定时器来实现动起来!
    b.贪吃蛇默认移动方向为:水平向右
    c.默认每次移动的距离为一个方格
    以下的x,y都是指蛇头的坐标只要蛇头的坐标发生改变,蛇的身体部分自然会跟着蛇头来运动
    水平往左 : x-1 , y不变
    垂直向下 : x不变 , y+1
    垂直向上 : x不变 , y-1

  5. 绘制网格:使用Canvas来实现
    注意Canvas使用方法:
    1)获取画布对象 var huabu = document.getElementById(‘huabu’)
    2)获取画布对象中的工具箱 var tools = huabu.getContext(‘2d’)
    3)从画图工具箱中取出要使用的工具 tools.moveTo(0, 30 * i + 0.5) 、 tools.lineTo(600, 30 * i + 0.5)
    4)找坐标
    5)绘制
    注意:在使用Canvas绘制线条时坐标的设置,如果要设置的线条粗细为1px,则需要把tools.moveTo()、 tools.lineTo()里面的起点终点坐标设置成.5小数形式,否则画出来的线条粗细为2px

  6. 游戏结束的判断标准:
    贪吃蛇超出上、下、左、右边界时,游戏结束
    即newHead.y < 0 || newHead.x < 0 || newHead.x * 30 >= 600 || newHead.y * 30 >= 600时,游戏结束。

三、技术要点

  1. 使用Canvas****绘制线条 tools.moveTo(0, 30 * i + 0.5) 、 tools.lineTo(600, 30 * i + 0.5)实心矩形tools.fillRect(x,y,width,height),并设置它们的颜色
  2. setInterval定时器的使用以及清除。var StopTime = setInterval(timer, 100)clearInterval(StopTime)
  3. 数组元素的尾部删除pop()和头部新增unshift()
  4. **Math.random()**随机数的使用,该方法生成[0,1)的随机数,包含0不包含1
  5. 监听键盘按下的行为,
document.**addEventListener**('keydown', function(event) {
if (event.keyCode === 38) {//如果键值为38,就说明按下了 上键console.log("上")directionX = 0directionY = -1}}
  1. JavaScript操作Dom对象,获取相应的Dom元素
  2. 自定义计时函数
var h = m = s = ms = 0; //定义时,分,秒,毫秒并初始化为0;function toDub(n) { //补0操作if (n < 10) {return "0" + n;} else {return "" + n;}}function toDubms(n) { //给毫秒补0操作if (n < 10) {return "00" + n;} else {return "0" + n;}}
function timer() { //定义计时函数ms = ms + 50; //毫秒if (ms >= 1000) {ms = 0;s = s + 1; //秒}if (s >= 60) {s = 0;m = m + 1; //分钟}if (m >= 60) {m = 0;h = h + 1; //小时}str = toDub(h) + "时" + toDub(m) + "分" + toDub(s) + "秒" + toDubms(ms) + "毫秒";timeDom.innerHTML = str;// document.getElementById('mytime').innerHTML=h+"时"+m+"分"+s+"秒"+ms+"毫秒";}

四、游戏功能:

  1. 每次吃到食物时蛇的长度加1
  2. 当蛇头触碰到游戏边界时,游戏结束
  3. 分数记录,每吃到一个一个食物,分数加1
  4. 游戏总时长记录

五、代码如下:

<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title>贪吃蛇游戏</title></head><style type="text/css">* {margin: 0;padding: 0;}a {text-decoration: none;}canvas {position: relative;display: block;margin: 0 auto;background-color: #33cc99;}.images {background: url(img/timg.jpg) no-repeat;width: 800px;height: 600px;position: absolute;top: 0;left: 50%;margin-left: -400px;}.start {width: 160px;height: 40px;border: 1px solid #33CC99;border-radius: 10px;color: #fff;background-color: orangered;font-size: 25px;text-align: center;line-height: 40px;position: absolute;bottom: 200px;left: 50%;margin-left: -80px;}.author {width: 160px;position: absolute;bottom: 150px;left: 50%;margin-left: -80px;text-align: center;font-weight: 600;font-size: 18px;}.over {background: url(img/over.jpg) no-repeat;width: 800px;height: 600px;position: absolute;top: 0;left: 50%;margin-left: -400px;}.black_overlay {display: none;position: absolute;top: 0%;left: 0%;width: 100%;height: 100%;background-color: black;z-index: 1001;-moz-opacity: 1;opacity: 1;filter: alpha(opacity=1);}.black_overlay>img {display: none;margin: 0 auto;margin-top: 190px;}.black_overlay>a {width: 160px;height: 40px;border: 1px solid #33CC99;border-radius: 10px;color: #fff;background-color: orangered;font-size: 25px;text-align: center;line-height: 40px;position: absolute;bottom: 230px;left: 50%;margin-left: -80px;}#score {margin-left: 500px;			}#scores {margin-right: 200px;}</style><body><canvas id="huabu" width="600" height="600"></canvas><div class="images" id="images"><div class="start" id="start">开始游戏</div><div class="author">制作人:Zep</div></div><div id="fade" class="black_overlay"><img src="./img/over.jpg" id="over"><a href="index.html">重新开始</a></div><div id="score">分数:<span id="scores">0</span>游戏时长:<span id="time">00时00分00秒0000毫秒</span></div></body><script type="text/javascript">// 是否开始游戏var isStart = false// 点击start按钮,隐藏首页图片var startbtn = document.getElementById('start')var imagesDom = document.getElementById('images')var fadeDom = document.getElementById('fade')var overDom = document.getElementById('over')var score = 0.0var speed = 3var scoresDom = document.getElementById('scores')var timeDom = document.getElementById('time')var h = m = s = ms = 0; //定义时,分,秒,毫秒并初始化为0;function toDub(n) { //补0操作if (n < 10) {return "0" + n;} else {return "" + n;}}function toDubms(n) { //给毫秒补0操作if (n < 10) {return "00" + n;} else {return "0" + n;}}function timer() { //定义计时函数ms = ms + 50; //毫秒if (ms >= 1000) {ms = 0;s = s + 1; //秒}if (s >= 60) {s = 0;m = m + 1; //分钟}if (m >= 60) {m = 0;h = h + 1; //小时}str = toDub(h) + "时" + toDub(m) + "分" + toDub(s) + "秒" + toDubms(ms) + "毫秒";timeDom.innerHTML = str;// document.getElementById('mytime').innerHTML=h+"时"+m+"分"+s+"秒"+ms+"毫秒";}startbtn.onclick = function() {imagesDom.style.display = 'none'isStart = true}var Game = setInterval(gameStart, 500)function gameStart() {if (isStart) {clearInterval(Game)var StopTime = setInterval(timer, 100)// console.log('111')// 1.获取画布对象var huabu = document.getElementById('huabu')// 2.获取画布对象中的工具箱var tools = huabu.getContext('2d')//注意:1.食物有默认位置//		2.食物没有被吃掉之前,不会动//      3.只有食物被吃掉后,才会随机再生成一个// 随机生产x,y坐标// 食物的默认位置var x = Math.floor(Math.random() * 20) * 30var y = Math.floor(Math.random() * 20) * 30// 添加一个标记,记录食物是否被吃掉了var isEated = false // 默认食物没有被吃掉// 蛇的默认位置var snake = [{x: 3,y: 0}, {x: 2,y: 0}, {x: 1,y: 0}]// 蛇的默认方向:水平向右var directionX = 1var directionY = 0// 判断游戏是否结束var isGameOver = false// 监听键盘按下的行为document.addEventListener('keydown', function(event) {console.log('按键的键值', event.keyCode)// 上:38,下:40,左:37,右:39if (event.keyCode === 38) {//如果键值为38,就说明按下了 上键console.log("上")directionX = 0directionY = -1} else if (event.keyCode === 40) {//如果键值为40,就说明按下了 下键console.log("下")directionX = 0directionY = 1} else if (event.keyCode === 37) {//如果键值为37,就说明按下了 左键console.log("左")directionX = -1directionY = 0} else if (event.keyCode === 39) {//如果键值为39,就说明按下了 右键console.log("右")directionX = 1directionY = 0}})// 使用定时器,让贪吃蛇动起来// 定时器每隔一段时间,就执行一遍“擦除画布->重绘画布”的过程// 以下代码表示:1s执行三次 “擦除画布->重绘画布”的过程setInterval(function() {// 如果isGameOver = false 说明游戏结束了,执行return,就不执行下面的代码了if (isGameOver) {fadeDom.style.display = 'block'overDom.style.display = 'block'clearInterval(StopTime)return}// 一、擦除画布tools.clearRect(0, 0, 600, 600)// 二、以下代码就是重绘画布的代码// -----------------------A.蛇头部分开始---------------------------// A.蛇头部分var oldHead = snake[0]var newHead = {x: oldHead.x + directionX,y: oldHead.y + directionY}//游戏结束的判定:// 1.蛇头的y<0,贪吃蛇超出上边界,游戏结束if (newHead.y < 0 || newHead.x < 0 || newHead.x * 30 >= 600 || newHead.y * 30 >= 600) {// 游戏结束isGameOver = true} else {// 在数组首部添加一节,结果为:(4,0)(3,0) (2,0)snake.unshift(newHead) //在数组第一个元素前面添加一个元素// -----------------------B.蛇吃食物开始---------------------------// 蛇吃食物的分析:// 当蛇头的坐标与食物的坐标重合的时候,表示食物被吃掉了// 此时,要做两件事情:// 1.isEated 变为 true,此时就会重新生成一个食物坐标if (snake[0].x * 30 === x && snake[0].y * 30 === y) {// 蛇头的x,y坐标都与食物的x,y坐标重合isEated = true} else { // 2.让蛇增加一节长度,也就是当蛇没有吃到食物时,删除一节,吃到食物时,就不删除一节,也就相当于蛇吃到食物增加一节// 删除最后一节,结果为:(3,0) (2,0)snake.pop() //删除数组最后一个元素// 重新设置食物没有被吃掉的标志isEated = false}// -----------------------蛇吃食物结束---------------------------}// -----------------------蛇头部分结束---------------------------// -----------------------C.绘制食物开始---------------------------// 绘制矩形 tools.fillRect(x,y,width,height)//注意:1.食物有默认位置//		2.食物没有被吃掉之前,不会动//      3.只有食物被吃掉后,才会随机再生成一个if (isEated) {x = Math.floor(Math.random() * 20) * 30y = Math.floor(Math.random() * 20) * 30score += 1speed += 0.1}scoresDom.innerHTML = score// 设置填充颜色tools.fillStyle = '#cccc00'tools.fillRect(x, y, 30, 30)// -----------------------绘制食物结束---------------------------// -----------------------D.绘制贪吃蛇开始---------------------------// 说明:// 1.贪吃蛇随着 擦除->重绘的过程,会动起来(即改变贪吃蛇的坐标)// 2.贪吃蛇默认移动方向为:水平向右// 3.默认每次移动的距离为一个方格// 问题:水平往左 : x-1 , y不变//		 垂直向下 : x不变 , y+1//		 垂直向上 : x不变 , y-1// // 删除最后一节,结果为:(3,0) (2,0)// snake.pop() //删除数组最后一个元素// 绘制蛇头部,蛇的每一节都是一个矩形// // 设置蛇头的颜色// tools.fillStyle = '#ff0033'// tools.fillRect(snake[0].x * 30,snake[0].y * 30,30,30)// // 绘制蛇的身体部分// tools.fillStyle = '#333399'// tools.fillRect(snake[1].x * 30,snake[1].y * 30,30,30)// tools.fillRect(snake[2].x * 30,snake[2].y * 30,30,30)for (var i = 0; i < snake.length; i++) {if (i === 0) {tools.fillStyle = '#ff0033'} else {tools.fillStyle = '#333399'}tools.fillRect(snake[i].x * 30, snake[i].y * 30, 30, 30)}// -----------------------绘制贪吃蛇结束---------------------------// -----------------------E.绘制网格开始---------------------------// 3.从画图工具箱中取出要使用的工具// 4.找坐标// 绘制水平线for (var i = 1; i < 20; i++) {tools.moveTo(0, 30 * i + 0.5)tools.lineTo(600, 30 * i + 0.5)}// 绘制垂直线for (var i = 1; i < 20; i++) {tools.moveTo(30 * i + 0.5, 0)tools.lineTo(30 * i + 0.5, 600)}// 设置绘制直线的颜色tools.strokeStyle = '#fff'// 5.绘制tools.stroke()// -----------------------绘制网格结束---------------------------}, 1000 / speed)}}</script>
</html>

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

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

相关文章

LeetCode 2160. 拆分数位后四位数字的最小和

文章目录1. 题目2. 解题1. 题目 给你一个四位 正 整数 num 。请你使用 num 中的 数位 &#xff0c;将 num 拆成两个新的整数 new1 和 new2 。 new1 和 new2 中可以有 前导 0 &#xff0c;且 num 中 所有 数位都必须使用。 比方说&#xff0c;给你 num 2932 &#xff0c;你拥…

我的世界怎么设置服务器维护中,我的世界服务器

发布时间&#xff1a;2016-08-26我的世界游戏中我们会遇到关于服务器的问题,怎么对服务器进行重启呢?今天跟大家介绍的这款我的世界工具是一款比较实用的辅助,可以检测服务器状态,而且有查找问题和快速重启服务器的功能,需要的小伙伴请看看下面的我的世界服务器怎么 ...标签&a…

LeetCode 2161. 根据给定数字划分数组

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums 和一个整数 pivot 。 请你将 nums 重新排列&#xff0c;使得以下条件均成立&#xff1a; 所有小于 pivot 的元素都出现在所有大于 pivot 的元素 之前 。所有等于 pivot 的元素都出现在小于和大于 pivot …

一、人工智能数学基础——线性代数

01 向量空间 1.1定义和例子 1.2向量及其运算 1.3向量组的线性组合 1.4向量组的线性相关性 02 内积和范数 2.1内积的定义 2.2范数的定义 2.3内积的几何解释 03矩阵和线性变换 3.1定义和例子 3.2线性变换 线性空间中的运动&#xff0c;被称为线性变换。线性空间中的一个向量变…

LeetCode 2162. 设置时间的最少代价(枚举)

文章目录1. 题目2. 解题1. 题目 常见的微波炉可以设置加热时间&#xff0c;且加热时间满足以下条件&#xff1a; 至少为 1 秒钟。至多为 99 分 99 秒。 你可以 最多 输入 4 个数字 来设置加热时间。 如果你输入的位数不足 4 位&#xff0c;微波炉会自动加 前缀 0 来补足 4 位…

八、操作系统——基本分页存储管理的基本概念(详解)

一、思考&#xff1a;连续分配方式的缺点&#xff1f; 考虑支持多道程序的两种连续分配方式&#xff1a; 固定分区分配&#xff1a;缺乏灵活性&#xff0c;会产生大量的内部碎片&#xff0c;内存的利用率很低。动态分区分配&#xff1a;会产生很多外部碎片&#xff0c;虽然可以…

oracle 查看服务器密码修改,如何修改oracle用户密码

修改oracle用户密码的方法&#xff1a;首先连接oracle数据库所在服务器&#xff0c;并进入oracle控制台&#xff1b;然后输入“select username from dba_users”查看用户列表&#xff1b;最后输入修改用户口令即可。本教程操作环境&#xff1a;windows7系统、oracle版&#xf…

计算机组成原理——校验码(奇偶校验码、汉明校验码、循环冗余校验码)

一、为什么要使用校验码&#xff1f; 数据在计算机系统内加工、存取和传送的过程中可能会产生错误。为了减少和避免这类错误&#xff0c;引入了数据校验码。数据校验码是一种常用的带有发现某些错误&#xff0c;甚至带有一定自动改错能力的数据编码方法。 例子&#xff1a; …

(转)基因芯片数据GO和KEGG功能分析

随着人类基因组计划(Human Genome Project)即全部核苷酸测序的即将完成&#xff0c;人类基因组研究的重心逐渐进入后基因组时代(Postgenome Era)&#xff0c;向基因的功能及基因的多样性倾斜。通过对个体在不同生长发育阶段或不同生理状态下大量基因表达的平行分析&#xff0c;…

LeetCode 2164. 对奇偶下标分别排序

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums 。根据下述规则重排 nums 中的值&#xff1a; 按 非递增 顺序排列 nums 奇数下标 上的所有值。 举个例子&#xff0c;如果排序前 nums [4,1,2,3] &#xff0c;对奇数下标的值排序后变为 [4,3,2,1] 。奇…

九、操作系统——基本地址变换机构(详解)

一、概览 重点理解、记忆基本地址变换机构&#xff08;用于实现逻辑地址到物理地址转换的一组硬件机构&#xff09;的原理和流程 二、基本地址变换机构 基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。 通常会在系统中设置一个页表寄存器&#xff08;PTR&am…

客户端显示服务器图片不显示,客户端请求服务器图片不显示

客户端请求服务器图片不显示 内容精选换一换已成功登录鲲鹏代码迁移工具。只有管理员用户(portadmin)可以执行生成CSR文件、导入web服务器证书、重启和更换工作密钥的操作。普通用户只能查看web服务端证书信息。SSL证书通过在客户端浏览器和web服务器之间建立一条SSL安全通道(访…

LeetCode 2165. 重排数字的最小值(计数)

文章目录1. 题目2. 解题1. 题目 给你一个整数 num 。重排 num 中的各位数字&#xff0c;使其值 最小化 且不含 任何 前导零。 返回不含前导零且值最小的重排数字。 注意&#xff0c;重排各位数字后&#xff0c;num 的符号不会改变。 示例 1&#xff1a; 输入&#xff1a;nu…

优酷路由宝无线服务器,优酷路由宝一站式刷潘多拉!!!整理版

本帖最后由 louis000 于 2015-11-3 14:57 编辑优酷路由宝L1W刷潘多拉固件-整理优化版准备工作&#xff1a;使用有线连接路由宝和电脑&#xff1b;电脑网络连接设置为手动获取IP地址。---------------------------------------------------------------------------------------…

LeetCode 2166. 设计位集(Bitset)

文章目录1. 题目2. 解题1. 题目 位集 Bitset 是一种能以紧凑形式存储位的数据结构。 请你实现 Bitset 类。 Bitset(int size) 用 size 个位初始化 Bitset &#xff0c;所有位都是 0 。void fix(int idx) 将下标为 idx 的位上的值更新为 1 。如果值已经是 1 &#xff0c;则不…

Web框架——Flask系列之Flask简介(一)

一、Web应用程序作用 Web(World Wide Web)诞生最初的目的,是为了利用互联网交流工作文档 二、关于Web框架 &#xff08;一&#xff09;什么是Web框架&#xff1f; 已经封装好了一段代码,协助程序快速开发,相当于项目半成品开发者只需要按照框架约定要求,在指定位置写上自己…

服务器系统网卡驱动装不上,网卡驱动装不上去怎么办?

满意答案hgtn1q6xvv52014.09.28采纳率&#xff1a;58% 等级&#xff1a;13已帮助&#xff1a;9534人现提示原: SP2更考虑安全问题IP设置自获取其实DHCP服务器获取IP及相关参数程能由于某种原没完. SP1代种情况操作系统防止脱网(微软写)自作主张网卡设置169.x.x.x保留IP作任何…

moco-globalsettings

1.单个json文件 &#xff08;1&#xff09;目录配置 &#xff08;2&#xff09;新建foo.json 在project文件夹中新建foo.json [{"request" : {"uri" : "/foo"},"response" : {"text" : "foo"}} ] &#xff08;3&a…

LeetCode 2169. 得到 0 的操作数

文章目录1. 题目2. 解题1. 题目 给你两个 非负 整数 num1 和 num2 。 每一步 操作 中&#xff0c;如果 num1 > num2 &#xff0c;你必须用 num1 减 num2 &#xff1b; 否则&#xff0c;你必须用 num2 减 num1 。 例如&#xff0c;num1 5 且 num2 4 &#xff0c;应该用 …

阿里云 腾讯云 服务器挂载数据盘

在默认拥有的腾讯云服务器是没有额外的数据盘的&#xff0c;默认Linux只有8GB系统盘&#xff0c;一般的网站也足够使用&#xff0c;如果额外购买的数据盘安装系统之后根据不同的面板、系统的路径问题可能不会自动加载到指定的数据盘目录&#xff0c;需要我们手工进行加载数据盘…