JS源码写个贪吃蛇
1.写想好贪吃蛇的组成部分:
首先是初始的蛇头蛇身,蛇头的运动是根据键盘的上下左右来的,需要用到键盘事件,蛇身必须跟着蛇头走后面新加的也是。
再就是碰撞算法用于计算蛇头碰到食物后食物的位置发生随机改变以及自身蛇尾要加一块。
所以后面引出食物的随机位置算法以及DOM操作让蛇体多加一截元素。
最后就是判断游戏输的算法,那么下面我们细说。
2.一些现成的或者容易找到的我们就不谈了,比如键盘事件和运动框架。
我们说一下算法部分,首先是蛇运动出可视区的处理
if(oEvent.keyCode==37) //左上右下 成键盘顺时针
{
clearTimeout(timer)
startMove(oDiv,{left:-100})
function zuoyi()
{
if(oDiv.offsetLeft<-10)
{oDiv.style.left=document.documentElement.clientWidth-200-10+'px'}
}
timer=setInterval(zuoyi,100)
}
交代下这里的oDiv是蛇头。做一个左移的判断条件,如果出左框的话就把他拉到右边界。其他方向同理,这个判断出框函数需要用定时器调用,隔很小的间隔就需要调用来判断。注意这里因为后面我添加了右侧的计分板,所以拉回的时候oDiv.style.left要多减200px
3.食物的随机出现
function random()
{
var num1=Math.floor(Math.random()*(document.documentElement.clientWidth-10-200))
var num2=Math.floor(Math.random()*(document.documentElement.clientHeight-20))
oDiv2.style.left=num1+'px'
oDiv2.style.top=num2+'px'
}
random();
注:oDiv2是食物。在加载页面进去的时候就出现一次,同时在后面吃到食物的时候这个函数还要再调用一次。
4.蛇头与食物的碰撞检测
function comparePostion()
{
var deltaLeft=Math.abs(oDiv2.offsetLeft-oDiv1.offsetLeft)
var deltaHeight=Math.abs(oDiv2.offsetTop-oDiv1.offsetTop)
if(deltaHeight<8&&deltaLeft<8)
{
random();
score=score+1
var oLi=document.createElement('li')
oUl.appendChild(oLi)
oScore.innerHTML=score
}
}
注:这里的oDiv1也是蛇头,我是分开了两个script写的。这里判断条件if(deltaHeight<8&&deltaLeft<8)的8可以看自己调整。score是最后的分数计算,这里可以先别管。
5.蛇身跟随蛇头算法
function follow()
{
var lis=document.getElementsByTagName('li')
for(let i=lis.length-1;i>0;i--)
{
lis[i].style.left=lis[i-1].offsetLeft+'px'
lis[i].style.top=lis[i-1].offsetTop+'px'
}
}
var timer1
timer1=setInterval(follow,50)
6.判断游戏输的算法
function loss()
{
var lis=document.getElementsByTagName('li')
var oDiv1=document.getElementById('tou')
for(var i=lis.length-1;i>1;i--)
{
var dLeft=Math.abs(oDiv1.offsetLeft-lis[i].offsetLeft)
var dHeight=Math.abs(oDiv1.offsetTop-lis[i].offsetTop)
if((dLeft>=0&&dLeft<=5)&&(dHeight>=0&&dHeight<=5))
{alert('you have lost'+'你的得分为'+score)}
}
}
这里有几个问题:第一,我的follow函数每5ms进行一次,**所以我们进去页面的时候三个li是重合在一起的,如果一开始就执行loss函数那么一开始就会弹出失败弹窗。**所以我们引入一个新函数
function Xloss()
{
timer5=setInterval(loss,5)
}
var timer8=setTimeout(Xloss,5000)
这样的话让5秒之后带着loss算法的时钟再开启。**这样的问题就会导致开始5s内用户允许有“无敌”操作,或者用户5s内没有进行游戏就会弹出失败弹窗。**这个是我设计的一个问题,如果有更好的问题希望大佬们能给点意见哈。
第二个问题,就是我输的判断函数每隔几ms执行和我的运动跟踪follow每隔几ms执行以及我的运动框架里写的蛇头每隔几ms运动一次,一次运动几px都有大学问。这个问题是最难处理的。
我原本是这样写的,每隔50ms运动10px,每隔50ms执行follow一次,每隔5ms判断输赢。这样走着走着就会被判输,原因就是50是5的倍数。到第50ms的时候这几个函数同时执行此时 蛇头的位置赋值给第二个li,第二个li赋值给第三个,这时候dLeft、dHeight都会等于0而满足条件,从而判输。但其实就算你设个每隔7ms判断输赢其实也会到350ms的时候给你判输,所以改这个不是重点。
解决办法:
1.让跟随算法在键盘第一次点击之后才开始执行。
document.οnkeydοwn=function(ev)
{
downCount++
if(downCount==1){
var timer1
timer1=setInterval(follow,50)
}
...
}
2.同时运动频率要保持1ms 1px
保证游戏初始时间内第三个li与蛇头的li的位置不会在1ms内完成位置赋值触发游戏失败条件。
7.运行截图:
最后:新手小白,有什么说的不对或者不清楚的地方还请大佬们多指点担待。