您现在的位置是:网站首页> 编程资料编程资料
教你如何一步一步用Canvas写一个贪吃蛇H5 canvas实现贪吃蛇小游戏
2023-10-16
350人已围观
简介 贪吃蛇是很常见的一种小游戏,这篇文章主要介绍了教你如何一步一步用Canvas写一个贪吃蛇,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
之前在慕课网看了几集Canvas的视频,一直想着写点东西练练手。感觉贪吃蛇算是比较简单的了,当年大学的时候还写过C语言字符版的,没想到还是遇到了很多问题。
最终效果如下(图太大的话 时间太长 录制gif的软件有时限…)

首先定义游戏区域。贪吃蛇的屏幕上只有蛇身和苹果两种元素,而这两个都可以用正方形格子构成。正方形之间添加缝隙。为什么要添加缝隙?你可以想象当你成功填满所有格子的时候,如果没有缝隙,就是一个实心的大正方形……你根本不知道蛇身什么样。
画了一个图。
格子是左上角的坐标是(0, 0),向右是横坐标增加,向下是纵坐标增加。这个方向和Canvas相同。
每次画一个格子的时候,要从左上角开始,我们直知道Canvas的左上角坐标是(0, 0),假设格子的边长是 GRID_WIDTH 缝隙的宽度是 GAP_WIDTH ,可以得到第(i, j)个格子的左上角坐标 (i*(GRID_WIDTH+GAP_WIDTH)+GAP_WIDTH, j*(GRID_WIDTH+GAP_WIDTH)+GAP_WIDTH) 。
假设现在蛇身是由三个蓝色的格子组成的,我们不能只绘制三个格子,两个紫色的空隙也一定要绘制,否则,还是之前说的,你根本不知道蛇身什么样。如下图,不画缝隙虽然也能玩,但是体验肯定不一样。
绘制相邻格子之间间隙
不绘制间隙
现在我们可以尝试着画一条蛇了。蛇身其实就是一个格子的集合,每个格子用包含两个位置信息的数组表示,整条蛇可以用二维数组表示。
blog_snack
我初始化了一条蛇,看起来是符合预期的。

接下来要做的是让蛇动起来。蛇动起来这事很简单,蛇向着当前运动的方向前进一格,删掉蛇尾,也就是最后一个格子就可以了。之前说的二维数组表示一条蛇, 现在规定其中snack[0]表示蛇尾,snack[snack.length-1]表示蛇头。 动画就简单的用setInterval实现了。
const GRID_WIDTH = 10; // 格子的边长 const GAP_WIDTH = 2; // 空隙的边长 const ROW = 10; // 一共有多少行格子&每行有多少个格子 const COLOR = '#fff'; // 蛇的颜色 const BG_COLOR = '#000';// 背景颜色 const UP = 0, LEFT = 1, RIGHT = 2, DOWN = 3; // 定义蛇前进的方向 const CHANGE = [ [0, -1], [-1, 0], [1, 0], [0, 1] ]; // 每个方向前进时格子坐标的变化 let canvas = document.getElementById('canvas'); canvas.height = GRID_WIDTH * ROW + GAP_WIDTH * (ROW + 1); canvas.width = GRID_WIDTH * ROW + GAP_WIDTH * (ROW + 1); let ctx = canvas.getContext('2d'); let snack = [ [2, 3], [2, 4], [2, 5], [3, 5], [4, 5], [4, 4], [5, 4], [5, 5] ]; // 初始化一条🐍 let dir = RIGHT; // 初始化一个方向 drawSnack(ctx, snack, COLOR); let timer = setInterval(() => { // 每隔一段时间就刷新一次 let head = snack[snack.length - 1]; // 蛇头 let change = CHANGE[dir]; // 下一个格子前进位置 let newGrid = [head[0] + change[0], head[1] + change[1]]; // 新格子的位置 snack.push(newGrid); // 新格子加入蛇身的数组中 ctx.fillStyle = COLOR; ctx.fillRect(...getGridULCoordinate(newGrid), GRID_WIDTH, GRID_WIDTH); // 画新格子 ctx.fillRect(...getBetweenTwoGridGap(head, newGrid)); // 新蛇头和旧蛇头之间的缝隙 ctx.fillStyle = BG_COLOR; let delGrid = snack.shift(); // 删除蛇尾-最后一个元素 ctx.fillRect(...getGridULCoordinate(delGrid), GRID_WIDTH, GRID_WIDTH); // 擦除删除元素 ctx.fillRect(...getBetweenTwoGridGap(delGrid, snack[0])); // 擦除删除元素和当前最后一个元素之间的缝隙 }, 1000); ..... // 和之前相同现在蛇已经可以动起来了。

