javascript 贪吃蛇(二)

javascript 贪吃蛇(一) 中,我们创建了Canvas、Snake及Food对象,本部分将继续进行余下的部分。
在开始进行余下部分的介绍前先将Utils.js公布出来,该js文件中设置了一些常用的方法。源码如下:

Array.prototype.indexOf = function(vItem) {
	for ( var i = 0; i < this.length; i++) {
		if (vItem == this[i]) {
			return i;
		}
	}
	return -1;
};
Array.prototype.sameItem = function(vItem) {// 判断元素在数组中出现的次数
	var __iNum = 0;// 应用python的私有变量申明方式
	for ( var i = 0; i < this.length; i++) {
		(this[i] == vItem) ? __iNum++ : __iNum;
	}
	return __iNum;
};

function createElement(sTagName, sTagId, sText) {
	var oElement = document.createElement(sTagName);
	if (sTagId != null) {
		oElement.setAttribute("id", sTagId);
	}
	if (sText != null) {
		oElement.appendChild(document.createTextNode(sText));
	}
	return oElement;
}

function RandomEventUtils() {
}
RandomEventUtils.getIntRandomNumFromOneToN = function(iN) {
	var iR = Math.random() * iN;
	return Math.ceil(iR);
};
RandomEventUtils.instanceRandomSnakeForCanvas = function(oCanvas) {
	var __head = this.getIntRandomNumFromOneToN(20 * 20);
	if (!oCanvas.whichWallForBrick(__head)) {// 不属于墙
		return new Snake(__head, __head - 1, "down");
	} else {
		return new Snake(34, 35, "right");
	}
};

Scoreboard对象:   
该对象定义的相对比较简单,仅仅是操作DOM生成显示游戏分数跟登记的相关位置。具体实现如下:

//Scoreboard.js
function Scoreboard() {
}

/*
 * 生成如下HTML代码:
 * <div id='scoreboard'>
 * 		<div><label>Score</label><span id='score'>0</span></div>
 *      <div><label>Level</label><span id='level'>0</span></div>
 *      <center>top ten</center>
 * </div>
 * 
 */
Scoreboard.prototype.draw = function() {
	var oFragment = document.createDocumentFragment();// 创建文档碎片
	var oDiv = createElement("div", "scoreboard", null);
	var oDiv_div1 = createElement("div", null, null);
	var oDiv_div1_label = createElement("label", null, "Score");
	var oDiv_div1_span = createElement("span", "score", "0");
	oDiv_div1.appendChild(oDiv_div1_label);
	oDiv_div1.appendChild(oDiv_div1_span);
	var oDiv_div2 = createElement("div", null, null);
	var oDiv_div2_label = createElement("label", null, "Level");
	var oDiv_div2_span = createElement("span", "level", "0");
	oDiv_div2.appendChild(oDiv_div2_label);
	oDiv_div2.appendChild(oDiv_div2_span);
	var oCenter = createElement("center", null, "top ten");
	oDiv.appendChild(oDiv_div1);
	oDiv.appendChild(oDiv_div2);
	oDiv.appendChild(oCenter);
	oFragment.appendChild(oDiv);
	document.body.appendChild(oFragment);

};
// 显示游戏分数与游戏等级
Scoreboard.prototype.showScoreAndLevel = function(iScore, iLevel) {
	document.getElementById('score').innerHTML = iScore;
	document.getElementById("level").innerHTML = iLevel;
};
// 初始游戏分数与登记
Scoreboard.prototype.cleanScoreAndLevel = function() {
	document.getElementById('score').innerHTML = 0;
	document.getElementById("level").innerHTML = 0;
};
// 显示游戏玩家游戏日志
Scoreboard.prototype.showHistory = function() {
	var aCookie = document.cookie.split(";");
	var oFragment = document.createDocumentFragment();// 创建文档碎片
	for ( var i = 0; i < aCookie.length; i++) {
		var oSpan = createElement("span", null, aCookie[i]);
		oFragment.appendChild(oSpan);
	}
	var oScoreboard = document.getElementById("scoreboard");
	var oTop = document.getElementById('top');
	if (oTop != null) {
		oScoreboard.removeChild(oTop);
	}
	oTop = createElement("div", "top", null);
	oTop.appendChild(oFragment);
	oScoreboard.appendChild(oTop);
};

SnakeGame对象:
    这个为游戏对象。属性有:iScore(分数)、iLevel(登记)、timeOut(计时)、canvas(画布)、scoreboard(记分牌)、snake(蛇)、food(食物)
     方法有:keyboardEventsListeners(键盘监听事件)、scoreAndSpeed(游戏分数及等级计算)、start(游戏开始)、stop(游戏暂停)等方法。具体实现如下:

