HTML5小游戏贪吃蛇分析与实现

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/liusaint1992/article/details/50513181


昨天下午研发中心总结大会,晚上大家一起吃饭。 多少面孔成了曾经,多人新人充满憧憬,明年又会是如何。年年岁岁花相似,岁岁年年人不同。

晚上大家吃饭,我们桌不喝酒。 口味虽然淡了点,勉强也还算尽兴。 


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.onkeydown=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






猜你喜欢

转载自blog.csdn.net/liusaint1992/article/details/50513181