|
|

<html>
<head>
<title>
俄罗斯方块游戏
</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body>
<STYLE>
BODY
{
BACKGROUND: black; MARGIN: 0px
}
td
{
height: 20px; width: 20px; font-family: 宋体; color: #FFFFFF; font-size: 9pt
}
#block_div
{
POSITION: absolute; WIDTH: 80px; Z-INDEX: 1
}
#table_div
{
POSITION: absolute; WIDTH: 320px
}
#nblock_div
{
COLOR: red; FONT: 48px system; POSITION: absolute; Z-INDEX: 2
}
#title_div
{
COLOR: white; FONT-SIZE: 22px; LEFT: 326px; POSITION: absolute; TOP: 7px
}
#infobar_div
{
LEFT: 396px; POSITION: absolute; TOP: 416px
}
#infobar2_div
{
COLOR: white; FONT-SIZE: 14px; LEFT: 396px; POSITION: absolute; TOP: 480px
}
#infobar2_div A
{
COLOR: #99ccff; TEXT-DECORATION: none
}
</STYLE>
<script id=clientEventHandlersJS language=javascript>
<!--
//读者知道俄罗斯方块的每个积木块由四格组成
//但是由于它们的组合位置可以达到四行四列中的每一格
//因此我们使用一个16个元素的数组来表示它
//下面为叙述方便,将把组成积木块的四格成为积木格
if(document.all)
{
var n_width = 800;//默认分辨率
var n_height = 600;//默认分辨率
var n_left = Math.round( screen.width/2 ) - n_width/2;//非默认分辨率下的换算左边沿
var n_top = Math.round( screen.height/2 ) - n_height/2;//非默认分辨率下的换算右边沿
var n_IncStep = 20;//每个格子的像素为单位的边长
var curBlcok,nextBlock;//分别表示当前积木块和下一个积木块
var arr_curBlock = new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);//以数组形式来表示的积木块,实际上可以认为是4*4,值为1的地方就是有一个积木的格
var curX,curY;//当前的游戏区的左边沿和上边沿的值,以像素来计算
var speed=1;//积木块下落速度
var maxspeed=9;//积木块下落的最高速度
var clr_per_line=18;//设置用户水平的一个标准,当用户操作中删除了这么多行后,就把速度提高之
var pause=0;//判断游戏是否处于暂停中
var gameover=0;//表示是否游戏结束
var colors = new Array("#999999","#0000FF","#80FFFF","#80FF80","#FFFF00","#FF8000","#FF00FF","#FF0000");//颜色数组,供调用
var cid;//游戏区积木块的颜色号
var ncid;//下一种颜色
var blocks = new Array("tt_O1","tt_T2","tt_Z1","tt_S1","tt_L1","tt_J1","tt_I2");//定义积木数组
var bid;//积木在blocks中的编号
var killedlines=0;//总共被删除的行数,也是成绩的值
//第一种积木的四种不同变形
var tt_O1 = new Array(0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0);
var tt_O2 = new Array(0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0);
var tt_O3 = new Array(0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0);
var tt_O4 = new Array(0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0);
//第二种积木的四种不同变形
var tt_T1 = new Array(0,0,0,0,0,1,0,0,1,1,0,0,0,1,0,0);
var tt_T2 = new Array(0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0);
var tt_T3 = new Array(0,0,0,0,0,1,0,0,0,1,1,0,0,1,0,0);
var tt_T4 = new Array(0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0);
//第三种积木的四种不同变形
var tt_Z1 = new Array(0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0);
var tt_Z2 = new Array(0,0,0,0,0,0,1,0,0,1,1,0,0,1,0,0);
var tt_Z3 = new Array(0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0);
var tt_Z4 = new Array(0,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0);
//第四种积木的四种不同变形
var tt_S1 = new Array(0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0);
var tt_S2 = new Array(0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0);
var tt_S3 = new Array(0,0,0,0,0,0,1,1,0,1,1,0,0,0,0,0);
var tt_S4 = new Array(0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0);
//第五种积木的四种不同变形
var tt_L1 = new Array(0,1,0,0,0,1,0,0,0,1,1,0,0,0,0,0);
var tt_L2 = new Array(0,0,0,0,0,0,1,0,1,1,1,0,0,0,0,0);
var tt_L3 = new Array(0,0,0,0,0,1,1,0,0,0,1,0,0,0,1,0);
var tt_L4 = new Array(0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0);
//第六种积木的四种不同变形
var tt_J1 = new Array(0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0);
var tt_J2 = new Array(0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0);
var tt_J3 = new Array(0,0,0,0,0,1,1,0,0,1,0,0,0,1,0,0);
var tt_J4 = new Array(0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0);
//第七种积木的四种不同变形
var tt_I1 = new Array(0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0);
var tt_I2 = new Array(0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1);
var tt_I3 = new Array(0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0);
var tt_I4 = new Array(0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1);
//游戏区,两侧的1用作隔离,这是编程中的常用技术
var table = new Array
(
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
)
}
else
alert("You need IE4+ to play Tetris!")
//返回某行某列的在一维数组中的位置
function dimension2(row,col,num)
{
var i = row * num + col;
return (this);
}
//为Array的prototype属性增加一个功能,此功能调用dimension2函数
Array.prototype.getd = dimension2;
//显示左边游戏区的积木块
function ShowBlock(x,y,block_type,color)//x,y代表积木块的位置,block_type代表积木块的种类,color代表积木块的颜色
{
for(var i=0;i<block_tbl.rows.length;i++)
{
for(var j=0;j<block_tbl.rows(i).cells.length;j++)
{
var d2 = i * 4 + j;//获得当前位置
if(block_type[d2]==1)//如果当前的值是1,则表明这是一个积木格
{
block_tbl.rows(i).cells(j).style.background = color;//则染上颜色
}
else
{
block_tbl.rows(i).cells(j).style.background = "";
}
}
}
//设置积木块的位置
block_div.style.pixelLeft=x;
block_div.style.pixelTop=y;
}
//更广泛的显示积木块的函数
//前四个参数和上一函数一致,obj_tabID表示引用的table的ID,obj_divID表示引用的div的ID
//此函数可参看上一函数的注释
function ShowBlock1(x,y,block_type,color,obj_tabID,obj_divID)
{
for(var i=0;i<obj_tabID.rows.length;i++)
{
for(var j=0;j<obj_tabID.rows(i).cells.length;j++)
{
var d2 = i * 4 + j;
if(block_type[d2]==1)
{
obj_tabID.rows(i).cells(j).style.background = color;
}
else
{
obj_tabID.rows(i).cells(j).style.background = "";
}
}
}
obj_divID.style.pixelLeft=x;
obj_divID.style.pixelTop=y;
}
//把积木块变成同一类型的不同形状
function Change(inc)
{
var type = curBlock.substr(0,4);//获得当前积木块的种类,即如tt_Z
var num = curBlock.substr(curBlock.length-1);//获得当前积木块的形状的指示值,如1,2等
num = parseInt(num) + inc;//获得将要变换成的积木块的形状的一个指示值
if(num>4||num<1) //如果此形状指示值不在1-4之间,则将之变为1-4之间
num -= 4*inc;//注意到如果要使num>4,则inc=1,要使num<1,则inc=-1。因此只需作这个减法即可
type += num;//更改形状,例如把type已经设为tt_Z2之类的值
eval("arr_tmp = " + type + ";");//获得更改后的积木形状
if(CanMove(curX,curY,arr_tmp))//判断能否变换成此形状
{
curBlock = type;//设置当前积木块的形状为更改后的形状
eval("arr_curBlock = " + curBlock + ";");//设置更改后的积木形状
eval("ShowBlock(block_div.style.pixelLeft,block_div.style.pixelTop," + curBlock + ",colors[" + cid + "]);");//显示现在的形状
}
}
//判断在x,y处的积木块是否相容于游戏区
function CanMove(x,y,block)
{
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
//如果在某处既是要判断的积木块的积木格又是游戏区已经有积木的地方或是游戏区的边界
//注意在边界上的值是1――这就是为什么我们设置它为1的原因――则返回false,即不可移动到x,y处
//这里的getd函数就是我们上面为Array对象新添加的功能,它调用dimensions函数
if(block.getd(i,j,4)&table.getd(y/n_IncStep+i,x/n_IncStep+j,16))
return false;
}
}
return true;//否则可移动,返回true
}
//设置下一块积木
function NewBlock()
{
curBlock = nextBlock;//设置原来的下一块积木为当前积木
cid = ncid;//原来的下一种颜色为当前颜色
bid = Math.round(Math.random()*(blocks.length-1));//获得随机的下一块积木
ncid = Math.round(Math.random()*(colors.length-1));//获得随机的下一种颜色
nextBlock = blocks[bid];//设置下一块积木
eval("arr_curBlock = " + curBlock + ";");//获得当前积木形状
eval("ShowBlock(120,0," + curBlock + ",colors[" + cid + "]);");//在游戏区顶部显示当前积木
eval("arr_curBlock = " + curBlock + ";");
eval("ShowBlock1(466,116," + nextBlock + ",colors[" + ncid + "],nblock_tbl,nblock_div);");//在右边显示区显示下一块积木
}
//在左边游戏区放置积木块,实际上我们需要处理的是把积木格占据的位置的值赋1和在此位置染上积木格的颜色
function SaveBlock()
{
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
table[(curY/n_IncStep+i)*16+curX/n_IncStep+j]|=arr_curBlock[i*4+j];//在当前位置放置积木格
if(arr_curBlock[i*4+j]==1)//如果该处为积木块的值为1,即它是积木格
if((curY/n_IncStep+i<21)&&(curX/n_IncStep+j>1)&&(curX/n_IncStep+j<14))//如果在游戏区的可视区域
table_tbl.rows(curY/n_IncStep+i).cells(curX/n_IncStep+j).style.background = colors[cid];//则在该处显示积木块的颜色
if(table[(curY/n_IncStep+i)*16+curX/n_IncStep+j]!=1)//如果该处无积木
table_tbl.rows(curY/n_IncStep+i).cells(curX/n_IncStep+j).style.background = "black";//则显示黑色
}
}
}
//俄罗斯方块中的删除某一行
function DelLine(line)
{
for(i=line;i>0;i--)//从本行开始,从下往上
{
for(j=2;j<14;j++)//对于游戏区的可视区域进行操作
{
table[i*16+j]=table[(i-1)*16+j];//由于要消去本行,这意味着本行以上的行都下降一行
}
}
table_tbl.deleteRow(line);//从HTML的相应table中也消去这一行
table_tbl.insertRow(0);//在第0行处插入一个空行
for(i=0;i<16;i++)
{
table_tbl.rows(0).insertCell();//为第一行添加单元格
if(i<2||i>13) //在可视游戏区外,将单元格颜色设成背景色
table_tbl.rows(0).cells(i).style.background="navy";
}
killedlines++;//删除的行数加1
cll.innerText=parseInt(cll.innerText)+1;//成绩加1
}
//当积木落下时,判断并删除行
function DelLines()
{
var c,d,i,j;
d=0;//该次删除的总行数
curY=block_div.style.pixelTop;//当前积木的最高行像素值
for(i=(curY/20+3);i>curY/20-1;i--)//监测当前积木造成的四行是否可以删除
{
c=0;
//计算该行的每格值的总和
for(j=2;j<14;j++)
{
if(isNaN(table[i*16+j])||i==21)
break;
c+=table[i*16+j];
}
//如果c==12,则表示该行每格都是某个积木格,则可删除
if(c==12)
{
DelLine(i);//删除该行
i++;//由于该行已被删除,再次从下一行开始判断
d++;//删除行数加1
}
}
if(d>0)
sco.innerText=parseInt(sco.innerText)+d*d*36;//加分,一次消去的行越多,分数越多
}
//判断是否满足game over条件的的函数
function Lucifer()
{
for(var i=2;i<14;i++)
{
if(table[16+i]==1) //若第一行有积木块,则game over
return true;
}
return false;
}
//游戏结束处理函数
function GameOver()
{
gameover=1;//设置游戏结束标志位
clearInterval(gameInterval);//结束游戏
block_div.innerHTML="";//先清空
for(i=0;i<21;i++)
{
for(j=2;j<14;j++)
{
setTimeout("table_tbl.rows(" + i + ").cells(" + j + ").style.background = colors[Math.round(Math.random()*7)];",16*i*j);//用随机颜色填满游戏区,这是俄罗斯方块的标准方式
}
}
nblock_div.innerHTML = "Game Over";//设置右边显示区出现"Game Over"字样。
}
//检测用户按键,这里主要是检测光标键和a,s,d,w和A,S,D,W键
function document_onkeydown()
{
if(gameover==1) //若游戏结束,则返回不响应
return;
with(block_div.style)
{
curX = pixelLeft;//获得游戏区的左边沿
curY = pixelTop;//获得游戏区的上边沿
switch(event.keyCode)//获得用户的按键
{
case 65://如果是A,则积木向左移动一步
case 97://如果是a,则与A同功能
case 37://如果是光标左键,则与A同功能
if(CanMove(curX-n_IncStep,curY,arr_curBlock))
pixelLeft-=n_IncStep;
break;
case 38://如果是光标上键,则积木变成下一形状
Change(1);
break;
case 87://如果是W,则积木变成上一形状
case 119://如果是w,则与W同功能
Change(-1);
break;
case 100://如果是d,则积木向右移动一步
case 68://如果是D,则与d同功能
case 39://如果是光标右键,则与d同功能
if(CanMove(curX+n_IncStep,curY,arr_curBlock))
pixelLeft+=n_IncStep;
break;
case 83://如果是S,则积木向下移动一步
case 115://如果是s,则与S同功能
case 40://如果是光标下键,则与S同功能
if(CanMove(curX,curY+n_IncStep,arr_curBlock))
{
pixelTop+=n_IncStep;
}
else//不能移动
{
SaveBlock();//则放置积木
DelLines();//删除可删的行
if(Lucifer())//判断是否达到游戏结束条件
{
GameOver();//如果达到则游戏结束
return;
}
sco.innerText=parseInt(sco.innerText)+2;//游戏未结束则总分加2
NewBlock();//开始进行下一步添加积木
}
break;
case 32://如果是空格符,则设定暂停,再次按下空格符则运行
if(pause==0)
{
clearInterval(gameInterval);//停止循环定时器
pause=1;
}
else
{
gameInterval=window.setInterval("Handle_Interval()",(maxspeed-speed+1)*60);//开始循环定时器
pause=0;
}
break;
default:
}
}
}
//在循环定时器中被调用的函数
//用来处理各种情况
function Handle_Interval()
{
curX = block_div.style.pixelLeft;//获得游戏区的当前左边沿,以像素为单位
curY = block_div.style.pixelTop;//获得游戏区的当前上边沿,以像素为单位
if(CanMove(curX,curY+n_IncStep,arr_curBlock))//用来判断是否可以下落
{
block_div.style.pixelTop+=n_IncStep;//如果可以则下落一个积木格的像素值,或者说是一行
}
else//如果无法下落
{
SaveBlock();//放置积木
DelLines();//删除所有可以删除的行
if(Lucifer())//如果达到游戏的结束条件
{
GameOver();//则游戏结束
return;
}
sco.innerText=parseInt(sco.innerText)+2//若游戏未结束则总分加2
NewBlock();//添加新的积木块
}
//若删除的行数大于某一标准
//则认为游戏者的水平可以达到下一标准,从而增加积木块的下落速度
if(killedlines>=clr_per_line)
{
killedlines-=clr_per_line;//减少删除行数纪录,以用来测试下一个标准
//增大游戏速度
if(speed<maxspeed)
speed++;
else
speed=maxspeed;
spd.innerText=speed;//在速度显示处显示速度
clearInterval(gameInterval);//由于速度变化造成循环定时器的时间间隔的变化,因此消除以前的定时器效果
gameInterval=window.setInterval("Handle_Interval()",(maxspeed-speed+1)*60);//开始新的循环定时器函数
}
}
//-->
</script>
<script event=onkeydown for=document language=javascript>
<!--
if(document.all)
document_onkeydown()//设置document.onkeydown事件的处理函数为document_onkeydown函数
//-->
</script>
<DIV id=block_div style="LEFT: 60px; TOP: 0px">
<TABLE border=0 cellPadding=0 cellSpacing=0 id=block_tbl>
<script>
//描述左边游戏区的积木块的属性
if(document.all)
{
for(var i=0;i<4;i++)
{
document.write("<tr>");
for(var j=0;j<4;j++)
{
document.write("<td style=\"border:1 solid black;\"></td>");
}
document.write("</tr>");
}
}
</script>
<TBODY>
</TBODY>
</TABLE>
</DIV>
<DIV id=nblock_div>
<TABLE border=0 cellPadding=0 cellSpacing=0 id=nblock_tbl>
<script>
//描述右边显示区的积木块的属性
if(document.all)
{
for(var i=0;i<4;i++)
{
document.write("<tr>");
for(var j=0;j<4;j++)
{
document.write("<td style=\"height:40;width:40;border:1 outset black;\"></td>");
}
document.write("</tr>");
}
}
</script>
<TBODY>
</TBODY>
</TABLE>
</DIV>
<DIV id=table_div>
<TABLE border=0 cellPadding=0 cellSpacing=0 id=table_tbl>
<script>
//描述游戏区
if(document.all)
{
for(var i=0;i<22;i++)
{
document.write("<tr>");
for(var j=0;j<16;j++)
{
var d2 = i * 16 + j;
if(table[d2]==1)
document.write("<td bgcolor=navy></td>");
else
document.write("<td style=\"background:black;\"></td>");
}
document.write("</tr>");
}
}
</script>
<TBODY>
</TBODY>
</TABLE>
</DIV>
<DIV id=title_div noWrap>
请输入数字(1-9)来调整速度:
<INPUT id=speedin size=8>
<BUTTON id=but onclick=begintet()>
开始
</BUTTON>
</DIV>
<DIV id=infobar_div>
<TABLE border=1 borderColor=navy cellPadding=0 cellSpacing=0>
<TBODY>
<TR align=middle>
<TD style="COLOR: #99ccff; FONT: 12px system; WIDTH: 56px">
<font size="2">
速度
</font>
:
</TD>
<TD id=spd style="COLOR: red; FONT: 12px system">
1
</TD>
<TD style="COLOR: #99ccff; FONT: 12px system; WIDTH: 86px">
总分:
</TD>
<TD id=sco style="COLOR: red; FONT: 12px system">
0
</TD>
<TD style="COLOR: #99ccff; FONT: 12px system; WIDTH: 96px">
成绩:
</TD>
<TD id=cll style="COLOR: red; FONT: 12px system">
0
</TD>
</TR>
</TBODY>
</TABLE>
</DIV>
<DIV id=infobar2_div>
</DIV>
<script id=MainSection language=javascript>
<!--
//初始化,在游戏区和显示区各显示一个积木块
//首先给出一块积木块,然后调用NewBlock()函数,这个函数使这里的积木块在游戏区显示
//然后NewBlock()函数会自动创建下一块积木并显示在右边的显示区
if(document.all)//IE浏览器
{
//利用随机发生器产生随机的颜色和积木
ncid = Math.round(Math.random()*(colors.length-1));//下一个积木块的颜色
bid = Math.round(Math.random()*(blocks.length-1));//下一块积木块编号
nextBlock = blocks[bid];//获得下一块积木
NewBlock();//调用下一块积木,在显示区显示
}
//开始游戏的函数
function begintet()
{
document.all.speedin.disabled=true//一旦开始游戏,则设定不能改变速度
document.all.but.disabled=true//设置不能按开始按钮
speed=parseInt(document.all.speedin.value);//获得用户输入的速度
if(isNaN(speed)||speed==null||speed>maxspeed||speed<1) //处理各种非法情况
speed=1;
spd.innerText=speed;//显示用户输入的速度
gameInterval=window.setInterval("Handle_Interval()",(maxspeed-speed+1)*60);//根据用户输入的速度值来设置游戏的速度,speed越大,则setInterval的时间参数越小,则游戏速度越快
}
//-->
</script>
</body>
</html> |
|