昨天下午研发中心总结大会,晚上大家一起吃饭。 多少面孔成了曾经,多人新人充满憧憬,明年又会是如何。年年岁岁花相似,岁岁年年人不同。
晚上大家吃饭,我们桌不喝酒。 口味虽然淡了点,勉强也还算尽兴。
8点多回到家想起下午开会时想到的贪吃蛇小游戏,就准备动手写一个。
先上效果图:
贪吃蛇的逻辑非常简单,稍微动一下脑子就能想出来。
规则:1、撞到墙壁或撞到自己。判输。
2、撞到幸运点,自身长大一格。
3、每长大一格,分数增加10。分数每增加100,速度提升一个级别。
逻辑:
1.首先要理解蛇的运动。很容易发现蛇每往前走一步。本质就是增加一个头部点,去掉原来的尾巴点。中间的所有点都是不动的。 用程序化的表达,整条贪吃蛇可以是一个类似这样[[1,2],[1,3]]的带位置信息的数组,每移动一步,我们往数组推入一个新的坐标点,并移除第一个坐标点。
2.如何获取下一个点的坐标。我们的蛇理论上可以往上下左右四个方向移动。可以根据现在蛇头的坐标和方向计算出合适的x,y坐标。就是新的蛇头坐标。 比如[1,2]往右边移动一下就变成[2,2],往右边移动的本质是x坐标增加1。
3.控制方向。 监控键盘事件。 注意:当前是向右的时候,下一步只可能是往上或往下或往右,不会出现倒退的情况。
4.生成幸运点。 一要随机。二不能生成在贪吃蛇身上。 也就是幸运点坐标不能在贪吃蛇身体的坐标组中就可以。
5.吃掉幸运点。 贪吃蛇坐标数组中添加幸运点到数组尾部。并且不移除蛇尾。
6.判断输。 如果新生成的头部的坐标,是蛇身坐标组是的一个值。说明撞到自己了。 如果新生成的头部坐标的x,y值超出了边界值。判输。
7.分数和速度。 速度就是控制蛇运动的 timer执行的时间间隔而已。
核心代码:
初始化:
var Snake = function(ele,scoreele,speedele,x,y){
this.cellWidth = 10;//每个格子的大小
this.ele = document.getElementById(ele);
this.cxt = this.ele.getContext("2d");
this.x=x;
this.y=y;
this.scoreele = document.getElementById(scoreele);
this.speedele = document.getElementById(speedele);
//生成canvas大小。边框。
this.ele.width = this.cellWidth * this.x;
this.ele.height = this.cellWidth * this.y;
this.ele.style.border ="1px solid #000";
this.changeDiretion();//绑定方向事件。
}
Snake.prototype = {
init:function(){
//初始化,重置。恢复js数据以及dom。
this.direction = 1;//向右 2下 3左 4 上
this.nextDirection = '';
this.snakeArr = [[0,parseInt(this.y/2)],[1,parseInt(this.y/2)]];
this.speed = 1;
this.score = 0;
this.cxt.fillStyle ='#fff';
this.cxt.fillRect(0,0,this.cellWidth*this.x,this.cellWidth*this.y);
this.scoreele.innerHTML="得分:0";
this.speedele.innerHTML="速度:1";
this.createCoolPoint();
this.drawCell(this.coolPoint,2);
this.drawSnake();
this.setTimer();
},
getCellArea:function(pos){//返回一个格子左上角的像素坐标[32,666];
return [(pos[0]-1)*this.cellWidth+1,(pos[1]-1)*this.cellWidth+1];
},
setTimer:function(){
var speedArr = [900,800,700,600,500,400,300,200,100];
var speed = this.speed;
if(speed>8){
speed = 8;
}
(function(theThis){
var that = theThis;
that.timer = setTimeout(function() {
that.moveSnake();
}, speedArr[speed]);
})(this);
},
moveSnake:function(){
//移动蛇的逻辑。数组处理。
this.direction = this.nextDirection == ''?this.direction:this.nextDirection;//当前移动方向,和下一个移动方向。这样处理能避免一个bug.
var direction = this.direction;
var snakeArr = this.snakeArr;
var snakeHead = snakeArr[snakeArr.length-1];
switch(direction){
case 1 ://向右
snakeHead = [snakeHead[0]+1,snakeHead[1]];
break;
case 2 ://向下
snakeHead = [snakeHead[0],snakeHead[1]+1];
break;
case 3 ://向左
snakeHead = [snakeHead[0]-1,snakeHead[1]];
break;
case 4 ://向上
snakeHead = [snakeHead[0],snakeHead[1]-1];
break;
}
//超界,或撞上自己。结束,重置。
if(in_array(snakeHead,snakeArr) || snakeHead[0]<0 || snakeHead[0]>this.x || snakeHead[1]<0 || snakeHead[1]>this.y){
window.clearInterval(this.timer);
alert('胜败乃兵家常事 大侠请重新来过。得分:'+this.score);
this.init();
return;
}
snakeArr.push(snakeHead);//将蛇头放入数组
this.drawCell(snakeHead,1);
if(snakeHead.toString() != this.coolPoint.toString()){
var tail = snakeArr.shift();//移除蛇尾。
this.drawCell(tail,0);
}else{//撞到coolPoint
this.createCoolPoint();
this.drawCell(this.coolPoint,2);
this.score = this.score + 10;
this.scoreele.innerHTML="得分:"+this.score;
this.speed = Math.ceil((this.score + 1)/100);
this.speedele.innerHTML="速度:"+this.speed;
console.log(this.score);
console.log(this.speed);
}
this.setTimer();
},
createCoolPoint:function(){//随机生成coolPoint,不在代表snakeArr的数组中。
do{
this.coolPoint = [getRandom(this.x),getRandom(this.y)];
}while(in_array(this.coolPoint,this.snakeArr));
},
changeDiretion:function(){
//更换移动方向。下一步的移动方向。
var that = this;
document.οnkeydοwn=function(event){
var e = event || window.event || arguments.callee.caller.arguments[0];
var direction = that.direction;
var keyCode = e.keyCode;
switch(keyCode){
case 39://右
if(direction!=1 && direction !=3){
that.nextDirection = 1;
}
break;
case 40://下
if(direction!=2 && direction !=4){
that.nextDirection = 2;
}
break;
case 37://左
if(direction!=1 && direction !=3){
that.nextDirection = 3;
}
break;
case 38://上
if(direction!=2 && direction !=4){
that.nextDirection = 4;
}
break;
default:
break;
}
};
},
drawSnake:function(){
//绘制初始小蛇。
var snakeArr = this.snakeArr;
for (var i = 0,sLen=snakeArr.length; i < sLen; i++) {
this.drawCell(snakeArr[i],1);
};
},
drawCell:function(pos,type){//绘制会用到的几种颜色的图。
var colorArr = ['#fff','rgb(0,140,202)',"red"];
var cxt = this.cxt;
var area;
cxt.fillStyle = colorArr[type];
area = this.getCellArea(pos);
cxt.fillRect(area[0],area[1],this.cellWidth-1,this.cellWidth-1);
}
}
var snake = new Snake("snake","score","speed",15,15);
snake.init();
演示地址:http://runningls.com/demos/2016/snake/snake.html
github:https://github.com/liusaint/games/tree/master/snake
欢迎留言交流。转载注明出处:http://blog.csdn.net/liusaint1992/article/details/50513181