游戏界面
思路
- 用table画地图
- 每个td给一个id当做坐标,格式(x_y)
- 怎么区分食物、蛇与空白区域(行动的区域)?
- 食物添加类(.food)
- 蛇身体添加类(.black)
- 空白区域添加类(.white)
- 怎么让蛇移动?
- 给蛇对象添加一个默认行进方向
- setInterval设置定时器
- 每隔一段时间让蛇朝着该方向移动
- 蛇对象存储坐标数组,目的为了更方便控制蛇的移动(使用id找到蛇的身体)
- 坐标数组整体后移一位(插入新的蛇头坐标),再删除原蛇尾坐标
- 怎么判断蛇的碰撞与吃到自己身体?
- 根据td的类来判断
- 吃到食物怎么办?
- 吃到食物改变逻辑,移动后不删除蛇尾
index.html
<!DOCTYPE html>
<html lang="zh_CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
<link rel="stylesheet" href="game.css">
<title>贪吃蛇</title>
</head>
<body>
<p id="score">得分:<span id="score_number">0</span></p>
<table cellpadding="0" cellspacing="0" id="playground"></table>
<script src="game.js"></script>
</body>
</html>
game.css
#playground{
border-collapse: collapse;
margin: auto;
}
#playground td{
width: 15px;
height: 15px;
border: 1px solid gainsboro;
}
#score_number{
color: tomato;
font-size: larger;
}
.black{
background: black;
}
.white{
background: white;
}
.food{
background: greenyellow;
}
game.js
// 地图宽
var map_width = 30;
// 游戏定时器
var timer;
// 蛇对象
var snake;
function setClass(id, cn) {
$(id).removeClass();
$(id).addClass(cn);
}
// 产生食物
function createFood() {
let x, y;
let idName;
do {
x = Math.floor(Math.random() * map_width);
y = Math.floor(Math.random() * map_width);
idName = '#' + x + '_' + y;
} while ($(idName).hasClass('black'));
setClass(idName, 'food');
}
// 创建蛇对象
function Snake() {
// 初始长度3
this.snakeBody = [
[1, 3],
[1, 2],
[1, 1]
];
// 初始方向
this.direction = "right";
// 初始化小蛇
for (let i = 0; i < this.snakeBody.length; ++i) {
let x = this.snakeBody[i][0];
let y = this.snakeBody[i][1];
let idName = '#' + x + '_' + y;
$(idName).removeClass();
$(idName).addClass('black');
}
this.autoMove = function() {
function move() {
let x = snake.snakeBody[0][0];
let y = snake.snakeBody[0][1];
switch (snake.direction) {
case 'up':
x -= 1;
break;
case 'down':
x += 1;
break;
case 'left':
y -= 1;
break;
case 'right':
y += 1;
break;
}
let idName = "#" + x + "_" + y;
// 判断撞墙或者吃到自己身体
if (x < 0 || x >= map_width || y < 0 || y >= map_width || $(idName).hasClass('black')) {
alert("游戏结束");
clearInterval(timer);
return;
}
// 蛇身前移
snake.snakeBody.unshift([x, y]);
// 吃到食物
if ($(idName).hasClass('food')) {
$(idName).removeClass('food');
// 更新分数
let score = parseInt($("#score_number").text()) + 10;
$("#score_number").text(score);
// 0.5秒后出现新的食物
setTimeout(createFood, 0.5);
} else {
// 没吃到食物删除尾巴
let p = snake.snakeBody.pop();
let popIdName = '#' + p[0] + '_' + p[1];
setClass(popIdName, 'white');
}
// 新位置为蛇身
setClass(idName, 'black');
}
// 200ms移动一次
timer = setInterval(move, 200);
}
}
// 网页加载时执行
window.onload = function() {
// 创建地图
for (let i = 0; i < this.map_width; ++i) {
let tr = document.createElement("tr");
for (let j = 0; j < this.map_width; ++j) {
let td = document.createElement('td');
td.setAttribute("class", "white");
td.setAttribute('id', i + '_' + j);
tr.appendChild(td);
}
$("#playground").append(tr);
}
// 1秒后创造第一个食物
setTimeout(createFood, 1000);
// 创造蛇对象
snake = new Snake();
snake.autoMove();
// 全局按键事件
$(document).keydown(function(event) {
switch (event.keyCode) {
case 37:
if (snake.direction != 'right') {
snake.direction = "left";
}
break;
case 39:
if (snake.direction != 'left') {
snake.direction = "right";
}
break;
case 38:
if (snake.direction != 'down') {
snake.direction = "up";
}
break;
case 40:
if (snake.direction != 'up') {
snake.direction = "down";
}
break;
case 32:
// 空格暂停
if (timer != null) {
clearInterval(timer);
timer = null;
} else {
snake.autoMove();
}
}
console.log("蛇(" + snake.snakeBody[0][0] + "," + snake.snakeBody[0][1] + ")的方向: " + snake.direction);
});
}
BUG
在定时器还未调用move期间按下了多个方向键(该代码期间是200ms),蛇的坐标为更新,当更新时,蛇对象里的默认方向指向了自己的蛇身(蛇头下一个位置,对应坐标数组snake.snakeBody[1]),导致蛇头吃到自己蛇身,从而游戏结束!