JavaScript写个贪吃蛇小游戏(超详细)

贪吃蛇大家都玩过,但你会制作嘛?

听起来好像很难的样子,其实非常的简单,话不多说直接上代码。

我们先把dom结构写出来:

<div id="content">
<div id="snake">
<div class="box head"></div>
<div class="box"></div>
 
</div>
</div>

其中,content为整个布局的大盒子,snake就是蛇,里面的box就是他的身体,为了区分头部我们给第一个box加了个head名字用于区分,下面我们再把css加上。

<style>
.box{
width: 60px;
height: 60px;
background-color: red;
position:absolute;
left: 0;
top: 0;
line-height: 60px;
}
.head{
background-color: yellowgreen;
}
</style>

我们给蛇的每一节的宽高设置为60像素,并给了一个定位,因为如果不加定位的话无法让他脱离文档流(在页面中飘起来),而且后续也无法通过left和top来判断他的坐标。

file

好的这样我们就得到了一条可爱的小蛇(然而并没有看出来哪里可爱 - -)。

什么?你问我他的头哪去了,很简单,在给元素加了定位以后,后面的元素会覆盖掉前面的元素,所以只是头部和身体重叠了你看不到而已。

随后咱们得让这条蛇动起来是吧,那么我们怎么让他动起来呢?

原理很简单,我们可以设置一个定时器,每过一个时间就让他动一下。而怎么让他动呢,只需要设置一个数值,让这个值每动一下就+=60,然后通过判断是上下动还是左右动,来给元素的left与top赋值。

我们把逻辑写成代码,就出来了如下的代码:

<script>
var boxs = document.querySelectorAll(".box");
var snake_x = 0;
var snake_y = 0;
var turn = "right";
setInterval(function(){
snakeMove();
},100)
function snakeMove(){
switch( turn ){
case "right": snake_x += 60;break;
case "left" : snake_x -= 60;break;
case "top" : snake_y -= 60;break;
case "bottom": snake_y += 60;break;
}
 
for(var i = boxs.length - 1; i > 0 ; i --){
boxs[i].style.left = boxs[i - 1].style.left;
boxs[i].style.top = boxs[i - 1].style.top;
}
boxs[i].style.left = snake_x + "px";
boxs[i].style.top = snake_y + "px";
 
}
document.onkeydown = function(evt){
var e = evt || event;
var keyCode = e.keyCode || e.which;
switch( keyCode ){
case 37 : turn = "left";break;
case 38 : turn = "top";break;
case 39 : turn = "right";break;
case 40 : turn = "bottom";break;
}
}
 
</script>

上述代码中,我们给小蛇的初始位置的x和y的坐标都设置为0,并且默认初始向右走,通过键盘上方向键的输入,来改变他的方向。

其中,难点在于

for(var i = boxs.length - 1; i > 0 ; i --){
boxs[i].style.left = boxs[i - 1].style.left;
boxs[i].style.top = boxs[i - 1].style.top;
}
boxs[i].style.left = snake_x + "px";
boxs[i].style.top = snake_y + "px";

这一块代码,这块代码的目的是让后面的元素跟着前面的走,也就是让蛇的每一块身体都跟着上一块去运动,然后最后再给头部设置为snake_x和snake_y当前的值即可,这样就形成了第一块(头部)坐标为snake_x,snake_y实时变化的值,第二块为第一块之前的值,第三块为第二块之前的值。

以此类推就得到了一个身体跟着头部走的效果:

file

但是当你把代码输进去以后一运行会发现,这条小蛇过于顽皮,以至于走到边界以后还会无限的向前走,那这不行啊,总不能让蛇跑了不是,所以得给小蛇加上一个边界:

var snake_x_max = document.documentElement.clientWidth ;
var snake_y_max = document.documentElement.clientHeight;
if(snake_x > snake_x_max){
snake_x = 0;
}
if(snake_x < 0){
snake_x = snake_x_max;
}
if(snake_y > snake_y_max){
snake_y = 0;
}
if(snake_y < 0){
snake_y = snake_y_max;
}

这里我们设置x和y的最大值为当前窗口的宽高,然后通过if语句进行判断,如果当前坐标大于了最大值,就讲当前坐标归0,如果小于0的话(也就是跑到了左边的边界),就将当前坐标设置为最大值,这样就可以得到一个边界啦。

file

你以为这样就完事啦?nonono,没有食物吃的蛇怎么能叫做贪吃蛇呢,那是没有灵魂哒。

下面我们开始制作食物。

<div id="food">
</div>

然后给他加个css

#food{
width: 60px;
height: 60px;
position: absolute;
background: greenyellow;
}

然后再绑定一下元素并将他的left和top值设为范围内随机数,这样可以做到随机位置生成:

var fd=document.getElementById("food");
fd.style.left=Math.random()*snake_x_max+"px";
fd.style.top=Math.random()*snake_y_max+"px";

这样我们就得到了一个随机生成的食物:

file

不过我们的小蛇好像对食物并没有什么兴趣呢,路过以后并不会吃掉,所以我们得给他加一个碰撞检测吧。

碰撞检测的逻辑很简单,只需要让食物的left值与头部的left值相减的绝对值<=食物的大小,并且食物的top值与头部的top值相减的绝对值<=食物的大小,设置小于等于是因为如果直接用相等来判断的话,必须两个元素完全重合才行,我们需要的是碰到边缘就算迟到,所以用两个数值相减小于等于来做。

然后判断当头部与食物发生碰撞时,将蛇的身体部分克隆一块出来放到蛇的身体里面,并让食物的位置重新刷新。适用克隆为偷懒方法,此偷懒方法仅适用于当小蛇开局自带一个身体的时候,如果小蛇开局不自带身体的话,我们无法克隆已有身体,只能通过createElement去新创建一个身体块出来并添加className后再添加到父元素中去才行。

下面我们把逻辑转换为代码:

var dl=snake_x;
var dt=snake_y;
var fl=fd.style.left;
var ft=fd.style.top;
var dv=document.querySelectorAll("#snake div");
var sk=document.getElementById("snake");
var a2=Number(fl.substring(0,fl.indexOf("px")));
var b2=Number(ft.substring(0,ft.indexOf("px")));
if(Math.abs(dl-a2)<=60&&Math.abs(dt-b2)<=60){
fd.style.left=Math.random()*1000+"px";
fd.style.top=Math.random()*800+"px";
sk.appendChild(dv[1].cloneNode());
boxs = document.querySelectorAll(".box");
}

其中那一大长串的substring的方法是因为获取到的left与top的值的格式是例如”200px”这样的数组,无法进行数学运算,所以要把px给截掉,并将剩下的字符串”200”转换成number类型才可以进行数学运算。

file

这样一个简单的贪吃蛇就做好啦~

啥?你问我什么什么类似碰到自己会死这样更多的规则机制咋没写,肯定是因为我懒啊!我连createElement都懒得用直接克隆一个出来了,咋会勤快到把剩下这么多的机制补全呢哈哈。基础机制我已经写出来了,各种奇奇怪怪的机制还是留给小伙伴们自由发挥吧~

PS:大家完全可以把头部的背景图片改成你小伙伴的照片,再把食物改成一些你想让ta吃的东西,可以拿来恶搞啊!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容