基于Vue2实现贪吃蛇【中秋主题暨月更挑战第20天】

94 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情 >>

前言

回忆最开始做编程的初心,找回曾经的热爱与激情

实现思路

贪吃蛇的玩儿法就是在一张有限大小的棋盘上,通过上下左右变换蛇移动的方向去吃掉随机位置出现的食物,蛇不可以撞墙,不能撞到自己。了解完玩儿法之后,我们就是一步步基于面向对象是去实现贪吃蛇.

创建棋盘与背景

背景的话,我们找一张好看的图片,作为背景即可

<style lang="less" scoped>
.home{
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-image: url('~@/assets/bg1.jpeg');
  background-size: cover;
  background-position: center;
  position: relative;
  .pan{
    width: 90%;
    height: 90%;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    background: rgba(255, 255, 255, 0.5);
    display: flex;
    flex-wrap: wrap;
    border-left: 1px solid #f4f4f4;
    border-top: 1px solid #f4f4f4;
    &>div{
      width: 2%;
      height: 2.5%;
      border-right: 1px solid #f4f4f4;
      position: relative;
      border-bottom: 1px solid #f4f4f4;
    }
  }
}
</style>

棋盘的话,我们创建50*40一共2000个格子,使用vue 的话,就是v-for进行循环即可

<div class="home">
<div class="pan">
  <template v-for="i in 40" >
    <template v-for="k in 50" >
      <div :key="`${i}_${k}`" :id="`${i}_${k}`"></div>
    </template>
  </template>
</div>
</div>

创建好的棋盘如下

image.png

接下来,就是基于面向对象去创建蛇了

创建蛇

首先,一开始我们让蛇的长度为3,从棋盘的左上角开始,那么蛇占据的坐标就是0,0,0,1,0,2

xyMap: { '1_1': true, '1_2': true, '1_3': true },
xy: [
{ x: 1, y: 1 },
{ x: 1, y: 2 },
{ x: 1, y: 3 }
]

接下来,就需要把蛇放进棋盘里,我们通过动态添加class的方式来实现,修改一下之前遍历棋盘的代码,通过判断是否存在来返回动态类名.head

 <div :class="{head: judgeHead(x,y)}" :key="`${x}_${y}`" :id="`${x}_${y}`"></div>
 judgeHead (x, y) {
  return this.xyMap[`${x}_${y}`] ? 'head' : ''
}

image.png

放置食物小球

食物小球需要随机出现在棋盘上,并且不能出现在蛇身位置上。代码判断如下

//data
foodXy: null
// methods
 food () {
  // 不能放在蛇身上
  let x, y
  do {
    x = Math.floor(Math.random() * 40) + 1
    y = Math.floor(Math.random() * 50) + 1
  } while (this.xyMap[x + '_' + y])
  return { x, y }
}
 created () {
    this.foodXy = this.food()
  },

此时,棋盘上就已经有了蛇和我们的食物

image.png

让蛇动起来,然后根据按键变化方向

首先我们需要监听方向键事件,这里为了方便,我们直接使用方向键返回的key

//data
direction: 'ArrowRight'
// mounted
// ArrowLeft ArrowRight ArrowDown ArrowUp
document.onkeydown = (e) => {
  e.preventDefault()
  this.direction = e.key
}

然后就是根据方向让蛇动起来,这里我们通过setInterval的方式实现的方式实现

setInterval(() => {
      this.move()
    }, 200)
    
     move () {
      const oldHead = this.xy[this.xy.length - 1] // 原来的位置
      let newHead = { x: oldHead.x, y: oldHead.y } // 新的位置
      if (this.direction === 'ArrowRight') {
        newHead = { x: parseInt(oldHead.x), y: parseInt(oldHead.y) + 1 }
      } else if (this.direction === 'ArrowDown') {
        newHead = { x: parseInt(oldHead.x) + 1, y: parseInt(oldHead.y) }
      } else if (this.direction === 'ArrowUp') {
        const x = parseInt(oldHead.x) - 1 > 0 ? parseInt(oldHead.x) - 1 : 0
        newHead = { x: x, y: parseInt(oldHead.y) }
      } else if (this.direction === 'ArrowLeft') {
        const y = parseInt(oldHead.y) - 1 > 0 ? parseInt(oldHead.y) - 1 : 0
        newHead = { x: parseInt(oldHead.x), y }
      }
      this.xy.push(newHead)
      this.$set(this.xyMap, newHead.x + '_' + newHead.y, true)
      if (this.foodXy.x === newHead.x && this.foodXy.y === newHead.y) {
        this.foodXy = this.food()
      } else {
        const xy = this.xy.shift()
        delete this.xyMap[xy.x + '_' + xy.y]
      }
    }

这样,我们的蛇就动起来了,接下来,我们需要判断,蛇不可以撞墙,不能碰到自己,撞墙就是x,y坐标超出限制,撞到自己就是我们的newHead在xyMap中已存在,对吧,这样,我们优化一下move的代码

// 判断不能撞到自己
  for (const i in this.xyMap) {
    if (this.xyMap[newHead.x + '_' + newHead.y] === this.xyMap[i]) {
      clearInterval(this.t)
    }
  }
  this.xy.push(newHead)
 ....
  // 判断不能撞墙
  if (newHead.x + 1 > 40 || newHead.y + 1 > 50 || newHead.x < 0 || newHead.y < 0) {
    clearInterval(this.t)
  }

这样,我们就完成了贪吃蛇的基础功能了,可以移动,可以吃小球食物长大

image.png

下一篇,我们将继续完善贪吃的相关功能,把分值和速度以及暂停,移动动效加上,让我们的贪吃蛇更加的完美。下一篇完成后,将会把代码以代码片段的形式放出,欢迎大家试玩儿。