- 要完成这个游戏,首先要了解蛇是由一个一个的点组成的,然后这个点要有位置、颜色,关键的还要有下一个点的基本位置信息,不然怎么知道这个点的下一个运动位置呢。上代码:
class Dot { constructor(x,y,color){ this.color = color this.x = x this.y = y this.next = null ctx.fillStyle = this.color ctx.beginPath() ctx.arc(x,y,5,0,2*Math.PI) ctx.fill() } reDraw() { ctx.fillStyle = this.color ctx.beginPath() ctx.arc(this.x,this.y,5,0,2*Math.PI) ctx.fill() } }
reDraw()方法就是对这个点的重画,点位置移动后重新画上去。
-
随机点的生成。随机点的位置其实也不是随机的,最基本的它不能超出画布范围,还有重要的一点就是它的位置必须是蛇可以经过的地方,可能说的不是很明白。但是大家应该都能明白..比如上边的代码设置的点的半径为5px,所以这个随机点的x、y都必须是5的整数倍,不然的话蛇就可能不会和随机点正面相撞,也就是虽然相遇了,但不在一条直线上。代码:
//生成随机点 function randomDot () { let x = parseInt(Math.random()*10 + 1) * (width-100)/10 let y = parseInt(Math.random()*10 + 1) * (height-100)/10 //判断点不在snake上,如果存在,重新生成 for(let dot of snake){ if(dot.x == x && dot.y == y){ return randomDot() } } return new Dot(x,y,'white') }
-
碰撞的判断。我判断碰撞就是简单的比较一下蛇头的x、y坐标和随机点的坐标是否一致
-
方向的控制。这个我想大家都会就不多说了:
window.onkeydown = function(eve){ switch(eve.keyCode){ case 38: dir = 'up' break; case 40: dir = 'down' break; case 37: dir = 'left' break; case 39: dir = 'right' break; } }
-
最后一步就是贪吃蛇的移动(画布刷新)、判断碰撞、长大、游戏失败等等的逻辑了。
通过setInterval来刷新画布,贪吃蛇使用一个存储‘点’的数组来表示,最后一个元素作为蛇头,通过点的next属性来判断每一个点下次的位置。需要注意的是蛇头的next为空,需要根据运动方向计算出来:nextDot(dot)。把点的x、y重新赋值,以及点的next信息重新赋值以后,调用reDraw()方法重新在画布上画出来就可以了。
代码: -
let time = 500 let refresh = setInterval(()=>updateCanvas(),time) function updateCanvas(){ ctx.clearRect(0,0,width,height) currentDot.reDraw() let dot = snake[snake.length - 1] snake[snake.length - 1] = nextDot(dot) //非末尾元素 for(let i = 0; i < snake.length-1; i++){ let next = snake[i].next let sNext = snake[i+1] snake[i] = new Dot(next.x,next.y,'red') if(sNext.next == null){ snake[i].next = new Dot(dot.x,dot.y,'red') }else{ snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red') } snake[i].reDraw() } if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){ clearInterval(refresh) alert("游戏结束...") } if(dot.x == currentDot.x && dot.y == currentDot.y){ score += 5 document.getElementById('score').innerHTML = score dot.next = currentDot dot.color = 'red' snake.push(currentDot) currentDot = randomDot() //吃到一个点,速度变快 clearInterval(refresh) time = time - 50 if(time <= 50) time = 50 refresh = setInterval(()=>updateCanvas(),time) } dot.reDraw() }
下面是完整的代码:
<!DOCTYPE html> <html> <head> <title>贪吃蛇</title> </head> <body> <div style="width: 1030px"> <canvas id="canvas" width="900" height="500" style="background-color: #2a8e2a;float: left;"></canvas> <div style="float: right;">得分:<h5 id="score" style="display: inline;">0</h5></div> <div style="float: right;"><button onclick="stopOrRun(this)">暂停</button> </div> <div><button onclick="speedUp()">加速</button> <button onclick="speedDown()">减速</button></div> </div> </body> <script type="text/javascript"> let ctx = document.getElementById('canvas').getContext('2d') let width = 900 let height = 500 let score = 0 let isRun = true class Dot { constructor(x,y,color){ this.color = color this.x = x this.y = y this.next = null ctx.fillStyle = this.color ctx.beginPath() ctx.arc(x,y,5,0,2*Math.PI) ctx.fill() } reDraw() { ctx.fillStyle = this.color ctx.beginPath() ctx.arc(this.x,this.y,5,0,2*Math.PI) ctx.fill() } } let dir = 'right' //初始化snake let snake = new Array() let len = 5 for(let i = 1; i <= len; i++){ let nextDot = null if(i < len) nextDot = new Dot(10 * (i+1),50,'red') let dot = new Dot(10 * i,50,'red') if(i === len) dot.color = 'white' dot.next = nextDot snake.push(dot) } let currentDot = randomDot() //生成随机点 function randomDot () { let x = parseInt(Math.random()*10 + 1) * (width-100)/10 let y = parseInt(Math.random()*10 + 1) * (height-100)/10 //判断点不在snake上,如果存在,重新生成 for(let dot of snake){ if(dot.x == x && dot.y == y){ return randomDot() } } return new Dot(x,y,'white') } let time = 500 let refresh = setInterval(()=>updateCanvas(),time) function updateCanvas(){ ctx.clearRect(0,0,width,height) currentDot.reDraw() let dot = snake[snake.length - 1] snake[snake.length - 1] = nextDot(dot) //非末尾元素 for(let i = 0; i < snake.length-1; i++){ let next = snake[i].next let sNext = snake[i+1] snake[i] = new Dot(next.x,next.y,'red') if(sNext.next == null){ snake[i].next = new Dot(dot.x,dot.y,'red') }else{ snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red') } snake[i].reDraw() } if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){ clearInterval(refresh) alert("游戏结束...") } if(dot.x == currentDot.x && dot.y == currentDot.y){ score += 5 document.getElementById('score').innerHTML = score dot.next = currentDot dot.color = 'red' snake.push(currentDot) currentDot = randomDot() //吃到一个点,速度变快 clearInterval(refresh) time = time - 50 if(time <= 50) time = 50 refresh = setInterval(()=>updateCanvas(),time) } dot.reDraw() } function nextDot(dot){ switch(dir){ case 'right': dot.x = dot.x + 10 break; case 'left': dot.x = dot.x - 10 break; case 'up': dot.y = dot.y - 10 break; case 'down': dot.y = dot.y + 10 break; } return dot } window.onkeydown = function(eve){ switch(eve.keyCode){ case 38: dir = 'up' break; case 40: dir = 'down' break; case 37: dir = 'left' break; case 39: dir = 'right' break; } } function stopOrRun (obj) { if(isRun){ obj.innerHTML = '运行' clearInterval(refresh) isRun = false }else{ obj.innerHTML = '暂停' refresh = setInterval(()=>updateCanvas(),time) isRun = true } } function speedUp() { time -= 10 clearInterval(refresh) if(time <= 50) time = 50 refresh = setInterval(()=>updateCanvas(),time) } function speedDown() { time += 10 clearInterval(refresh) if(time <= 50) time = 50 refresh = setInterval(()=>updateCanvas(),time) } </script> </html>
-
over。
转载于:https://my.oschina.net/xiwanglr/blog/1493105