JS实现俄罗斯方块


JavaScript #俄罗斯方块2012-05-24 09:35
只实现了基本功能。

isColorful=false; //方块是否有颜色

把这里的变量设置为true值,将可以显示为简单的彩色版

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>更多的代码请来yige.org</title>
<script type="text/javascript">
/******************************************/
function $(id){
	return document.getElementById(id);
}
function myalert(msg){
	$("myalertbox").value=msg;
}
/******************************************/
var widthDot=20,		//方块格宽度
heightDot=20,			//方块格高度
widthContainer=300,		//游戏面板宽度
heightContainer=460,	//游戏面板高度
rows=0,					//游戏面板中容纳的方格行数
cols=0,					//列数
widthGraph=0;			//方块宽度

var colors="#ffffff,#cccccc,#ff0000,#00ff00,#0000ff,#ffff00,#ff00ff,#00ffff,#000000";	//颜色

//方块的坐标值
var cur_top=0,	
cur_left=0;

var eles=null,		//方格数组
graph=null;			//方块对象

var control_interval=50,
main_interval=200;			//主时间实例(线程)的时间触发间隔,即方块的下降速度
//时间实例
var main_t=0,				//主时间实例
control_t=0;				//控制方块操作功能的时间实例

var isPause=false,			//暂停标识
isColorful=false;			//方块是否有颜色

//监控的事件
document.onkeydown=keyDown;
document.onkeyup=keyUp;
window.onload=init;

