贪吃蛇小游戏
具体实现
地图绘制
<!-- 绘制地图 地图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;
}
这样整个贪吃蛇游戏就制作完成了。
Comments NOTHING