沙发
whbchy [专家分:410] 发布于 2004-03-01 13:05:00
(*转载,,有更好的欢迎*)
俄罗斯方块详细说明
关于本站(www.delfan.com)的TETRIS(俄罗斯方块)很多网友发来电子邮件询问设计思路, 一直想写, 总是没有时间, 趁着今天休息, 就写一点东西吧.
1. 首先这个程序是个多线程, 就是处理下落的情况我们用一个单独的线程来处理. 关于线程编程方面的知识, 我就不罗索了, 可以参考本站收集的一篇文章<Java多线程编程详解>. 这个处理下落的线程同时也担负着处理开始的时候闪烁字体的任务.
2. 很多网友不理解造型数组的定义. 这里其实我是偷懒了, 本来应该只定义出来基本的形状, 就是7个基本的形状, 不用定义出来旋转后的情况, 旋转后的情况可以通过计算得到的. 我这里这样定义为了简化程序. 我们来看一下其定义及其含义:
byte SHAPE[][][][] = // [造型索引][旋转索引][4][坐标]
关于这个数组, 我们这么来想: 每个造型都是一个二维数组, 为了包含所有的情况, 就使用可能出现的最大的情况, 就是那个"■■■■"造型, 就必须用4x4的二维数组来处理. 这样, 我们就可以用"1"来表示造型中有方块的情况, "0"来表示没有方块的情况, 例如:
[][][][] 0,0,0,0
[]■[][] ==> 0,1,0,0
■■■[]1,1,1,0
[][][][]0,0,0,0
OK, 我们接着往下推导. 为了下落的时候处理方便, 我们用坐标来表示有方块的相对位置,注意, 只保留有方块的位置, 就是上面数组中为"1"的情况, 就可以把上述数组转化为这样的情况:
-----,-----,-----,-----
-----,(1,1),-----,-----
(3,1),(3,2),(3,3),-----
-----,-----,-----,-----
再来接着想, 为了简化处理旋转的情况, 我们把旋转的那个方块作为零坐标(0,0), 其他都是相对这个方块的相对坐标, 上面的这个"数组"就可以推出下面的情况:
------,------,-----,-----
------,(0,-1),-----,-----
(-1,0),(0, 0),(1,0),-----
------,------,-----,-----
现在, 每一个造型就可以变成一个元素为4的数组, 而每一个元素是一个坐标, 一个最标也是一个二维数组"{x,y}", 因此, 一个造型就可以表示为{{x1,y1},{x2,y2},{x3,y3},{x4,y4}}, 这时候数组的定义就是"造型[4][2]".
好, 我们现在把旋转后的情况加上, 也就是一个造型有4种旋转的情况, 此时, 数组就是"造型[4][4][2]".由此类推, 因为有7种不同的造型, 我们把他们整合到一个数组中, 就是"造型[7种造型][4种旋转情况][每个造型有4个方块][每个方块的坐标]". 这样, 我们就完成了整个数组的定义.
3. 下落过程的处理, 其实就是提前模拟出已经下落或旋转的情况, 然后去判断下落或旋转后, 是否和已经堆放的方块有重叠的情况, 是否有下落或旋转后超出边界的情况. 没有则下落或旋转, 有则判断是否需要停止下落或旋转, 是否要堆放等.
4. 双缓冲处理, 这个问题在本站的其他Applet中都有很详细的解释, 这里就不罗索了.
好了, 主要就是这些东西了, 如果您还有其他什么不懂的地方, 可以给我们发邮件或着留言. 最后祝大家早日成为编程高手~ :)
板凳
whbchy [专家分:410] 发布于 2004-03-02 12:15:00
刚找到的源程序:
USES Crt;
CONST
Change:Array [0..6,0..3,0..7] Of Byte =(((0,1,1,1,2,1,3,1),(1,0,1,1,1,2,1,3),(0,1,1,1,2,1,3,1),(1,0,1,1,1,2,1,3)),
((1,0,0,1,1,1,2,1),(1,0,1,1,1,2,2,1),(0,1,1,1,2,1,1,2),(1,0,0,1,1,1,1,2)),
((1,0,2,0,1,1,2,1),(1,0,2,0,1,1,2,1),(1,0,2,0,1,1,2,1),(1,0,2,0,1,1,2,1)),
((1,0,2,0,0,1,1,1),(0,0,0,1,1,1,1,2),(1,0,2,0,0,1,1,1),(0,0,0,1,1,1,1,2)),
((0,0,1,0,1,1,2,1),(1,0,0,1,1,1,0,2),(0,0,1,0,1,1,2,1),(1,0,0,1,1,1,0,2)),
((1,0,2,0,1,1,1,2),(0,0,0,1,1,1,2,1),(1,0,0,2,1,1,1,2),(2,2,0,1,1,1,2,1)),
((0,0,1,0,1,1,1,2),(2,0,0,1,1,1,2,1),(2,2,1,0,1,1,1,2),(0,2,0,1,1,1,2,1)));
VAR
Board:Array [0..3,0..11,1..25] Of Byte;
Players,N,Nowx,Nowy,Kind,Trans,Speed:Byte;
Time,Score:Word;
Now:Array [0..7] Of Byte;
PROCEDURE Furbish;
VAR B,C:Byte;
Begin
For C:=24 Downto 2 Do Begin
Gotoxy(1,C);
For B:=1 To 10 Do
If Board[0,B,C]=0 Then Write(' ')
Else Write('圹');
End;
End;
PROCEDURE Clear;
Var A,B,C:Byte;D:Boolean;
Begin
For A:=24 Downto 1 Do
Begin
D:=True;
For B:=1 To 10 Do
If Board[0,B,A]=0 Then D:=False;
If D=True Then
Begin
Score:=Score+10;Gotoxy(1,1);Write(Score:5,'0');
For C:=A Downto 2 Do
For B:=1 To 10 Do
Board[0,B,C]:=Board[0,B,C-1];
A:=A+1;
End;
End;
Furbish;
End;
FUNCTION Canmove(X,Y:Byte):Boolean;
BEGIN
Canmove:=True;
If Board[0,X+Now[0],Y+Now[1]]>0 Then Canmove:=False;
If Board[0,X+Now[2],Y+Now[3]]>0 Then Canmove:=False;
If Board[0,X+Now[4],Y+Now[5]]>0 Then Canmove:=False;
If Board[0,X+Now[6],Y+Now[7]]>0 Then Canmove:=False;
End;
PROCEDURE Clean;
Begin
Gotoxy((Nowx+Now[0])*2-1,Nowy+Now[1]);Write(' ');
Gotoxy((Nowx+Now[2])*2-1,Nowy+Now[3]);Write(' ');
Gotoxy((Nowx+Now[4])*2-1,Nowy+Now[5]);Write(' ');
Gotoxy((Nowx+Now[6])*2-1,Nowy+Now[7]);Write(' ');
End;
PROCEDURE Show;
Begin
Gotoxy((Nowx+Now[0])*2-1,Nowy+Now[1]);Write('圹');
Gotoxy((Nowx+Now[2])*2-1,Nowy+Now[3]);Write('圹');
Gotoxy((Nowx+Now[4])*2-1,Nowy+Now[5]);Write('圹');
Gotoxy((Nowx+Now[6])*2-1,Nowy+Now[7]);Write('圹');
End;
BEGIN
Fillchar(Board,Sizeof(Board),0);
Randomize;Score:=0;
For N:=1 To 24 Do
Board[0,0,N]:=1;
For N:=1 To 24 Do
Board[0,11,N]:=1;
For N:=1 To 10 Do
Board[0,N,25]:=1;
Window(31,2,50,25);Textcolor(White);Textbackground(Blue);
Clrscr;Window(31,2,51,25);
Speed:=1;
Kind:=Random(7);Trans:=Random(4);Nowx:=4;Nowy:=1;
For N:=0 To 7 Do
Now[N]:=Change[Kind,Trans,N];
While Canmove(Nowx,Nowy) Do
Begin
Repeat
Clean;Nowy:=Nowy+1;Show;
Repeat
If Keypressed Then
Case Upcase(Readkey) Of
#0:Case Readkey Of
#75:If Canmove(Nowx-1,Nowy) Then Begin Clean;Nowx:=Nowx-1;Show;End;
#77:If Canmove(Nowx+1,Nowy) Then Begin Clean;Nowx:=Nowx+1;Show;End;
#80:Begin Clean;Repeat
If Canmove(Nowx,Nowy+1) Then Nowy:=Nowy+1;
Until Not(Canmove(Nowx,Nowy+1));Show;End;
#61:Begin Gotoxy(9,12);Write('Pause');Repeat Delay(1000);Until Keypressed;Furbish;End;
End;
#27:Exit;
' ',#13:Begin
Clean;Trans:=Trans+1;
If Trans=4 Then Trans:=0;
For N:=0 To 7 Do
Now[N]:=Change[Kind,Trans,N];
If Not(Canmove(Nowx,Nowy)) Then Begin Trans:=Trans-1;For N:=0 To 7 Do
Now[N]:=Change[Kind,Trans,N];Show;End
Else Show;
End;
End;
Until Not(Keypressed);
Delay((10-Speed)*50);
Until Not(Canmove(Nowx,Nowy+1));
Score:=Score+1;Gotoxy(1,1);Write(Score:5,'0');Speed:=(Score Div 300)+1;
Board[0,Nowx+Now[0],Nowy+Now[1]]:=1;
Board[0,Nowx+Now[2],Nowy+Now[3]]:=1;
Board[0,Nowx+Now[4],Nowy+Now[5]]:=1;
Board[0,Nowx+Now[6],Nowy+Now[7]]:=1;
Clear;
Kind:=Random(7);Trans:=Random(4);Nowx:=4;Nowy:=1;
For N:=0 To 7 Do
Now[N]:=Change[Kind,Trans,N];
End;
Gotoxy(7,12);Write('GAME OVER');Readln;
END.