主要有五个知识点,一一道破,首先是监听键盘事件:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
<h1>按键事件</h1>
<div id="keypress"></div>
<div id="keydown"></div>
<div id="keyup"></div>
<script>
document.onkeypress = function(e) {
document.getElementById('keypress').innerText = 'press : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
}
document.onkeydown = function(e) {
document.getElementById('keydown').innerText = 'down : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
}
document.onkeyup = function(e) {
document.getElementById('keyup').innerText = 'up : ' + e.keyCode + ' ' + e.which + ' ' + e.charCode;
}
</script>
</body>
check the result
按键相关的东西就是三个:document.onkeypress、document.onkeydown、document.onkeyup,分别表示字符按键、按下和弹起,键的信息都在参数e中,onkeypress只有按到字符键才有效,onkeydown和onkeyup基本对所有键都有效,所以贪吃蛇的上下左右用onkeydown就好。
接下来是每隔一定时间就触发动作,其实专业术语叫定时器:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
<h1>定时器</h1>
<button id="start">开始</button>
<button id="stop">停止</button>
<div id="num"></div>
<script>
var i = 0;
var timer = undefined;
document.getElementById('start').onclick = function() {
timer = setInterval(function(){
i++;
document.getElementById('num').innerText = i;
}, 500);
document.getElementById('start').disabled = true;
document.getElementById('stop').disabled = false;
};
document.getElementById('stop').onclick = function() {
if(timer) {
clearInterval(timer);
timer = undefined;
}
document.getElementById('start').disabled = false;
document.getElementById('stop').disabled = true;
};
document.getElementById('stop').disabled = true;
</script>
</body>
check the result
这里的重点是setInterval函数,第一个参数是回调函数,第二个参数是时间间隔,单位ms,这个函数会返回一个timer,代表定时器,当我们要取消定时器的时候,就调用clearInterval,将setInterval返回的timer作为参数传进去。还有就是可以通过设置元素的disabled为true或false来控制按钮的可点击状态。
再接下来就是随机数了,这个也很简单:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<body>
<h1>产生1~100的随机数</h1>
<button id="btn">产生随机数</button>
<div id="num"></div>
<script>
document.getElementById('btn').onclick = function() {
var ran = Math.random();
var res = Math.ceil(ran * 100);
document.getElementById('num').innerText = res;
};
</script>
</body>
check the result
Math.ramdon产生0~1之间的随机数,但是是小数,要把它变成1~100的整数,只需要乘以100,再向上去整就好了。
然后是二维地图的实现:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
.map {
width : 400px;
height : 400px;
border : 5px solid brown;
background-color : transparent;
position : relative;
}
.snakehead, .snake, .target {
width : 20px;
height : 20px;
position : absolute;
}
.snakehead {
background-color : pink;
}
.snake {
background-color : red;
}
.target {
background-color : blue;
}
</style>
<body>
<h1>二维地图</h1>
<div class="map">
<div class="snakehead" style="top:0px;left:0px;"></div>
<div class="snake" style="top:20px;left:0px;"></div>
<div class="snake" style="top:40px;left:0px;"></div>
<div class="snake" style="top:60px;left:0px;"></div>
<div class="target" style="top:60px;left:60px;"></div>
</div>
</body>
check the result
这里用了一个relative的div作为map,然后里面蛇和食物都是absolute的div,移动的时候只要设置它们的left和top就行了。注意这里的样式设置,.snakehead, .snake, .target就可以设置.snakehead、.snake和.target的公共样式。
最后是动态添加蛇身:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
.map {
width : 400px;
height : 400px;
border : 5px solid brown;
background-color : transparent;
position : relative;
}
.snake {
width : 20px;
height : 20px;
position : absolute;
background-color : red;
}
</style>
<body>
<h1>动态添加DOM元素</h1>
<button id="add">添加</button>
<div class="map" id="map"></div>
<script>
var myLeft=0;
var myTop=0;
document.getElementById('add').onclick = function() {
if(myTop < 400) {
var newNode = document.createElement('div');
newNode.className = 'snake';
newNode.style.top = myTop + 'px';
newNode.style.left = myLeft + 'px';
document.getElementById('map').appendChild(newNode);
myLeft += 20;
if(myLeft >= 400) {
myLeft = 0;
myTop += 20;
if(myTop >= 400) {
window.alert('满了');
}
}
}
};
</script>
</body>
check the result
首先我们用document.createElement来创建一个div,然后设置它的一些属性,最后用document.getElementById('map').appendChild(newNode),把它加到map中,这样就动态添加了一个div。
好了,基本的知识点都已经打通,接下来就打大BOSS了:
<!DOCTYPE html>
<head>
<meta charset=utf-8 />
<title>贪吃蛇游戏</title>
</head>
<style>
.map {
width : 400px;
height : 400px;
border : 5px solid brown;
background-color : transparent;
position : relative;
}
.snakehead, .snake, .target {
width : 20px;
height : 20px;
position : absolute;
}
.snakehead {
background-color : pink;
}
.snake {
background-color : red;
}
.target {
background-color : blue;
}
</style>
<body>
<h1>贪吃蛇</h1>
<div class="map" id="map"></div>
<script>
// 0:up 1:left 2:down 3:right
var dir = 3;
var step = [{dx : 0, dy : -20}, {dx : -20, dy : 0}, {dx : 0, dy : 20}, {dx : 20, dy : 0}];
// the snake, a array of div
var snake = [];
// the snake target
var target;
// timer
var timer = undefined;
// can not act two key in one interval
var isKey = false;
// add snake
var add = function(left, top, className) {
var newNode = document.createElement('div');
newNode.className = className;
newNode.style.left = left + 'px';
newNode.style.top = top + 'px';
document.getElementById('map').appendChild(newNode);
snake.push(newNode);
};
// judge the target in snake
var inSnake = function(newx, newy, type) {
var start = 0;
if(type == 'all') {
start = 0;
} else if(type == 'body') {
start = 1;
}
for (var i = start; i<snake.length; i++) {
if(parseInt(snake[i].style.left) == newx && parseInt(snake[i].style.top) == newy) {
return true;
}
}
return false;
};
// new target
var newTarget = function() {
var newx = -1;
var newy = -1;
while(newx == -1 || newy == -1 || inSnake(newx, newy, 'all')) {
newx = (Math.floor(Math.random()*20) * 20);
newy = (Math.floor(Math.random()*20) * 20);
}
target.style.left = newx + 'px';
target.style.top = newy + 'px';
};
// snake move
var move = function() {
// calculate next head pos
var nextx, nexty;
nextx = parseInt(snake[0].style.left) + step[dir].dx;
nexty = parseInt(snake[0].style.top) + step[dir].dy;
// is Game Over?
if(nextx < 0 || nextx > 380 || nexty < 0 || nexty > 380) {
clearInterval(timer);
window.alert('Game Over!');
return;
}
// move
var tailLeft = snake[snake.length-1].style.left;
var tailTop = snake[snake.length-1].style.top;
for(var i=snake.length-1; i>0; i--) {
snake[i].style.left = snake[i-1].style.left;
snake[i].style.top = snake[i-1].style.top;
}
snake[0].style.left = nextx + 'px';
snake[0].style.top = nexty + 'px';
// is get food?
if(nextx == parseInt(target.style.left) && nexty == parseInt(target.style.top)) {
add(parseInt(tailLeft), parseInt(tailTop), 'snake');
newTarget();
}
// snake head meet snake body
if(inSnake(parseInt(snake[0].style.left), parseInt(snake[0].style.top), 'body')) {
clearInterval(timer);
window.alert('Game Over!');
return;
}
isKey = false;
}
add(60, 20, 'snakehead');
add(40, 20, 'snake');
add(20, 20, 'snake');
target = document.createElement('div');
target.className = 'target';
newTarget();
document.getElementById('map').appendChild(target);
// key event
document.onkeydown = function(e) {
if(!isKey) {
if(e.keyCode == 38) { //up
if(dir != 2) {dir = 0; isKey = true;}
} else if(e.keyCode == 39) { //right
if(dir != 1) {dir = 3; isKey = true;}
} else if(e.keyCode == 40) { //down
if(dir != 0) {dir = 2; isKey = true;}
} else if(e.keyCode == 37) { //left
if(dir != 3) {dir = 1; isKey = true;}
}
}
};
// timer
timer = setInterval(move, 100);
</script>
</body>
check the result
这里用了snake作为一个数组,每个元素是一个div的Element,然后就是游戏结束的条件,有两个,一个是蛇碰到墙壁,一个是蛇碰到自身,主要逻辑就是蛇吃到食物的时候,蛇身要变长,然后食物随机换一个位置,当然不能与蛇身重合。当然游戏的细节比较多的,可以结合代码理解。
这个游戏调了两天,虽然规则很简单,但是细节还是需要花费精力的。
,不要超过100元哦!