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>
相关文章
- JavaScript编码模式 2012/05/23
- javascript处理与当前时间间隔的函数 2012/05/23
- JavaScript学习笔记 2012/05/23
- js获取系统时间的方法 2012/05/22
- js实现隔行变色 2012/05/22
- 兼容FF/IE在页面预览客户端本地图片方法 2012/05/21
- 通过JS获取用户本地图片路径 2012/05/21
- JS实现回到顶部按钮的代码 2012/05/20
- Javascript中匿名函数的调用方法 2012/05/19
- 比较js的对象 2012/05/19