贪吃蛇小游戏

具体实现

地图绘制

<!-- 绘制地图 地图600*600,20行,20列 -->
    <div class="snake">
        <div class="title"><h1>贪吃蛇游戏</h1></div>
        <table border="1px" cellspacing="0" cellpadding="0">
        </table>
        <div id="map"></div>
        <div class="score_box">
            <h2>游戏结束,总分:0分</h2>
            <button>再玩一局</button>
            <button><a href="index.html">返回主页面</a></button>
        </div>
    </div>
/* 地图绘制 */
.snake {
    position: relative;
    width: 600px;
    margin: 100px auto 0;

}
.snake .title {
    width: 600px;
    height: 60px;
    text-align: center;
}
table {
    width: 601px;
    height: 601px;
    position: absolute;
    border-collapse: collapse;
}
td {
    width: 29px;
    height: 29px;
}
#map {
    position: relative;
    width: 600px;
    height: 600px;
}
.head {
    background-image: url(../image/head.png);
    background-size: 100% 100%;
}
.body {
    background-image: url(../image/body.png);
    background-size: 100% 100%;
}
.food {
    background-image: url(../image/apple.png);
    background-size: 100% 100%;
}
.score_box {
    display: none;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -100px;
    margin-left: -300px;
    padding-top: 30px;
    width: 600px;
    height: 170px;
    background-color:#ccc;
}
.score_box h2 {
    text-align: center;
}
.score_box button {
    float: left;
    width: 150px;
    height: 40px;
    cursor: pointer;
    margin: 50px 0 0 100px;
    font-size: 18px;
}
.score_box a {
    display: block;
    width: 150px;
    height: 40px;
    line-height: 40px;
    color: #000;
}

地图的网格线使用600×600的表格绘制处理的,20行,20列,再用一个大小600×600的盒子用定位覆盖表格,还有一个积分盒子隐藏起来,如果贪吃蛇触发死亡判断就让盒子显示。

绘制初始蛇

我们把蛇分为蛇头与蛇身,和食物都放在一个div里面,根据属性通过一个创建div的函数创建它,放到map大盒子里,然后通过定位确定它的位置。

 function createDiv(index, top, left) {
        var node = document.createElement('div');//创建一个div节点
        node.style.width = "30px";
        node.style.height = "30px";
        node.style.position = "absolute";
        node.style.top = top + 'px';
        node.style.left = left + 'px';
        map.appendChild(node);
        node.setAttribute('class', index);
        return node;
    }

然后定义一个对象数组,创建一个三节点的初始蛇

 //创建一个三节点蛇
 var x = 0;
 var y = 0;
 var snake = [{ x: 0, y: 2 }, { x: 0, y: 1 }, { x: 0, y: 0 }];
 //画蛇
 function drawSnake() {
    for (var i = 0; i < snake.length; i++) {
         if (i == 0) {
             createDiv('head', snake[i].x * 30, snake[i].y * 30);
        } else {
             createDiv('body', snake[i].x * 30, snake[i].y * 30);
        }
     }
}

绘制食物

利用随机数初始化食物坐标,还需要判断食物不能生成再蛇身上,如果生成到蛇身上就重新生成食物,再次判断,直到食物没有生成到蛇身上。

//初始化食物
var food_x = Math.floor(Math.random() * 20);
var food_y = Math.floor(Math.random() * 20);
//判断食物不能在蛇身上
function isSnake() {
     for (var i = 0; i < snake.length; i++) {
          if (snake[i].x == food_x && snake[i].y == food_y) {
           return true;
        }
     }
     return false;
}
function food() {
    //食物不能生成在蛇身上
    while (isSnake()) {
         food_x = Math.floor(Math.random() * 20);
         food_y = Math.floor(Math.random() * 20);
    }
         createDiv('food', food_x * 30, food_y * 30);
    }
//生成食物
food();

按键监测

我们通过键盘事件监听蛇头上下左右移动方向,注意之前div盒子使用定位来确定位置,向下向右为正,向上向左为负,同时还需要注意不要让蛇调头,在条件判断中加入限定。

