使用Canvas和javaScript实现贪吃蛇

复刻经典:贪吃蛇

首先我们先将Canvas画布绘画出来

HTML代码如下

 <canvas id="myCanvas" width="600" height="600"></canvas>

Css代码如下

 <style>
     #myCanvas{
         background:#9d9d9d;
         box-shadow:0 1px 10px #3e3e3e ;
    }
 </style>

Js代码如下

 var canv = document.getElementById('myCanvas')    //获取前端的Dom
 var ctx = canv.getContext('2d')    //在2d平面上进行绘画

首先思考到我们经典的贪吃蛇是一个方块一个方块组成的,食物也是一个方块一个方块组成的,我们的画布也是一个600px×600px的方块,这样我们这个画布可以分解成400个 30px×30px的方块 他们的id分别为0~399

如图所示

 

 

 

基本思路

我们是用键盘事件keyCode来实现的

我们学习过

左键:keyCode:37 上键:keyCode:38 右键:keyCode:39 下键:keyCode:40

接下来我们会用到这些 keyCode

 

然后我们如何根据解析id来获取每一个方块的坐标呢

 

我们思考第一行的那些方块 它们的id都是小于20的 而我们的一贯思路认为这一行的坐标是 (x , 0 )

而这个坐标0,是如何得到的呢?

????????

这一行的每一个元素对20取整 得到的整数部分都是 00就是这一行的纵坐标

同理第二行 对20取整 得到的整数部分都是1 第三行,第四行 ......... 都是如此

 

那么横坐标是什么呢?

??????

那么横坐标应该是将他的id 取余 得到的 余数 即为他的横坐标

 

那么综上所述我们解析id来获取坐标 行号 row:~~(id/20) 列号:col:id%20

坐标 x y 就应该是

x = col×块宽 y = row×块高

 

实现移动

根据移动方向 生成新的头部块next = snake[0] + 方向

将新生成的next 添加到snake数组的头部 我们用到unshift()方法

并且我们删除掉最后一个尾部元素 这样我们保证在不吃到食物的情况下 蛇的身体长度不变

这里我们使用pop()方法

如果吃到食物的话,我们就不删除尾部元素,使得snake体长+1

并且在别的地方生成新的食物

 

键盘事件

之前我们说到 KeyCode :左:37 上:38 右:39 下:40

对应到贪吃蛇的 左:-1 上:-20 右:+1 下:+20

贪吃蛇的方向数组为[-1 , -20, 1 , 20] 每个数组的index 为 0 , 1 , 2 , 3

那么这个 index 怎么和这个KeyCode取得联系呢

我们可以想到 index[KeyCode-37]

 

 

整明白以上的基础内容

我们开始正式的代码编写

 

首先 声明我们用到的一些变量

     var g_block = 30
     var g_row = 600 / g_block
     var g_col = 600 / g_block
     var g_margin = 1 //为了方块之间有空隙这样会更美观
 
     var snake = [45, 44, 43]  //蛇是由53,54,55游戏块组成的
     var food = 55   //自定义初始食物为58号游戏块
     var dirc = 1   //定义方向是向右移动1个单位
     var colors = ['#f5b6b3', '#ffebb5', '#89cff0']  //声明蛇的颜色 食物的颜色 和 背景颜色

 

然后我们自定义一个函数 setBlock

 function setBlock(id, color) {
     //我们声明setBlock函数
     let [row, col] = [~~(id / g_col), id % g_col]//为他的row和col赋值
     let [x, y] = [col * g_block, row * g_block]//对他的坐标赋值
     ctx.save()
     ctx.fillStyle = colors[color]
     ctx.fillRect(x, y, g_block - g_margin, g_block - g_margin)
     ctx.restore()
 }

~~ 取整的意思

在上面

 function setBlock(id, color)

我们在 setBlock 中传了两个参数 一个是 id 一个是 color

接下来我们会用到这两个参数

 

首先根据这个 setBlock 方法 我们先将我们的蛇体绘画出来

 snake.forEach(n => setBlock(n, 0))

这样我将snake里面三个方块都绘制成了淡粉色 也就是用到了第二个参数 color 值为'#f5b6b3'

效果如下

 

 

这样完成了初始三个游戏块的绘制

接下来就是绘制一个食物并让它下一步进行移动了

我们让他向右移动一格

也就是 在头部添加一个淡粉色的游戏块

在尾部删除最后一个游戏块

代码如下

 setBlock(food,1)
 //id为 food color:第一个元素
 //将food绘画出来
 
 //贪吃蛇的增添
 let next = snake[0]+dirc
 snake.unshift(next)
 setBlock(next,0)
 //id 为next color: 为第零个元素
 
 let tail = snake.pop()
 setBlock(tail)
 //id 为tail color 为第二个元素

这样的话,我们会得到这样一个效果

 

很明显,我们在尾部,删除的元素,他默认给绘制成了黑色

这样我们修改代码如下,让他删除,并将最后一个元素绘制成和背景一样的颜色

 setBlock(tail,2)

这个基本的移动规律是这样的

我们该怎么让他动起来呢

我们想到应该使用 定时器 setInterval

 

修改代码如下

 setInterval(() => {
     //贪吃蛇的增添
     let next = snake[0] + dirc
     snake.unshift(next)
     setBlock(next, 0)
     //id 为next color: 为第零个元素
 
     let tail = snake.pop()
     setBlock(tail, 2)
     //id 为tail color 为第二个元素
 
     // 但是我们该怎么让他动起来呢
     //我们想到用定时器
 
 }, 500)

这样我们就实现了贪吃蛇的基本移动

 

 

但是我们这样的话贪吃蛇移动了,但是他吃掉食物的时候

第一:他的身体没有增长

第二:没有生成新的食物

 

如图所示

 

 

我们做食物碰撞判断

修改代码如下

 setInterval(() => {
     //贪吃蛇的增添
     let next = snake[0] + dirc
     snake.unshift(next)
     setBlock(next, 0)
     //id 为next color: 为第零个元素
     if (next == food){
         //在其他地方生成新的食物,并绘制游戏块:食物
         food=~~(Math.random()*400)
         setBlock(food,1)
 
    }else {
         let tail = snake.pop()
         setBlock(tail, 2)
         //id 为tail color 为第二个元素
    }
 
 
     // 但是我们该怎么让他动起来呢
     //我们想到用定时器
 
 }, 500)

效果如下

 

这里我们存在一个小BUG是我们随机生成食物的时候

      food=~~(Math.random()*400)

因为我们是随机生成的,所以我们不知道我们是否是生成到蛇的身体上,这样就不符合实际了

我们先存在这个疑问

我们先实现根据上下左右键实现移动

 

实现自定义移动,我们用键盘事件 keyCode 来实现

首先我们做补充

键盘事件的一个监听事件

代码如下

 document.addEventListener('keydown', (event) => {
 console.log(event.code, event.keyCode)
 })

这样我们监听到键盘按下它的keyCode 我们检查一下控制台输出 keyCode

 

让他根据键盘的 keyCode 和方向数组为[-1 , -20, 1 , 20] 取得联系

上面我们有讲到 index[KeyCode-37]

完善代码如下

 document.addEventListener('keydown', (event) => {
     dirc = [-1, -20, 1, 20][event.keyCode - 37]
     console.log(dirc)
 })

我们控制台输出 dirc 应该就是 左:-1 上:-20 右:+1 下:+20

如图所示

 

这样我们就基本实现了贪吃蛇的基本移动效果

posted @   doudou帅  阅读(123)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示