// SnakeGame.js
function SnakeGame(oCanvas, oScoreboard, oSnake, oFood) {
	this.iScore = 0;
	this.iLevel = 0;
	this.timeOut;
	this.canvas = oCanvas;
	this.scoreboard = oScoreboard;
	this.snake = oSnake;
	this.food = oFood;
}
// 键盘监听事件
SnakeGame.prototype.keyboardEventsListeners = function(oEvent) {
	if (window.event) {// ie
		// var direc = arguments[0].keyCode;
		var direc = window.event.keyCode;
	} else if (oEvent.which) {// ff
		var direc = oEvent.which;
		// var direc = arguments[0].which;
	}
	if (direc == 37 && this.snake.direction != "right") {// 37-->left
		this.snake.direction = "left";
	}
	if (direc == 39 && this.snake.direction != "left") {// 39-->right
		this.snake.direction = "right";
	}
	if (direc == 38 && this.snake.direction != "down") {// 38-->up
		this.snake.direction = "up";
	}
	if (direc == 40 && this.snake.direction != "up") {// 40-->down
		this.snake.direction = "down";
	}
};
SnakeGame.prototype.__delay = function(obj, fn, time) {
	fnGameDelay = function() {
		fn.call(obj);// call方法会把fn方法中的this关键字替换成obj对象
		// apply方法同call,但参数要用数组形式。IE中参数为空时不能用apply(obj,null),但FF中是可以的
		// fn.apply(obj, new Array());
	};
	return setTimeout('fnGameDelay()', time);
};
// 记分及游戏级别控制
SnakeGame.prototype.scoreAndSpeed = function() {
	this.iScore += Math.pow(2, this.food.iRank)
			* Math.ceil(Math.sqrt(Math.pow(5, this.iLevel))) - 2;
	var level = this.snake.body.length - 2;
	if (level > 0 && level % 7 == 0 && this.iLevel != 10) {
		this.iLevel += 1;
	}
	this.scoreboard.showScoreAndLevel(this.iScore, this.iLevel);
};
// 开始游戏
SnakeGame.prototype.start = function() {
	// 当使用typeof param时,param可以声明也可以不用声明。
	if (this.snake == undefined) {// null == undefined 为真,但null与undefied是不同的
		this.snake = RandomEventUtils.instanceRandomSnakeForCanvas(this.canvas);
	}
	// 当使用声明变量但没有初始值时才可以使用 param == undefined 否则的话会报错
	if (this.food == undefined) {
		this.food = new Food();
	}
	if (this.food.bEat) {
		this.scoreAndSpeed();
		this.food.productionFoodForSnake(this.snake);
	}
	this.snake.draw();
	this.snake.moveAndFindFood(this.food);
	if (this.snake.isHitWall(this.canvas)) {
		var sPlayer = prompt("Game Over!/nPlease input your name!", "Anonymous");
		this.saveHistory(sPlayer);
		this.onceAgain();
		return;
	}
	this.snake.draw();
	this.timeOut = this.__delay(this, this.start, 1000 - this.iLevel * 100);
};
// 游戏暂停
SnakeGame.prototype.stop = function() {
	clearTimeout(this.timeOut);
};
// 游戏结束后的重新初始化
SnakeGame.prototype.onceAgain = function() {
	this.scoreboard.cleanScoreAndLevel();
	this.scoreboard.showHistory();
	this.snake.cleanUpSnakeBody();
	this.food.cleanUpLeftovers();
	this.snake = null;
	this.food = null;
	this.iScore = 0;
	this.iLevel = 0;
	this.timeOut = null;
};
// 保存玩家游戏记录
SnakeGame.prototype.saveHistory = function(sPlayer) {
	if (sPlayer != null && sPlayer != "") {
		var oDate = new Date();
		var sDate = oDate.getFullYear() + "-" + (oDate.getMonth() + 1) + "-"
				+ oDate.getDate() + " " + oDate.getHours() + ":"
				+ oDate.getMinutes() + ":" + oDate.getSeconds();
		document.cookie = sPlayer + "=" + this.iScore + ":" + sDate;
	}
};
// 预加载
SnakeGame.prototype.preload = function() {
	// 添加控制按钮
	var oDiv = createElement("div", "ctlbtn", null);
	var btn_start = createElement("button", "start", "Start");// 开始
	var btn_stop = createElement("button", "stop", "Stop");// 暂停
	var btn_help = createElement("button", "help", "Help");// 帮助
	oDiv.appendChild(btn_start);
	oDiv.appendChild(btn_stop);
	oDiv.appendChild(btn_help);
	document.body.appendChild(oDiv);
	this.canvas.draw();// 显示画布
	this.scoreboard.draw();// 显示记分牌
	this.scoreboard.showHistory();// 显示当前游戏历史排行记录
};
window.onload = function() {
	var oCanvas = new Canvas();// 创建canvas对象
	var oScoreboard = new Scoreboard();// 创建scoreboard对象
	var oSnake;// 声明snake
	var oFood;// 声明snake's food
	var oSnakeGame = new SnakeGame(oCanvas, oScoreboard, oSnake, oFood);// 创建SnakeGame
	oSnakeGame.preload();// SnakeGame预加载

	// 为游戏按钮添加监听事件
	document.body.onkeydown = function(oEvent) {
		oSnakeGame.keyboardEventsListeners.call(oSnakeGame, oEvent);
	};
	document.getElementById("start").onclick = function() {
		oSnakeGame.start.call(oSnakeGame);
	};
	document.getElementById("stop").onclick = function() {
		oSnakeGame.stop.call(oSnakeGame);
	};
	document.getElementById("help").onclick = function() {
		alert("键盘方向键控制蛇的移动!/n" + "点击“Start”开始游戏、“Stop”暂停游戏/n"
				+ "游戏共有十个等级,从零开始难度依次增大/n" + "共有四种不同颜色的食物。分别是黄、蓝、红、黑/n"
				+ "食物随机产生并且每种食物的分值随等级变化/n" + "级别越高则相同颜色的食物分值越高");
	};

};

