如何用javascript写一个贪吃蛇

我原来用C语言,借助curses库实现了linux 终端下的贪吃蛇游戏

这个javascript版本的贪吃蛇是http://www.veryhuo.com/game/tanchishe.html 的学习笔记,实现的原理和C版本基本一样。

--------------------

1.怎样表示一条snake

用一个二维数组存snake的各个点(x,y),同时标记这些点(x,y)为“cover”,这是用于以后检查snake的头是否撞到了snake的body。

//initialize snake
function initSnake() {
	var pointer = randomPointer(len-1, len-1, WIDTH/2);
	for(var i = 0; i < len; i++) {
		var x = pointer[0] - i,
			y = pointer[1];
		snake.push([x,y]);
		carrier[x][y] = "cover"; //标记snake body
	}
}

2.用js画出格子

用document.createElent()方法创建出table->tr->td, 然后用document.appendChild()方法追加到id为“snakewrap”的元素上:

//initialize grid 
function initGrid() {
	var body = document.getElementsByTagName("body")[0];
	var table = document.createElement("table"),
		tbody = document.createElement("tbody")
	for(var j = 0; j < HEIGHT; j++) {  
		var col = document.createElement("tr");  
		for(var i = 0; i < WIDTH; i++) {  
			var row = document.createElement("td");
			gridElems[i][j] = col.appendChild(row);  
		}
		tbody.appendChild(col);  
	}
	table.appendChild(tbody);
	document.getElementById("snakewrap").appendChild(table);
}

3.生成食物的随机坐标

function randomPointer(startX,startY,endX,endY) {
	startX = startX || 0;
	startY = startY || 0;
	endX = endX || WIDTH;
	endY = endY || HEIGHT;
	
	var p = [],
	x = Math.floor(Math.random()*(endX - startX)) + startX,
	y = Math.floor(Math.random()*(endY - startY)) + startY;
	
	//如果(x,y)有物体,则重新生成坐标
	if(carrier[x][y]) {
		return randomPointer(startX,startY,endX,endY);
	}
	
	p[0] = x;
	p[1] = y;
	return p;
}

添加新的食物:

//addObject("food")
function addObject(name) {
	var p = randomPointer(); //get random position
	var x = p[0];
	var y = p[1];
	carrier[x][y] = name;
	gridElems[x][y].className = name;
}

4.方向键按下动作事件监听:

允许左上右下这4个按键来改变snake的运动方向,注意,如果方向相反的话,不生效。

对于键盘上的每一个按键,都有一个key cord,我的这篇博客记录了javascript的key cord,可看到:

left arrow 37
up arrow 38
right arrow 39
down arrow 40

//keyboard event listener
function attachEvents(e) {
	e = e || event;
	directkey = Math.abs(e.keyCode - directkey) != 2 && e.keyCode > 36 && e.keyCode < 41 ? e.keyCode : directkey; 
	return false;
}

5.贪吃蛇的核心--判断

每次判断(即judge()函数每运行一次-->这里用到了setInterval()方法),都要先把snake的“头”节点保存下来,然后做判断

1)判断方向,根据方向调整“头”的坐标(由于有setInterval()方法,系统会每个若个毫秒就运行一次judge()函数,确保用户按下方向键后能够该表方向)

2)判断“头”是否撞到墙,或碰到snake的身体(即carrier[headX][headY] == "cover"时),如果碰到,则游戏结束。

3)判断“头”当前的位置是不是食物(即carrier[headX][headY] == "food"), 如果头元素的carrier不是食物,则让snake的尾巴pop出来;如果是,则让当前位置的携带信息carrier[headX][headY] = false

4 )向数组的开头添加一个元素-->从而实现了“视觉上”的snake移动(或吃食物body增长)的效果


function judge() {
	//把snake的“头”位置暂存起来
	var headX = snake[0][0], headY = snake[0][1];
	switch(directkey) {
		case 37: headX -= 1; break; //left
		case 38: headY -= 1; break; //up
		case 39: headX += 1; break  //right
		case 40: headY += 1; break; //down
	}
	
	//碰到边界(block),或头碰到身体(cover),则结束游戏
	if(headX >= WIDTH || headX < 0 || headY >= HEIGHT || headY < 0 || carrier[headX][headY] == "block" || carrier[headX][headY] == "cover" ) {
		$("say").innerText = "Game Over.";
		
		$("start").removeAttribute("disabled");
		$("start").style.color = "#000";
		
		window.clearInterval(snakeTimer);
		
		return;
	}
	
	//如果头元素的carrier不是食物,则让snake的尾巴pop出来
	if(carrier[headX][headY] != "food") {
		var lastX = snake[snake.length-1][0],
			lastY = snake[snake.length-1][1];
		carrier[lastX][lastY] = false;
		gridElems[lastX][lastY].className = "";
		snake.pop();
	} 
	else {
		carrier[headX][headY] = false;
		addObject("food"); //吃掉食物,然后调用addObject("food"),重新生成食物
	}
	
	//向数组的开头添加一个元素-->从而实现了“视觉上”的snake移动(或吃食物body增长)的效果
	snake.unshift([headX,headY]); 
	carrier[headX][headY] = "cover";
	gridElems[headX][headY].className = "cover";
	
	len = snake.length;
}

setInterval()函数(使得上面的judge()函数每隔300ms就运行一次):

function run_run_run() {
	if(snakeTimer) {
		window.clearInterval(snakeTimer);
	}
	snakeTimer = window.setInterval("judge()", Math.floor(300));
}

6.onload 运行

onload 事件会在页面或图像加载完成后立即发生:

window.onload = function(){
	initGrid(); 
	document.onkeydown = attachEvents; //监听keydown事件
	$("start").onclick = function (e) {
		len = 3; //snake的初始长度
		directkey = 39; //right
		snake = new Array();
		initSnake(); 
		addObject("food");
		run_run_run();
		
		//让start按钮失效
		$("start").setAttribute("disabled",true);
		$("start").style.color = "#aaa";
	}
}

7.参考http://www.veryhuo.com/game/tanchishe.html


8.玩玩:我的simple and stupid snake game

效果图(CSS我借用了下最近很火的2048):

如何用javascript写一个贪吃蛇



如何用javascript写一个贪吃蛇,布布扣,bubuko.com

如何用javascript写一个贪吃蛇

上一篇:C++虚拟多重继承对象模型讨论


下一篇:24.4. 批量生成监控配置文件