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