但这肯定不是我想要的效果——它的移动是一顿一顿的,而我想要顺滑的。
现在每一次变化都是直接移动一个格子边长的距离,保证蛇移动速度不变的情况下,动画是不可能变得顺滑的。所以想要移动变得顺滑,一种可行的方法是,移动一个格子的距离的过程分多次绘制。
blog_snack
实话,代码写的非常糟糕……我也很无奈……
反正现在蛇可以缓慢顺滑的移动了。

接下来要做的是判断是否触碰到边缘或者触碰到自身导致游戏结束,以及响应键盘事件。
这里的改动很简单。用一个map标记每一个格子是否被占。每一个格子(i, j)可以被编号i*row+j。
const GRID_WIDTH = 10; // 格子的边长 const GAP_WIDTH = 2; // 空隙的边长 const ROW = 10; // 一共有多少行格子&每行有多少个格子 const COLOR = '#fff'; // 蛇的颜色 const BG_COLOR = '#000';// 背景颜色 const INTERVAL = 300; const UP = 0, LEFT = 1, RIGHT = 2, DOWN = 3; // 定义蛇前进的方向 const CHANGE = [ [0, -1], [-1, 0], [1, 0], [0, 1] ]; // 每个方向前进时格子坐标的变化 let canvas = document.getElementById('canvas'); canvas.height = GRID_WIDTH * ROW + GAP_WIDTH * (ROW + 1); canvas.width = GRID_WIDTH * ROW + GAP_WIDTH * (ROW + 1); let ctx = canvas.getContext('2d'); let snack, dir, map, nextDir; function initialize() { snack = [ [2, 3], [2, 4], [2, 5], [3, 5], [4, 5], [4, 4], [5, 4], [5, 5] ]; // 初始化一条🐍 nextDir = dir = RIGHT; // 初始化一个方向 map = []; for (let i = 0; i < ROW * ROW; i++) map[i] = 0; for (let i = 0; i < snack.length; i++) map[ getGridNumber(snack[i]) ] = 1; window.onkeydown = function(e) { // e.preventDefault(); if (e.key === 'ArrowUp') nextDir = UP; if (e.key === 'ArrowDown') nextDir = DOWN; if (e.key === 'ArrowRight') nextDir = RIGHT; if (e.key === '
相关内容
- html5/css3响应式页面开发总结 CSS3移动端vw+rem不依赖JS实现响应式布局的方法CSS banner图响应式居中显示的方法详解使用CSS3的@media来编写响应式的页面 jQuery和CSS3响应式轮播插件jcSlider纯CSS3大转盘抽奖示例代码(响应式、可配置)CSS3 media queries + jQuery实现响应式导航CSS 响应式布局系统的实例代码
- 传统HTML页面实现模块化加载的方法在HTML里加载摄像头的方法基于HTML代码实现图片碎片化加载功能html5用video标签流式加载的实现HTML5 图片预加载的示例代码HTML页面缩小后显示滚动条的示例代码h5页面背景图很长要有滚动条滑动效果的实现HTML5实现直播间评论滚动效果的代码html+css实现滚动到元素位置显示加载动画效果
- HTML5 和小程序实现拍照图片旋转、压缩和上传功能HTML5页面嵌入小程序没有返回按钮及返回页面空白的问题微信小程序之html5 canvas绘图并保存到系统相册基于Jscex +HTML5 Canvas 制作的抽奖小程序HTML5跳转小程序wx-open-launch-weapp的示例代码
- 详解canvas drawImage()方法绘制图片不显示的问题HTML5 Canvas API中drawImage()方法的使用实例canvas绘制图片drawImage使用方法
- 全民英雄 仙女龙怎么样 仙女龙技能详解_手机游戏_游戏攻略_
- 我叫MT 黑沼泽副本艾尔努斯打法攻略推荐阵容_手机游戏_游戏攻略_
- 全民英雄 怎么提高酒馆上限的方法_手机游戏_游戏攻略_
- 我叫MT 3.1精英能源计算者如何刷 阵容推荐_手机游戏_游戏攻略_
- 爸爸去哪儿游戏时装大全以及这些时装作用_手机游戏_游戏攻略_
- 全民飞机大战如何刷分刷金币皇冠详细教程_手机游戏_游戏攻略_
点击排行
本栏推荐