最后我们看戏该如何使用。相应的html页面snake.html及CSS样式snake.css为:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>snake</title>
<mce:script type="text/javascript" src="Snake.js" mce_src="Snake.js"></mce:script>
<mce:script type="text/javascript" src="Food.js" mce_src="Food.js"></mce:script>
<mce:script type="text/javascript" src="Canvas.js" mce_src="Canvas.js"></mce:script>
<mce:script type="text/javascript" src="Utils.js" mce_src="Utils.js"></mce:script>
<mce:script type="text/javascript" src="Scoreboard.js" mce_src="Scoreboard.js"></mce:script>
<mce:script type="text/javascript" src="SnakeGame.js" mce_src="SnakeGame.js"></mce:script>
<link type="text/css" rel="stylesheet" href="snake.css" mce_href="snake.css">
</head>
<body>

</body>
</html>
@CHARSET "UTF-8";
body {
	margin-left: 10px;
	margin-top: 50px;
}
#ctlbtn {
	padding: 0px;
	border: 1px solid red;
	width: 662px;
}
#ctlbtn #start,#stop,#help {
	padding: 1px 2px 1px 1px;
	border: 1px solid #ECE9D8;
	background-color: #ffffff;
	font-style: italic;
	font-family: sans-serif;
	cursor: pointer;
	width: 46px;
}
#help {
	cursor: help;
}
#canvas {
	float: left;
	width: 460px;
	height: 440px;
	border: 1px solid green;
}
#canvas span {
	float: left;
	padding-left: 1px;
	width: 20px;
	height: 20px;
	border: 1px solid #CDCBFE;
	font-size: 12px;
}
#scoreboard {
	float: left;
	width: 200px;
	height: 440px;
	border: 1px solid red;
}
#scoreboard  center {
	margin: 4px 0px 5px 0px;
	padding: 1px 1px 1px 1px;
	font-style: inherit;
	font-family: cursive;
}
#scoreboard label {
	font-style: italic;
	font-family: cursive;
}
#score,#level {
	padding-left: 20px;
	border: 0px solid #A2C11E;
	font-family: cursive;
}
#top {
	padding: 0px 0px 0px 0px;
	border: 0px dotted #A2C11E;
}
#top span {
	margin-left: 0px;
	width: 20;
	border: opx dotted #A2C11E;
	font-size: 13px;
}
#player {
	margin: 200px 50px 50px 150px;
	padding: 1px 1px 1px 1px;
	position: absolute;
	z-index: 20px;
	border: 0px solid orange;
	background-color: #CDCBFE;
}
#player button {
	padding: 0px 0px 0px 0px;
	border: 1px solid #ECE9D8;
	background-color: #ffffff;
}

现在可以体验下js版的snake了。最终效果如下:

转载于:https://my.oschina.net/yeelee/blog/650898

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值