function init(){
	//计算并赋值变量,用以保存
	rows=heightContainer/heightDot;
	cols=widthContainer/widthDot;
	eles=$("MainDiv").getElementsByTagName("DIV");
	
	initPanel();
	start();
}
function start(){
	graph=exportGraph(parseInt(Math.random()*7));
	//获取方块的宽度,并保存到全局变量
	widthGraph=0;
	for(var i=0;i<graph.length;i++){
		if(widthGraph<graph[i].length)widthGraph=graph[i].length;
	}
	////////////////
	cur_top=0-graph.length;
	cur_left=parseInt((cols-widthGraph)/2);

	startDiamonds();
}
//下移
function doDownShift(){
	if(isTouchBottom()){		//判断是否不能再继续下降
		stopDiamonds();
		//把方块降落地点的所有方格设置起fixed属性,代表该方格已被占用
		for(var i=0;i<graph.length;i++){
			for(var j=0;j<graph[i].length;j++){
				//if(graph[i][j]==1)eles[(cur_top+i)*cols+(cur_left+j)].setAttribute("fixed",1);
				if(graph[i][j]!=0)eles[(cur_top+i)*cols+(cur_left+j)].setAttribute("fixed",graph[i][j]);
			}
		}
		//消行处理
		var isFilled=false;	//填充标识
		for(var i=rows-1;i>=0;i--){
			isFilled=true;
			for(var j=0;j<cols;j++){
				if(eles[i*cols+j].getAttribute("fixed")=="0"){
					isFilled=false;
					break;
				}
			}
			if(isFilled){
				for(var j=0;j<cols;j++)eles[i*cols+j].setAttribute("fixed",0);
				repaint();
				var fixed=0;
				//所有方块下移
				for(var k=i-1;k>=0;k--){	//因为当前的i为被消除的一行的下标,所以应该设置k=i-1
					for(var j=0;j<cols;j++){
						fixed=eles[k*cols+j].getAttribute("fixed");
						eles[(k+1)*cols+j].setAttribute("fixed",fixed);
					}
				}
				i=i+1;		//注意这里因为所有方块已经下移,所以必须重新修改i值让外部的循环再次扫描最近被撤销的一行	
			}
		}
		//////
		start();
		return;
	}
	cur_top++;
	repaint();
	refreshGraph();
}
//左移
function doLeftShift(){
	if(cur_left<=0)return;
	var fixed=0;
	for(var i=0;i<graph.length;i++){
		for(var j=0;j<graph[i].length;j++){	//左边数起
			if(graph[i][j]!=0){
				fixed=eles[(cur_top+i)*cols+(cur_left+j-1)].getAttribute("fixed");
				if(fixed!=0)return;		//判断靠左的一点是否被置点
				break;		//只需要判断方块当前行中最左端的一个有颜色的点
			}
		}
	}
	cur_left--;
	repaint();
	refreshGraph();	
}
//右移
function doRightShift(){
	if(cur_left>=cols-widthGraph)return;
	var fixed=0;
	for(var i=0;i<graph.length;i++){
		for(var j=graph[i].length-1;j>=0;j--){		//右边数起
			if(graph[i][j]!=0){
				fixed=eles[(cur_top+i)*cols+(cur_left+j+1)].getAttribute("fixed");
				if(fixed!=0)return;		//判断靠右的一点是否被置点
				break;		//只需要判断方块当前行中的最右端的一个有颜色的点
			}
		}
	}
	cur_left++;
	repaint();
	refreshGraph();
}
//改变方块方向
function doRedirection(){
	var row=graph.length;
	var col=widthGraph;
	var temp=new Array(col);
	for(var i=0;i<temp.length;i++)temp[i]=new Array();
	for(var i=0;i<col;i++)
		for(var j=0;j<row;j++)
			temp[i][j]=graph[row-j-1][i];
	//给方块重新定位
	var incHeight=col-row;
	var incWidth=row-col;
	//判断当前的空间是否可以让方块改变方向
	var tempWidth=row;
	var temp_cur_top=cur_top-parseInt(incHeight/2);
	var temp_cur_left=cur_left-parseInt(incWidth/2);
	if(temp_cur_top>rows-temp.length)return;
	if(temp_cur_left<0)return;
	if(temp_cur_left>(cols-tempWidth))return;
	//判断是否存在足够方块旋转的空间大小
	var nMax=row>col?row:col;
	for(var i=0;i<nMax;i++){
		for(var j=0;j<nMax;j++){
			fixed=eles[(cur_top+i)*cols+(cur_left+j)].getAttribute("fixed");
			if(fixed!=0)return;
		}
	}	
	//为全局对象赋值
	cur_top=temp_cur_top;
	cur_left=temp_cur_left;
	widthGraph=tempWidth;		//方块宽度已经改变,必须重新赋值
	graph=temp;
	
	repaint();
	refreshGraph();
}
//加速
function doAccelerate(){
	if(isTouchBottom())return;
	cur_top++;
	repaint();
	refreshGraph();
}
//刷新,重绘游戏面板
function repaint(){
	var fixed=0;
	var cur=null;
	for(var i=0;i<rows;i++){
		for(var j=0;j<cols;j++){
			cur=eles[i*cols+j];
			fixed=cur.getAttribute("fixed");
			/*
			if(fixed==1){
				cur.style.backgroundColor="#cccccc";
			}else{
				cur.style.backgroundColor="#ffffff";
			}
			*/
			cur.style.backgroundColor=getRandomColor(fixed);			
		}
	}
}
//刷新,重绘方块对象
function refreshGraph(){
	if(graph==null)return;
	for(var i=0;i<graph.length;i++){
		if(cur_top+i<0)continue;
		for(var j=0;j<graph[i].length;j++){
			//if(graph[i][j]==1) eles[(cur_top+i)*cols+(cur_left+j)].style.backgroundColor="#cccccc";
			if(graph[i][j]!=0)		//当为0(透明)的情况下,没有必要重绘该点,而且更会因为重绘而影响到当前的底色(有的话)
				eles[(cur_top+i)*cols+(cur_left+j)].style.backgroundColor=getRandomColor(graph[i][j]);
		}
	}
}
//是否到底部
function isTouchBottom(){
	if(cur_top<0)return false;	//首先判断cur_top是否超出正确的下标值,不然程序无法运行
	if(cur_top>=rows-graph.length)return true;
	var fixed=0;
	for(var i=graph.length-1;i>=0;i--){	//为效率考虑,从方块底部开始扫描
		for(var j=0;j<graph[i].length;j++){
			/*
			if(graph[i][j]==1){
				//判断当前点的下面一个点属性fixed是否为1
				fixed=eles[(cur_top+i+1)*cols+cur_left+j].getAttribute("fixed");
				if(fixed==1)return true;
			}
			*/
			if(graph[i][j]!=0){
				//判断当前点的下面一个点的属性fixed是否不为0(白色),非0代表有颜色
				fixed=eles[(cur_top+i+1)*cols+cur_left+j].getAttribute("fixed");
				if(fixed!=0) return true;
			}
		}
	}
	return false;
}
//启动线程触发方块运行
function startDiamonds(){
	if(main_t==0){
		main_t=setInterval(function(){
			doDownShift();
		},main_interval);
	}
}
//停止方块运行监控线程
function stopDiamonds(){
	clearInterval(main_t);
	main_t=0;
}
function exportGraph(num){
	var oGraph=null;
	switch(num){
		case 0:			//水平条
			oGraph=[[1,1,1,1,1]];
			break;
		case 1:			//三角
			oGraph=[[0,1,0],[1,1,1]];	//graph[0]为顶,graph[1]为底
			break;
		case 2:			//左横节
			oGraph=[[1,0,0],[1,1,1]];
			break;
		case 3:			//右横节
			oGraph=[[0,0,1],[1,1,1]];
			break;
		case 4:			//左闪电
			oGraph=[[1,1,0],[0,1,1]];
			break;
		case 5:			//右闪电
			oGraph=[[0,1,1],[1,1,0]];
			break;
		case 6:			//石头
			oGraph=[[1,1],[1,1]];
			break;
	}
	//附上颜色
	if(isColorful){
		var idx=parseInt(Math.random()*(colors.split(",").length));
		idx=idx==0?1:idx;	//idx不应该为0
		var temp=new Array(oGraph.length);		//只能创建临时变量temp,并重新赋值给oGraph,不然会出现奇怪的错误,原因不明
		for(var i=0;i<temp.length;i++){
			temp[i]=new Array();
			for(var j=0;j<oGraph[i].length;j++){
				if(oGraph[i][j]!=0) temp[i].push(idx);
				else temp[i].push(0);
			}
		}
		oGraph=temp;
	}
	return oGraph;
}
//根据调色板的值,获取特定颜色值
function getRandomColor(idx){
	var arrayColors=colors.split(",");
	return arrayColors[idx];
}
function keyDown(e){
	if(control_t!=0)return;
	e=e||window.event;
	switch(e.keyCode){
		case 37:		//左移
			if(!isPause)control_t=setInterval(doLeftShift,control_interval);
			//doLeftShift();
			break;
		case 39:		//右移
			if(!isPause)control_t=setInterval(doRightShift,control_interval);
			//doRightShift();
			break;
		case 38:		//改变方向
			//control_t=setInterval(doRedirection,control_interval);
			if(!isPause)doRedirection();
			break;
		case 40:		//加速
			if(!isPause)control_t=setInterval(doAccelerate,control_interval);
			//doAccelerate();
			break;
		case 13:		//暂停或取消暂停,回车符
			if(isPause){
				startDiamonds();
			}else{
				stopDiamonds();
			}
			isPause=!isPause;
			break;
	}
	return;
}
function keyUp(){
	if(control_t==0)return;
	clearInterval(control_t);
	control_t=0;
}	
//初始化游戏,创建方格,生成游戏面板,
function initPanel(){
	var container=$("MainDiv");
	container.style.width=widthContainer+"px";
	container.style.height=heightContainer+"px";

	var row=heightContainer/heightDot;
	var col=widthContainer/widthDot;
	var strHtml="<table width='"+widthContainer+"' height='"+heightContainer+"' border='0' cellpadding='0' cellspacing='0'>";
	
	for(var i=0;i<row;i++){	
		strHtml+="<tr>";
		for(var j=0;j<col;j++){
			strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='0' style='border:solid 1px #000000; background-color:#ffffff; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
		}
		strHtml+="</tr>";
	}
	
	/*
	for(var i=0;i<rows-1;i++){
		strHtml+="<tr>";
		if(i==10)strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='0' style='border:solid 1px #000000; background-color:#ffffff; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
		else strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='1' style='border:solid 1px #000000; background-color:#cccccc; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
		for(var j=1;j<cols-1;j++){
			strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='0' style='border:solid 1px #000000; background-color:#ffffff; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>"
		}
		if(i==10)strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='0' style='border:solid 1px #000000; background-color:#ffffff; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
		else strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='1' style='border:solid 1px #000000; background-color:#cccccc; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
		strHtml+="</tr>";
	}
	strHtml+"<tr>";
	for(var j=0;j<cols;j++){
		strHtml+="<td style='width:"+widthDot+"; height:"+heightDot+"; text-align:center;'><div class='dot' fixed='1' style='border:solid 1px #000000; background-color:#cccccc; width:"+(widthDot-4)+"px; height:"+(heightDot-4)+"px;'></div></td>";
	}
	strHtml+="</tr>";
	*/
	strHtml+="</table>";
	container.innerHTML=strHtml;
}
</script>
</head>
<body>
<input type="text" id="myalertbox" ma style="width:500px; height:15px; border:solid 1px #000000; position:absolute; top:10px; left:10px;" />
<div style="margin:0 auto; margin-top:30px; width:250px; border:solid 1px #000000; font-size:12px;">方向键:<br />上:变形  下:加速  左:左移  右:右移<br />回车符:暂停</div>
<div id="MainDiv" style="margin:0 auto; margin-top:10px; padding:0px; border:solid 1px #000000;"></div>
</body>
</html>


相关文章

粤ICP备11097351号-1