论坛: 编程破解 标题: 俄罗斯方块编程分析 复制本贴地址    
作者: 286 [unique]    版主   登录

首先,这个游戏有如下几个问题要解决:
1 速度控制,这个速度控制应不受用户按键的影响.每隔一定时间下落的方块(以下简称下落物)就无条件下落,并且随着时间的延长速度越来越快.因此可以通过一个

系统变量来控制.其值越来越小.下面程序用Delays控制.闲时可用delay(Delays)进行延时.
2 下落物的表示.可以有各种形式下落物,并且每个下落物又有几种状态.为了表示他们,可以用数组表示,鉴于其形状特点,建一个4X4的数组,数组值为0则表示该位不

显示,为1则显示。这里有个不好处理的地方是每种下落物的状态个数不同。有的只有一个状态,有的却有四个状态。为了处理方便,全部定义为四个状态,只是部

分有重复状态而已。
定义如下:
int a[7][4][4][4]={{{1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
    {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
    {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}},
  {{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
  {{1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},
  {{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},
  {{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}},
  {{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},
    {1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0}},
  {{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},
    {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0}}};
图形如下:
/*
    1    2  3  4    5    6  7
  8888  88 888  8  8  88  88
88  8  88  88  8  8
    8            8    8  8  8
    8      8
    8      88  88    88    8 888
    8      8    88  88  888  8

    8            8    8
  888            8    8
  88  88
    8
    88            888 8
    8            8  888

*/
3 整个下落区(也就是所有方块可在的地方),可以定义为15X27数组,表示方法同下落物,为0表示该位没有方块,为1有方块,显示出来。
4 下落处理。在下落过程中,有两种可能,一种是半空被挂住,一种是落到底部。无论哪种都不能再继续。
我的处理办法是,把下落物的数组和下落区的数组对应相加。由于二者值都或为0或为1,因此如果出现2,则表示两个有重合的,这样当然就不能下降了。恢复办法也很简单,就是相减一下就变成原来的了。当然这里还有一个必须考虑的地方就是落到底了,也得停,不然就落到无底洞了。
int Touch(int x,int y,int dx,int dy)
{
NoPass=CAN;
for (i=0;i<4;i++)
for (j=0;j<4;j++)
Position[x+dx+i][y+dy+j]+=b[i][j];
for (i=0;i<MAX;i++)
for (j=0;j<MAX;j++)
if (Position[i][j]>1) NoPass=CANNOT;
for (i=0;i<4;i++)
  for (j=0;j<4;j++)
Position[x+dx+i][y+dy+j]-=b[i][j];
if (NoPass==CANNOT && dx==0 && dy==1)
{
for (i=0;i<4;i++)
for (j=0;j<4;j++)
Position[x+i][y+j]+=b[i][j];
NoPass=BOTTOM;
}
return NoPass;
}
5 每一排充满后要消掉。这个处理相对简单,为了刺激玩者,还可以对同时消多排的加大分量。比如同时消两排的分数要比单独两次消一排的分数要多。
void DetectFill()
{
int Number,Fall,FallTime=0;
for (i=Shu-1;i>=0;i--)
{
Number=0;
for (j=0;j<Heng;j++)
if (Position[j][i]==1) Number++;
if (Number==Heng)
{
FallTime++;
if (Sounds==CAN)
{
sound(500);
delay(500);
nosound();
}
for (Fall=i;Fall>0;Fall--)
  for (j=0;j<Heng;j++)
  {
Position[j][Fall]=Position[j][Fall-1];
if (Position[j][Fall]==0) DrawBox(j,Fall,0);
      else DrawBox(j,Fall,1);
  }
i++;
}
}
switch(FallTime)
{
case 0:break;
case 1:Scores+=1;break;
case 2:Scores+=3;break;
case 3:Scores+=6;break;
case 4:Scores+=10;break;
}
if (FallTime!=0)
{
GetScores();
if (Scores%100==0) Delays-=100;
}
}

6 还有一个,对于TC编程人员来说最困难的可能就是键盘控制了。因为对于DOS系统,可视字符可直接获得ASCII码,但控制字符由于只能获得SCAN扫描码,因此相对比较困难。这里有个函数,用户可方便的一次转换。
int GetKey(void)
{
int Ch,Low,Hig;
Ch=bioskey(0);
Low=Ch&0x00ff;
Hig=(Ch&0xff00)>>8;
return(Low==0?Hig+256:Low);
}
这样,不管用户按哪一个键,都可以直接获得。对于其中ASCII部分,得的结果小于128,对于控制字符(比如上下左右键)得到的大于128。


7 完整源代码如下。在DOS环境,TC2。0下调试通过。
#include <stdlib.h>
#include <stdio.h>
#include <graphics.h>

#define ESC    27
#define UP    328
#define DOWN  336
#define LEFT  331
#define RIGHT  333
#define BLANK  32
#define BOTTOM  2
#define CANNOT  1
#define CAN      0
#define MAX    30
#define F1    315
#define ADD 43
#define EQUAL 61
#define DEC 45
#define SOUNDs 115
#define SOUNDS  83
#define PAUSEP 80
#define PAUSEp 112

void Init();
void Down();
void GoOn();
void Display(int color);
void Give();
int Touch(int x,int y,int dx,int dy);
int GeyKey();
void Select();
void DetectFill();
void GetScores();
void Fail();
void Help();
void Quit();
void DrawBox(int x,int y,int Color);
void OutTextXY(int x,int y,char *String);
void DispScore(int x,int y,char Ch);
void DrawNext(int Color);

int Heng=15,Shu=27;
int Position[MAX][MAX];
int ActH,ActS;
int Act,Staus;
int i,j,k;
int Wid=10;
int NoPass=CAN;
int Delays=1000;
int BeginH=250,BeginS=7;
int Seconds=0;
int Scores=0;
int Sounds=CAN;
int PreAct,NextAct;
int a[7][4][4][4]={{{1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
    {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0},
    {1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0}},
  {{1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
  {{1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},
  {{1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
    {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0}},
  {{0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0}},
  {{1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},
    {1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0},
    {0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0}},
  {{0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0},
    {1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},
    {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
    {1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0}}};
int b[4][4];

main(int argc,char *argv[])
{
if (argc!=1)
{
if (argv[1]!="") Heng=atoi(argv[1]);
if (argv[2]!="") Shu=atoi(argv[2]);
}
Init();
PreAct=random(7);
for(;;)
{
NextAct=random(7);
DrawNext(1);
Act=PreAct;
if (Heng%2==0) ActH=Heng/2; else ActH=(Heng-1)/2;
ActS=0;
Staus=0;
NoPass=CAN;
Give();
Display(1);
GoOn();
PreAct=NextAct;
DrawNext(0);
}
}
void Init()
{
int GraphDriver=DETECT,GraphMode;
initgraph(&GraphDriver,&GraphMode,"");
if (kbhit()) Sounds=CANNOT;
setcolor(1);
OutTextXY(10,10,"Tetris");
OutTextXY(30,30,"Version 2.0");
OutTextXY(10,120,"Help:");
OutTextXY(20,140,"+      :Faster");
OutTextXY(20,160,"-      :Slower");
OutTextXY(20,180,"Esc    :Quit");
OutTextXY(20,200,"F1    :Help");
OutTextXY(10,310,"Copyright(c) 1998.2.22");
OutTextXY(10,320,"By Mr. Unique");
outtextxy(10,250,"Score: 00000");
rectangle(BeginH-3,BeginS-3,BeginH+Heng*(Wid+2)+2,BeginS+Shu*(Wid+2)+2);
rectangle(BeginH-5,BeginS-5,BeginH+Heng*(Wid+2)+4,BeginS+Shu*(Wid+2)+4);
rectangle(BeginH+(Heng+4)*(Wid+2)-2,BeginS+10,BeginH+(Heng+8)*(Wid+2)+2,BeginS+12+4*(Wid+2));
        for (i=0;i<MAX;i++)
for (j=0;j<MAX;j++)
Position[i][j]=1;
for (i=0;i<Heng;i++)
for (j=0;j<Shu;j++)
Position[i][j]=0;
for (i=0;i<Heng;i++)
for (j=0;j<Shu;j++)
DrawBox(i,j,0);
randomize();
}
void GoOn()
{
for(;;)
{
Seconds++;
if (Seconds>=Delays)
{
Down();
Seconds=0;
if (NoPass==BOTTOM)
{
DetectFill();
if (ActS==0) Fail();
return;
}
}
if (kbhit())
Select();
}
}
void Down()
{
Display(0);
if (Touch(ActH,ActS,0,1)==CAN)
ActS++;
Display(1);
}
int Touch(int x,int y,int dx,int dy)
{
NoPass=CAN;
for (i=0;i<4;i++)
for (j=0;j<4;j++)
Position[x+dx+i][y+dy+j]+=b[i][j];
for (i=0;i<MAX;i++)
for (j=0;j<MAX;j++)
if (Position[i][j]>1) NoPass=CANNOT;
for (i=0;i<4;i++)
  for (j=0;j<4;j++)
Position[x+dx+i][y+dy+j]-=b[i][j];
if (NoPass==CANNOT && dx==0 && dy==1)
{
for (i=0;i<4;i++)
for (j=0;j<4;j++)
Position[x+i][y+j]+=b[i][j];
NoPass=BOTTOM;
}
return NoPass;
}
int GetKey(void)
{
int Ch,Low,Hig;
Ch=bioskey(0);
Low=Ch&0x00ff;
Hig=(Ch&0xff00)>>8;
return(Low==0?Hig+256:Low);
}
void Select()
{
int OldStaus;
switch(GetKey())
{
case ESC  :Quit();break;
case DOWN  :Seconds+=1450;break;
case LEFT  :Display(0);
    if (ActH>0 && Touch(ActH,ActS,-1,0)==CAN) ActH--;
    Display(1);break;
case RIGHT :Display(0);
    if (ActH<Heng && Touch(ActH,ActS,1,0)==CAN) ActH++;
    Display(1);break;
case F1    :Help();break;
case EQUAL :
case ADD  :if (Delays>300) Delays-=100;break;
case DEC  :if (Delays<3000) Delays+=100;break;
case PAUSEP :
case PAUSEp :getch();break;
case SOUNDS :
case SOUNDs :if (Sounds==CAN) Sounds=CANNOT; else Sounds=CAN;break;
case UP    :
case BLANK :Display(0);
    OldStaus=Staus;
    switch(Act)
    {
case 0:
case 3:
case 4:if (Staus==1) Staus=0;else Staus=1;break;
case 1:break;
case 2:
case 5:
case 6:if (Staus==3) Staus=0;else Staus++;break;
    }
    Give();
    if (Touch(ActH,ActS,0,0)==CANNOT)
    {
Staus=OldStaus;
Give();
    }
    Display(1);
    break;
}
}
void Quit()
{
int ch,TopScore;
FILE *fp;
if ((fp=fopen("Russian.scr","r+"))!=NULL)
{
fscanf(fp,"%d",&TopScore);
if (Scores>TopScore)
{
setcolor(1);
outtextxy(470,80,"Hello !");
outtextxy(470,100,"In all the players,");
outtextxy(470,120,"You are the First !");
outtextxy(470,140,"And your score will");
outtextxy(470,160,"be the NEW RECORD !");
fseek(fp,0L,0);
fprintf(fp,"%d",Scores);
}
fclose(fp);
}
setcolor(1);
OutTextXY(470,220,"Are You Sure (Yes/no)?");
ch=getch();
if (ch=='y'||ch=='Y')
{
closegraph();
delay(20);
exit(0);
}
setcolor(0);
outtextxy(470,220,"Are You Sure (Yes/no)?");
}
void OutTextXY(int x,int y,char *String)
{
int i=0;
char a[2];
moveto(x,y);
a[1]='\0';
while (*(String+i)!='\0')
{
a[0]=*(String+i);
outtext(a);
if (Sounds==CAN && a[0]!=' ')
{
sound(3000);
delay(50);
nosound();
}
i++;
}
}
void Help()
{
unsigned Save;
void *Buf;
Save=imagesize(160,120,500,360);
Buf=malloc(Save);
getimage(160,120,500,360,Buf);
setfillstyle(1,1);
bar(160,120,500,280);
setcolor(0);
OutTextXY(170,130,"            About & Help");
OutTextXY(170,150,"    #  # #    ##########  #  #    #    ");
OutTextXY(170,160,"  # ##  # #  #  #  #  # ###### ###    ");
OutTextXY(170,170,"  ##########  ##########  ## #  #      ");
OutTextXY(170,180," # #  #  # #      #      # ##  ####    ");
OutTextXY(170,190,"  #  ## #        ####    ## #  # #    ");
OutTextXY(170,200,"  # ##  # #    #  #    # ##  # #    ");
OutTextXY(170,210,"  #  #  #    ## ## #  ###### # #    ");
OutTextXY(170,220,"  ## #  ## #      ##    #  #  # #    ");
OutTextXY(170,230,"  # ##    #    ####    #    ##  #    ");
OutTextXY(170,260,"        Good Luckly to You !!!          ");
getch();
putimage(160,120,Buf,0);
free(Buf);
}
void GetScores()
{
int Sec10000,Sec1000,Sec100,Sec10,Sec1;
setfillstyle(0,1);
bar(60,250,109,260);
Sec1=Scores%10;
Sec10=(Scores%100-Scores%10)/10;
Sec100=(Scores%1000-Scores%100)/100;
Sec1000=(Scores%10000-Scores%1000)/1000;
Sec10000=(Scores%100000-Scores%10000)/10000;
DispScore(60,250,'0'+Sec10000);
DispScore(70,250,'0'+Sec1000);
DispScore(80,250,'0'+Sec100);
DispScore(90,250,'0'+Sec10);
DispScore(100,250,'0'+Sec1);
DispScore(110,250,'0');
DispScore(120,250,'0');
}
void DispScore(int x,int y,char Ch)
{
char a[2];
a[1]='\0';
a[0]=Ch;
outtextxy(x,y,a);
}
void Give()
{
for (i=0;i<4;i++)
for (j=0;j<4;j++)
b[i][j]=a[Act][Staus][i][j];
}
void Display(int color)
{
for (i=0;i<4;i++)
for (j=0;j<4;j++)
if (b[i][j]==1) DrawBox(ActH+i,ActS+j,color);
}
void DrawBox(int x,int y,int Color)
{
x=BeginH+x*(Wid+2);
y=BeginS+y*(Wid+2);
setfillstyle(1,Color);
bar(x+2,y+2,x+Wid-1,y+Wid-1);
if (Color==0)
setcolor(1);
else
setcolor(0);
rectangle(x+4,y+4,x+Wid-4,y+Wid-4);
}
void DrawNext(int Color)
{
for (i=0;i<4;i++)
for (j=0;j<4;j++)
if (a[NextAct][0][i][j]==1) DrawBox(Heng+4+i,1+j,Color);
}
void DetectFill()
{
int Number,Fall,FallTime=0;
for (i=Shu-1;i>=0;i--)
{
Number=0;
for (j=0;j<Heng;j++)
if (Position[j][i]==1) Number++;
if (Number==Heng)
{
FallTime++;
if (Sounds==CAN)
{
sound(500);
delay(500);
nosound();
}
for (Fall=i;Fall>0;Fall--)
  for (j=0;j<Heng;j++)
  {
Position[j][Fall]=Position[j][Fall-1];
if (Position[j][Fall]==0) DrawBox(j,Fall,0);
      else DrawBox(j,Fall,1);
  }
i++;
}
}
switch(FallTime)
{
case 0:break;
case 1:Scores+=1;break;
case 2:Scores+=3;break;
case 3:Scores+=6;break;
case 4:Scores+=10;break;
}
if (FallTime!=0)
{
GetScores();
if (Scores%100==0) Delays-=100;
}
}
void Fail()
{
if (Sounds==CAN)
{
for (k=0;k<3;k++)
{
sound(300);
delay(200);
nosound();
}
}
setcolor(1);
OutTextXY(440,200,"Game over!");
Quit();
closegraph();
exit(0);
}

在DOS环境,TC2。0下调试通过。
由于是早期程序,所以速度、颜色等各处不一定合适,后来也没作过任何修改。请大家指正。

地主 发表时间: 09/16 13:25

回复: jkd [jkd]   论坛用户   登录
大哥,你真猛!!!!!!!!
  哪个大学的?
小弟去找你!!!!!!!!!

B1层 发表时间: 09/16 13:46

回复: kert_t8 [kert_t8]   论坛用户   登录
斑竹就是斑竹,不服不行

B2层 发表时间: 09/16 15:45

回复: ceo_8008 [ceo_8008]   论坛用户   登录
五体投地

学海无崖・・

B3层 发表时间: 09/16 22:02

回复: 286 [unique]   版主   登录
不要这么说,其实这些程序很一般,很多地方实现起来并不高明。
再说,听了你的的话我会骄傲的.....

B4层 发表时间: 09/17 10:02

回复: flyfalcon [flyfalcon]      登录
说实在,286做得很好啊,
其实,我学程序本义也是为了做游戏啊,
谁叫游戏误我的学业呢,
现在得好好向 版主学习啦
请问版主是girl还是boy 啊



[此贴被 枫叶依红(flyfalcon) 在 09月18日13时12分 编辑过]

B5层 发表时间: 09/18 13:40

回复: jkd [jkd]   论坛用户   登录
好厉害1

B6层 发表时间: 09/19 15:12

回复: smx8796 [smx8796]   论坛用户   登录
大哥就是大哥,小弟佩服的五体投地
我也很想学c,但是不知该从何入手。
请问大哥能否教教小弟

B7层 发表时间: 09/22 20:41

回复: wasdeszwsx [wasdeszwsx]   论坛用户   登录
支持你
希望在多一写好的

B8层 发表时间: 09/22 22:32

回复: guangtian [guangtian]   论坛用户   登录
俄罗斯方块我也编过,为什么当时我没遇到你?不然是不好多问题都轻易解决了。

B9层 发表时间: 09/28 13:24

回复: wkbsb [wkbsb]   论坛用户   登录
我觉的代码并不重要,最主要的是你编这个程序的思路.

B10层 发表时间: 09/29 23:52

回复: ceo_8008 [ceo_8008]   论坛用户   登录
就是算法了・・

程序的灵魂嘛

也是一个人的高低之分了

B11层 发表时间: 09/30 10:02

回复: lwei889 [lwei889]   论坛用户   登录
我也是c语言的学习者,但,看到你的程序,我才意思到,我所学的不及你的万分之一啊?能请教你这个程序的核心是什么吗?

B12层 发表时间: 09/30 12:19

回复: blindeaf [blindeaf]   论坛用户   登录
我以前也想编个俄罗斯方块,但没编出来。看了你的程序给我收益不小。

B13层 发表时间: 10/07 21:16

回复: honyry [honyry]   论坛用户   登录

电脑是网吧的
以前我在学校也是用C编程
能不能教教我 用C语言编个扫描器或者简单的木马什么的!!!
因为我现在还不知道原理啊!上面的程序很好

B14层 发表时间: 10/07 21:32

回复: Answer [_answer]   论坛用户   登录


B15层 发表时间: 04-02-23 19:35

回复: sniper167 [sniper167]   论坛用户   登录

佩服的全体投地

B16层 发表时间: 04-02-24 13:02

回复: yuncocoon [yuncocoon]   论坛用户   登录


B17层 发表时间: 04-02-25 00:02

回复: kert_t8 [kert_t8]   论坛用户   登录
有人想看,又懒得找,只有我给他顶起来了哦

B18层 发表时间: 05-01-01 12:58

回复: mingren123 [mingren123]   论坛用户   登录
作者已是小有成就了啊

B19层 发表时间: 05-01-10 12:47

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号