//初始化移动方向,默认向右移动
var direct_x = 0;//1代表向下移动,-1代表向上移动
var direct_y = 1;//1代表向右移动,-1代表向左移动
document.addEventListener('keydown', function (event) {
//上38 下40 左37 右39
      switch (event.keyCode) {
            case 38:
            //防止蛇调头
            if (direct_x != 1) {
                 direct_x = -1;
                 direct_y = 0;
            }
            break;
            case 40:
              if (direct_x != -1) {
                  direct_x = 1;
                  direct_y = 0;
              }
            break;
            case 37:
              if (direct_y != 1) {
                  direct_x = 0;
                  direct_y = -1;
              }
              break;
            case 39:
              if (direct_y != -1) {
                  direct_x = 0;
                  direct_y = 1;
              }
              break;
      }
})

同时因为我们准备蛇头的方向是默认向右的,触发上下左右按键时要使得蛇头顺着上下左右旋转

//根据上下左右判断蛇头转向 向右默认 由于既往蛇被清除,蛇头节点在第二个
if (direct_x == -1 && direct_y == 0) {
    map.children[1].style.transform = 'rotate(270deg)';
} else if (direct_x == 0 && direct_y == -1) {
    map.children[1].style.transform = 'rotate(180deg)';
} else if (direct_x == 1 && direct_y == 0) {
    map.children[1].style.transform = 'rotate(90deg)';
}

蛇的移动

蛇的移动用canvas写就是一个擦除重绘的过程,我们的处理方法也一样,先把map盒子里面的原先的蛇头蛇身节点都给干掉,然后通过方向生成新蛇头的坐标,完成蛇头的移动,蛇身的移动就是下一个节点移动到上一个节点,最后还会剩下一个尾节点,用数组的pop方法去掉就行了,后来如果蛇吃食物判断的时候,蛇吃到食物身体会变长,我们就保留那个尾节点。

function move() {
    // 删除既往画的蛇
    var head = document.querySelectorAll('.head');
    var body = document.querySelectorAll('.body');
    for (var i = 0; i < head.length; i++) {
        map.removeChild(head[i]);
    }
    for (var j = 0; j < body.length; j++) {
        map.removeChild(body[j]);
    }
    //蛇头移动,创建新蛇头,老蛇头变成蛇身第二个节点
    var newNode = {
        x: snake[0].x + direct_x,
        y: snake[0].y + direct_y
    }
    snake.unshift(newNode);
    ······
}

然后触发定时器使得完成蛇的移动,定时器的执行间隔时间在难度设置页面已经设置,从会话储存对象里面拿到,默认为简单难度,同时通过键盘监听事件完成空格键控制蛇的移动与暂停。

//初始化难度,默认为简单难度 1s蛇移动一次
var speed = sessionStorage.getItem('snakeSpeed');
//如果没有设置难度,默认简单难度
if (speed == null) {
    speed = 500;
}
var timer = setInterval(move, speed);
//定时器使得蛇可以移动 按空格键蛇暂停 
document.addEventListener('keydown', function (event) {
    if (event.keyCode == 32 && flag == 0) {
        clearInterval(timer);
        flag = 1;
    } else if (event.keyCode == 32 && flag == 1) {
        timer = setInterval(move, speed);
        flag = 0;
    }
})

蛇吃食物

蛇吃食物的判断就是蛇头与食物坐标重合,吃到食物后食物消失,重新生成新食物,蛇身变长,然后积分增加10分。

//初始化分数
var score = 0;
//初始化标记食物是否被吃
var isEated = false;
//蛇吃食物 蛇吃到食物食物消失并随机生成,蛇生长一格
if (newNode.x == food_x && newNode.y == food_y) {
    isEated = true;
    score += 10;//吃到食物加分
} else {
    isEated = false;
    // 没吃到食物清除尾节点
    snake.pop();
}
//吃到食物,食物再次生成
if (isEated) {
    //清除老食物
    map.removeChild(map.children[0]);
    //生成食物
    food();
}

死亡判断

死亡判断分为蛇头撞墙会死,蛇头撞蛇身也会死,死了以后弹出积分对话框

//判断游戏结束,如果超出边界游戏结束
if (newNode.x < 0 || newNode.y < 0 || newNode.x * 30 >= 600 || newNode.y * 30 >= 600) {
    isGameOver = true;
}
//蛇头撞到自己游戏结束
for (var k = 0; k < snake.length; k++) {
    if (newNode.x == snake[k].x && newNode.y == snake[k].y) {
        isGameOver = true;
    }
}
if (isGameOver) {
    score_box.style.display = "block";
    score_text.innerHTML = "游戏结束,总分:" + score + '分';
    return;
}

这样整个贪吃蛇游戏就制作完成了。

具体代码:https://github.com/diguaaixiaran/snake