之前用原生的JavaScrip
写过一次贪吃蛇,逻辑稍显复杂,后面用JQuery
做过一个优化,但是整体的效果不是很好,这里我们用vue2
来粗略地实现。
要让一条蛇在画板上跑,因此首先我们要新建一个画板元素div
,先暂时固定宽高,然后给定一个背景色,样式后面再来优化。
然后我们再来放一条蛇,新增一个list
的数据,然后初始化它的坐标为(0, 0)、(0, 1)、(0, 2)、(0, 3)、(0, 4)
,其中x
表示每一个元素位于多少行,y
表示位于多少列。
this.list = new Array(length).fill(0).map((el, index) => ({ x: 0, y: index }))
然后我们要v-if
渲染到画板上,同时配上位置函数,将每个元素都位置都放好。
getPosotion({ x, y }) {
return {
top: `${x * 20}px`,
left: `${y * 20}px`,
}
},
现在我们来让这条蛇元素动起来,很简单,列表中的数据,后一个的坐标来覆盖前一个的坐标即可,而最后一个元素,也就是蛇头,我们固定让它的y
自增1
就可以了。
const list = [...this.list]
const len = list.length
const head = list[len - 1]
list.forEach((item, index) => {
if (index < len - 1) {
const next = list[index + 1]
;[item.x, item.y] = [next.x, next.y]
}
})
head.y += 1
现在它就动起来了。
现在来想一个问题呢,如果定时器一直跑,蛇就跑出画板了,同时我们还不能控制方向,因此我们需要监听键盘的按下事件,同时,我们需要一个current
值来保存当前的方向。
addEventListener() {
document.addEventListener('keydown', ({ keyCode }) => {
this.current = keyCode
})
},
然后在移动的函数中,根据当前的方向值,来让蛇上下左右移动。
const keyCodes = {
LEFT: 37,
TOP: 38,
RIGHT: 39,
BOTTOM: 40,
}
switch (this.current) {
case keyCodes.RIGHT:
head.y += 1
break
case keyCodes.LEFT:
head.y -= 1
break
case keyCodes.BOTTOM:
head.x += 1
break
case keyCodes.TOP:
head.x -= 1
break
}
this.list = list
现在,我们的大蛇可以上下左右移动了。
然后再来考虑碰撞问题,无非就是四个边界,还有就是自身也可能发生碰撞,这里直接上代码。边界碰撞只需要判断头部元素的坐标值和边界之间的关系,而自身碰撞,需要头部坐标与除了头部以外的剩余蛇身体部分的坐标做比较,如果有一个相等,some
再好不过,那么就是碰撞了自身,游戏将结束。
isImpact() {
const len = this.list.length
const { x: headX, y: headY } = this.list[len - 1]
const { cols, rows } = this.getRowsCols()
if (this.list.slice(0, len - 1).some(({ x, y }) => x === headX && y === headY)) {
return true
}
if (headY >= cols) {
return true
}
if (headX >= rows) {
return true
}
if (headX < 0) {
return true
}
if (headY < 0) {
return true
}
return false
},
这里就是自己撞自己的情况。
以上情况都解决之后呢,我们再来考虑生成苹果的情况,蛇嘛,让吃此苹果就行了。逻辑上也很简单,根据画布的情况,随机生成一个苹果,然后我们要判断每一个方向时,只要苹果的坐标和蛇头的坐标满足条件与否。举个栗子,假设蛇往右移动,那么就是current
为RIGHT
的keycode
时,且苹果的x
和蛇头的x
相同,而蛇头的y + 1
是等于苹果的y
的话,表明蛇可以吃苹果,然后我们往list
中push
一个空对象就可以了。为什么是空对象呢,因为下一次移动时,空对象将被上一个对象覆盖。
canEat() {
const len = this.list.length
const { x: headX, y: headY } = this.list[len - 1]
const { x, y } = this.apple
if (this.current === keyCodes.RIGHT) {
if (headY + 1 === y && headX === x) {
return true
}
}
if (this.current === keyCodes.LEFT) {
if (headY - 1 === y && headX === x) {
return true
}
}
if (this.current === keyCodes.TOP) {
if (headX - 1 === x && headY === y) {
return true
}
}
if (this.current === keyCodes.BOTTOM) {
if (headX + 1 === x && headY === y) {
return true
}
}
return false
},
一个简单的贪吃蛇就完成了,你可以添加一些得分,或者暂停按钮,或者其它的样式,这里是完整的代码。
你已经GG了!!!
重新开始
最后的效果。