基本思路
1.开始游戏
1-1.初始化游戏空间
1-2.初始化蛇
1-3.初始化食物
2.让蛇移动
2-1.判断蛇头下一步位置
2-2.检测碰撞
2-2-1.碰撞食物?
2-2-2.碰撞自己?
2-2-3.碰撞边界?
2-2-4.正常游走
3.添加键盘的事件监听
再来一张思维导图说明一下
下面代码实现:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
*{
margin: 0;
}
td{
padding: 10px;
}
td.snake{
background: #000000;
}
td.food{
background: #FF0000;
}
</style>
</head>
<body>
<table id="game" border="1" cellspacing="0" cellpadding="0">
</table>
</body>
<script type="text/javascript">
function Game(){
this.init();
}
Game.prototype = {
//初始化游戏空间
init() {
this.tab = document.getElementById("game");
for(let i = 0; i < 28; i++){
let tr = document.createElement("tr");
for (let j = 0; j < 62; j++) {
let td = document.createElement("td");
tr.appendChild(td);
}
this.tab.appendChild(tr);
}
},
// 开始游戏:初始化游戏空间->初始化蛇->初始化食物
start() {
// this.init();
//创建蛇
this.snake = new Snake(this);
this.snake.show();
//初始化食物,在print中调用打印
this.createFood();
//让蛇移动
this.snake.run();
this.addControl();
},
//游戏空间内生成食物
createFood() {
if(this.food){
this.tab.children[this.food.row].children[this.food.col].className = "";
}
let pos = {row : parseInt(Math.random()*28), col : parseInt(Math.random()*62)};
while(this.test(pos) == Snake.Constant.NEXT_POSISTION_TYPE_SELF){
pos = {row : parseInt(Math.random()*28), col : parseInt(Math.random()*62)};
}
this.tab.children[pos.row].children[pos.col].className = "food";
this.food = pos;//记住食物的位置
// console.log(pos);
},
//添加键盘监听,控制蛇的移动
addControl() {
// console.log("control")
document.addEventListener("keydown",(e)=>{
e = e || event;
if(this.snake.stepcount > 0){
switch(e.keyCode){
case 37 : {//向左移动
if(this.snake.dir != Snake.Constant.DIR_RIGHT){
this.snake.dir = Snake.Constant.DIR_LEFT;
this.snake.stepcount = 0;
}
break;
}
case 38 : {//上移
if(this.snake.dir != Snake.Constant.DIR_DOWN){
this.snake.dir = Snake.Constant.DIR_UP;
this.snake.stepcount = 0;
}
break;
}
case 39 : {//右移
if(this.snake.dir != Snake.Constant.DIR_LEFT){
this.snake.dir = Snake.Constant.DIR_RIGHT;
this.snake.stepcount = 0;
}
break;
}
case 40 : {//下移
if(this.snake.dir != Snake.Constant.DIR_UP){
this.snake.dir = Snake.Constant.DIR_DOWN;
this.snake.stepcount = 0;
}
break;
}
}
}
})
},
//让蛇和食物在游戏空间内显示
print() {
this.clear();
let pos = this.snake.position();//接收【snakeStep-3】返回的蛇身body
pos.forEach((p)=>{//画出蛇
this.tab.children[p.row].children[p.col].className = "snake";
})
if(this.food){
this.tab.children[this.food.row].children[this.food.col].className = "food";
}
},
clear() {//清空当前游戏空间
for(let i=0; i<28; i++) {
for(let j=0; j<62; j++) {
this.tab.children[i].children[j].className = "";
}
}
},
test(pos) {//检测碰撞
if(pos.row == 28 || pos.row < 0 || pos.col == 62 || pos.col < 0){
return Snake.Constant.NEXT_POSISTION_TYPE_RANGE;
}
let td = this.tab.children[pos.row].children[pos.col];
if(td.className == "food") return Snake.Constant.NEXT_POSISTION_TYPE_FOOD;
if(td.className == "snake") return Snake.Constant.NEXT_POSISTION_TYPE_SELF;
return Snake.Constant.NEXT_POSISTION_TYPE_NORMAL;
},
gameover() {
alert("you have died");
}
}
function Snake(game){
this.game = game;
this.init();
}
//蛇的相关变量
Snake.Constant = {
DIR_LEFT : Symbol(),
DIR_RIGHT : Symbol(),
DIR_UP : Symbol(),
DIR_DOWN : Symbol(),
NEXT_POSISTION_TYPE_FOOD : Symbol(),//检测碰撞点是食物
NEXT_POSISTION_TYPE_RANGE : Symbol(),//检测碰撞点是边界
NEXT_POSISTION_TYPE_SELF : Symbol(),//检测碰撞点是自己身体
NEXT_POSISTION_TYPE_NORMAL : Symbol()//检测正常游走无碰撞
}
Snake.prototype = {
//初始化蛇
init() {
this.body = [ { row : parseInt(Math.random()*28), col : parseInt(Math.random()*62) } ];//用数组存储蛇身的每一部分
this.dir = Snake.Constant.DIR_RIGHT;//初始活动方向
this.stepcount = 1;//记录步数
this.speed = 400;//游走速度
},
//画出蛇
show() {
this.game.print();
},
// 返回蛇身给game使用
position() {
return this.body;
},
//让蛇移动,判断蛇头的下一位置
run() {
console.log("run")
let that = this;
let timer = setInterval(function(){
//判断蛇头下一个位置
switch(that.dir){
case Snake.Constant.DIR_LEFT : {
that.next = {
row : that.body[0].row,
col : that.body[0].col-1,
}
break;
}
case Snake.Constant.DIR_RIGHT : {
that.next = {
row : that.body[0].row,
col : that.body[0].col+1,
}
break;
}
case Snake.Constant.DIR_UP : {
that.next = {
row : that.body[0].row-1,
col : that.body[0].col,
}
break;
}
case Snake.Constant.DIR_DOWN : {
that.next = {
row : that.body[0].row+1,
col : that.body[0].col,
}
break;
}
}
// that.nextStep();
//走的过程检测碰撞
let res = that.game.test(that.next);
switch(res){
case Snake.Constant.NEXT_POSISTION_TYPE_FOOD:{
that.eat();
that.stepcount++;
break;
}
case Snake.Constant.NEXT_POSISTION_TYPE_RANGE:{
that.stop();
that.game.gameover();
break;
}
case Snake.Constant.NEXT_POSISTION_TYPE_SELF:{
that.stop();
that.game.gameover();
break;
}
case Snake.Constant.NEXT_POSISTION_TYPE_NORMAL:{
that.nextStep();
that.stepcount++;
break;
}
}
},that.speed);
},
nextStep() {//下一步
this.body.pop();
this.body.unshift(this.next);
this.game.print();
},
eat() {//吃掉食物
this.body.unshift(this.next);
this.game.createFood();
this.game.print();
},
stop() {//碰撞边界或自己,死亡,关闭定时器
clearInterval(this.timer);
}
}
new Game().start();
</script>
</html>