问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

用c语言编写俄罗斯方块程序 求详解54

发布网友 发布时间:2023-10-09 23:51

我来回答

5个回答

热心网友 时间:2023-11-19 19:34

1、用C语言绘制图形界面

EasyX图形库(http://www.easyx.cn)即TC的图形库在VC下的移植。

包含库#include <graphics.h>

先初始化图形窗口

initgraph(WINDOW_WIDTH, WINDOW_HIGH) ;WINDOW_WIDTH为窗口的宽带,WINDOW_HIGH为窗口的高度。

清空绘图设备

cleardevice();

设置画笔颜色

setcolor(RED) ;

设置线条风格

setlinestyle(PS_SOLID, NULL, 0);

画矩形

rectangle

还有画线、显示文字等函数,可以参照其帮助文档。

注意:由于我们用的是EasyX图形库,故源文件后缀要为.cpp,但其中内容都是C的语法。

2、存储表示出俄罗斯方块的形状

一、我们可以用编号,不同的编号代表不同的俄罗斯方块,根据编号把不同方块的画法写在代码中,这样19种

方块就得有19种相应的代码来描绘。而且这样扩展性不好,若以后设计了新的方块,则需要更改大量源代码。

二、我们很自然的想到可用字模点阵的形式来表示,即设置一个4行4列的数组,元素置1即代表这个位置有小

方块,元素置0即代表这个位置无小方块,这个整个的4*4的数组组成俄罗斯方块的形状。

1000

1000

1100

0000

这个方法挺靠谱,但我们还可以优化一下:不用4*4的数组,而是用16个bit位来表示这个点阵。这样存储起来比较方便,故我们用unsigned int 的低16位来表示方块的点阵。

我们可以用掩码与表示俄罗斯方块的位进行操作,来识别并在屏幕上画出方块。

我们把俄罗斯方块点阵的数位存在rockArray中,我们可以事先把这19种方块的字模点阵自己转化成十六进制,然后在rockArray数组的初始化时赋值进去。

但这样做未免有点太费力,且扩展性也不太好,若以后设计的新方块种类加入,要改变数组rockArray中的值。

我们可以考虑把所有俄罗斯方块的点阵存储在配置文件中,在程序初始化时读取文件,把这些点阵转换成unsigned int的变量存储在rockArray中。

这样,以后我们增添新的方块形状只需要在配置文件中增加新的点阵即可。

@###

@###

@@##

####   (为使得看起来更醒目,我们用@表示1,用#表示0)

3、让图形动起来

在某位置处用函数DrawRock在屏幕上画出俄罗斯方块,然后再擦除掉(即用背景色在原位置处重绘一次方块),最后在下落的下一个位置处用函数DrawRock在屏幕上画出俄罗斯方块,如此循环,中间用计时器间隔一段时间以控制下落的速度。

同理,按下屏幕的左右键也是如此,只是在按下键盘时把方块的位置重新计算了。

那么按下上方向键时,如何让方块翻转呢?

我们在配置文件中就把方块的顺时针翻转形态放在了一起:

@###

@###

@@##

####

@@@#

@###

####

####

@@##

#@##

#@##

####

##@#

@@@#

####

####

我们每按一次上方向键改变一次方块的形状即可。若一直按上键,形状应该是循环地翻滚。

我们想到了循环链表的数据结构可实现这个效果。

可是我们若把这些一种类的方块的各种形态串成循环链表形式,那么每次重新生成方块时我们就难以随机地生成方块了。

故还是得用数组来存储,但又要有循环链表的功能,于是我们想到了静态循环链表。

我们用结构体来作为一个方块在rockArray中的元素

typedef struct ROCK

{  //用来表示方块的形状(每一个字节是8位,用每4位表示方块中的一行)

unsigned int rockShapeBits ; 

int          nextRockIndex ;  //下一个方块,在数组中的下标

} RockType ;

这样,当我们按下上方向键时,把传入函数DrawRock中的rockIndex变为当前方块结构体中的nextRockIndex即可。

参考资料:C语言图形界面篇

热心网友 时间:2023-11-19 19:35

在写一个程序之前得先有思路,本题中得思路是:

随机给出不同的形状(长条形、Z字形、反Z形、田字形、7字形、反7形、T字型)下落填充给定的区域,若填满一条便消掉,记分,当达到一定的分数时,过关,每关方块下落的速度不同,若在游戏中各形状填满了给定区域,为输者。

有了思路再动手,如果不会可以参考一下别人开源的项目!

因为项目复杂性,我给出了一个俄罗斯方块程序的项目地址在最后,祝您好运!

项目地址:俄罗斯方块游戏

热心网友 时间:2023-11-19 19:35

俄罗斯方块C源代码

#include <stdio.h>

#include <windows.h>

#include <conio.h>

#include <time.h>

#define  ZL  4     //坐标增量, 不使游戏窗口靠边

#define WID  36    //游戏窗口的宽度

#define HEI  20    //游戏窗口的高度

int i,j,Ta,Tb,Tc;      // Ta,Tb,Tc用于记住和转换方块变量的值

int a[60][60]={0};    //标记游戏屏幕各坐标点:0,1,2分别为空、方块、边框

int b[4];        //标记4个"口"方块:1有,0无,类似开关

int x,y, level,score,speed;    //方块中心位置的x,y坐标,游戏等级、得分和游戏速度

int flag,next;   //当前要操作的方块类型序号,下一个方块类型序号

void gtxy(int m, int n);   //以下声明要用到的自编函数

void gflag( );  //获得下一方块序号

void csh( );  //初始化界面

void start( );  //开始部分

void prfk ( );  //打印方块

void clfk( );  //清除方块

void mkfk( );  //制作方块

void keyD( );  //按键操作

int  ifmov( );  //判断方块能否移动或变体

void clHA( );  //清除满行的方块

void clNEXT( );  //清除边框外的NEXT方块

int main( )

{ csh( );   

   while(1)

     {start( );  //开始部分

       while(1)

       { prfk( );  

         Sleep(speed); //延时

          clfk( );

          Tb=x;Tc=flag;  //临存当前x坐标和序号,以备撤销操作

          keyD( );  

          y++;     //方块向下移动

         if (ifmov( )==0) { y--; prfk( ); dlHA( ); break;} //不可动放下,删行,跨出循环

       }

      for(i=y-2;i<y+2;i++){ if (i==ZL) { j=0; } }  //方块触到框顶

     if (j==0) { system("cls");gtxy(10,10);printf("游戏结束!"); getch(); break; } 

    clNEXT( );  //清除框外的NEXT方块

    }

  return 0;

}

void gtxy(int m, int n)  //控制光标移动

{COORD pos;  //定义变量

 pos.X = m;  //横坐标

 pos.Y = n;   //纵坐标

 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); 

}

void csh( )    //初始化界面

{gtxy(ZL+WID/2-5,ZL-2); printf("俄罗斯方块");      //打印游戏名称

 gtxy(ZL+WID+3,ZL+7); printf("******* NEXT:");  //打印菜单信息

 gtxy(ZL+WID+3,ZL+13); printf("**********");

 gtxy(ZL+WID+3,ZL+15); printf("Esc :退出游戏");

gtxy(ZL+WID+3,ZL+17); printf("↑键:变体");

 gtxy(ZL+WID+3,ZL+19); printf("空格:暂停游戏");

 gtxy(ZL,ZL);  printf("╔");  gtxy(ZL+WID-2,ZL);  printf("╗");  //打印框角

 gtxy(ZL,ZL+HEI);  printf("╚");  gtxy(ZL+WID-2,ZL+HEI);  printf("╝");

a[ZL][ZL+HEI]=2;  a[ZL+WID-2][ZL+HEI]=2;  //记住有图案

 for(i=2;i<WID-2;i+=2) {gtxy(ZL+i,ZL);  printf("═"); }  //打印上横框

 for(i=2;i<WID-2;i+=2) {gtxy(ZL+i,ZL+HEI); printf("═"); a[ZL+i][ZL+HEI]=2; } //下框

 for(i=1;i<HEI;i++) { gtxy(ZL,ZL+i);  printf("║"); a[ZL][ZL+i]=2; }  //左竖框记住有图案

 for(i=1;i<HEI;i++) {gtxy(ZL+WID-2,ZL+i); printf("║"); a[ZL+WID-2][ZL+i]=2; } //右框

 CONSOLE_CURSOR_INFO cursor_info={1,0};   //以下是隐藏光标的设置

 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);

 level=1; score=0; speed=400;

 gflag( );  flag=next;  //获得一个当前方块序号

}

void gflag( )   //获得下一个方块的序号

{ srand((unsigned)time(NULL)); next = rand()%19+1; }

void start( )  //开始部分

{ gflag( ); Ta=flag; flag=next;  //保存当前方块序号,将下一方块序号临时操作

  x=ZL+WID+6; y=ZL+10; prfk( );  //给x,y赋值,在框外打印出下一方块

 flag=Ta; x=ZL+WID/2; y=ZL-1;  //取回当前方块序号,并给x,y赋值

}

void prfk ( )  //打印俄罗斯方块

{ for(i=0;i<4;i++) {b[i]=1; }  //数组b[4]每个元素的值都为1

  mkfk ( );  //制作俄罗斯方块

 for( i= x-2; i<=x+4; i+=2 )  //打印方块

  { for(j=y-2;j<= y+1;j++) { if( a[i][j]==1 && j>ZL ){ gtxy(i,j); printf("□"); } } }

 gtxy(ZL+WID+3,ZL+1);   printf("level : %d",level);  //以下打印菜单信息

 gtxy(ZL+WID+3,ZL+3);  printf("score : %d",score);

 gtxy(ZL+WID+3,ZL+5);  printf("speed : %d",speed);

}

void clfk( )  //清除俄罗斯方块

{ for(i=0;i<4;i++) { b[i]=0; }  //数组b[4]每个元素的值都为0

  mkfk ( );  //制作俄罗斯方块

 for( i=x-2; i<=x+4; i+=2 )  //清除方块

  { for(j=y-2;j<=y+1;j++){ if( a[i][j]==0 && j>ZL ){ gtxy(i,j); printf("  "); } } }

}

void mkfk( )  //制作俄罗斯方块

{ a[x][ y]=b[0];  //方块中心位置状态: 1-有,0-无

 switch(flag)   //共6大类,19种小类型

 { case 1: { a[x][y-1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; }  //田字方块

  case 2: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x+4][y]=b[3]; break; }  //直线方块:----

  case 3: { a[x][y-1]=b[1]; a[x][y-2]=b[2]; a[x][y+1]=b[3]; break; }  //直线方块: |

  case 4: { a[x-2][y]=b[1]; a[x+2][y]=b[2]; a[x][y+1]=b[3]; break; }  //T字方块

  case 5: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y]=b[3]; break; }  //T字顺时针转90度

  case 6: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x+2][y]=b[3]; break; }  //T字顺转180度

  case 7: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y]=b[3]; break; }  //T字顺转270度

  case 8: { a[x][y+1]=b[1]; a[x-2][y]=b[2]; a[x+2][y+1]=b[3]; break; } //Z字方块

  case 9: { a[x][y-1]=b[1]; a[x-2][y]=b[2]; a[x-2][y+1]=b[3]; break; }  //Z字顺转90度

  case 10: { a[x][y-1]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; }  //Z字顺转180度

  case 11: { a[x][y+1]=b[1]; a[x+2][y-1]=b[2]; a[x+2][ y]=b[3]; break; } //Z字顺转270度

  case 12: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y-1]=b[3]; break; }  //7字方块

  case 13: {a[x-2][y]=b[1]; a[x+2][y-1]=b[2]; a[x+2][y]=b[3]; break; }  //7字顺转90度

  case 14: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x+2][y+1]=b[3]; break; }  //7字顺转180度

  case 15: { a[x-2][y]=b[1]; a[x-2][y+1]=b[2]; a[x+2][y]=b[3]; break; }  //7字顺转270度

  case 16: { a[x][y+1]=b[1]; a[x][y-1]=b[2]; a[x+2][y-1]=b[3]; break; }  //倒7字方块

 case 17: { a[x-2][y]=b[1]; a[x+2][y+1]=b[2]; a[x+2][y]=b[3]; break; }  //倒7字顺转90度

 case 18: { a[x][y-1]=b[1]; a[x][y+1]=b[2]; a[x-2][y+1]=b[3]; break; }  //倒7字顺转180度

  case 19: { a[x-2][y]=b[1]; a[x-2][y-1]=b[2]; a[x+2][y]=b[3]; break; }  //倒7字顺转270度

 }

}

void keyD( )  //按键操作

{ if (kbhit( ))       

   { int key;

     key=getch();

     if (key==224)

       { key=getch();

         if (key==75) { x-=2; }  //按下左方向键,中心横坐标减2

         if (key==77) { x+=2; }  //按下右方向键,中心横坐标加2

        if (key==72)     //按下向上方向键,方块变体

          { if (flag>=2 && flag<=3 ) { flag++; flag%=2; flag+=2; }

           if ( flag>=4 && flag<=7 ) { flag++; flag%=4; flag+=4; }

           if (flag>=8 && flag<=11 ) { flag++; flag%=4; flag+=8; }

           if (flag>=12 && flag<=15 ) { flag++; flag%=4; flag+=12; }

           if ( flag>=16 && flag<=19 ) { flag++; flag%=4; flag+=16; } }

         }

      if (key==32)     //按空格键,暂停

        { prfk( ); while(1) { if (getch( )==32) { clfk( );break;} } }  //再按空格键,继续游戏

      if (ifmov( )==0) { x=Tb; flag=Tc; }   //如果不可动,撤销上面操作

      else { prfk( ); Sleep(speed); clfk( ); Tb=x;Tc=flag;}   //如果可动,执行操作

   }

}

int ifmov( )   //判断能否移动

{ if (a[x][y]!=0) { return 0; }  //方块中心处有图案返回0,不可移动

 else{ if ( (flag==1 && ( a[x][ y-1]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||  

         (flag==2 && ( a[x-2][y]==0 && a[x+2][y]==0 && a[x+4][y]==0 ) ) || 

         (flag==3 && ( a[x][y-1]==0 && a[x][y-2]==0 && a[x][y+1]==0 ) ) ||

         (flag==4 && ( a[x-2][y]==0 && a[x+2][y]==0 && a[x][y+1]==0 ) ) ||

         (flag==5 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x-2][y]==0 ) ) ||

         (flag==6 && ( a[x][ y-1]==0 && a[x-2][y]==0 && a[x+2][y]==0 ) ) ||

         (flag==7 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y]==0 ) ) ||

         (flag==8 && ( a[x][y+1]==0 && a[x-2][y]==0 && a[x+2][y+1]==0 ) ) ||

         (flag==9 && ( a[x][y-1]==0 && a[x-2][y]==0 && a[x-2][y+1]==0 ) ) ||

         (flag==10 && ( a[x][y-1]==0 && a[x-2][y-1]==0 && a[x+2][y]==0 ) ) ||

         (flag==11 && ( a[x][y+1]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||

         (flag==12 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x-2][y-1]==0 ) ) ||

        ( flag==13 && ( a[x-2][y]==0 && a[x+2][y-1]==0 && a[x+2][y]==0 ) ) ||

        ( flag==14 && ( a[x][y-1]==0 && a[x][y+1]==0 && a[x+2][y+1]==0 ) ) ||

        (flag==15 && ( a[x-2][y]==0 && a[x-2][y+1]==0 && a[x+2][y]==0 ) ) ||

        (flag==16 && ( a[x][y+1]==0 && a[x][y-1]==0 && a[x+2][y-1]==0 ) ) ||

        ( flag==17 && ( a[x-2][y]==0 && a[x+2][y+1]==0 && a[x+2][y]==0 ) ) ||

        (flag==18 && ( a[x][y-1]==0 &&a[x][y+1]==0 && a[x-2][y+1]==0 ) ) ||

        (flag==19 && ( a[x-2][y]==0 && a[x-2][y-1]==0

              && a[x+2][y]==0 ) ) ) { return 1; }

    }

  return 0;   //其它情况返回0

}

void clNEXT( )   //清除框外的NEXT方块

{ flag = next;  x=ZL+WID+6;  y=ZL+10;  clfk( ); }

void clHA( )   //清除满行的方块

int k, Hang=0;    //k是某行方块个数, Hang是删除的方块行数

  for(j=ZL+HEI-1;j>=ZL+1;j--)  //当某行有WID/2-2个方块时,则为满行

   { k=0; for(i=ZL+2;i<ZL+WID-2;i+=2)

    { if (a[i][j]==1)   //竖坐标从下往上,横坐标由左至右依次判断是否满行

     { k++;   //下面将操作删除行

       if (k==WID/2-2)  {   for(k=ZL+2;k<ZL+WID-2;k+=2) 

           { a[k][j]=0; gtxy(k,j); printf("  "); Sleep(1); }

          for(k=j-1;k>ZL;k--)

          { for(i=ZL+2;i<ZL+WID-2;i+=2)  //已删行数上面有方块,先清除再全部下移一行

            { if(a[i][k]==1) { a[i][k]=0; gtxy(i,k); printf("  ");a[i][k+1]=1; 

              gtxy(i,k+1); printf("□"); } }

            }

          j++;     //方块下移后,重新判断删除行是否满行

          Hang++;  //记录删除方块的行数

         }

      }

     }

   }

   score+=100*Hang;   //每删除一行,得100分

 if ( Hang>0 && (score%500==0 || score/500> level-1 ) )  //得分满500速度加快升一级

    { speed-=20; level++; if(speed<200)speed+=20; } 

}

热心网友 时间:2023-11-19 19:36

http://tieba.baidu.com/f?kz=1090419809这里有个高手写了一个。

热心网友 时间:2023-11-19 19:37

////////////////////////////////////////////
// 程序名称:俄罗斯方块
// 编译环境:Visual C++ 6.0,EasyX 2011惊蛰版
// 程序编写:krissi <zhaoh1987@qq.com>
// 最后更新:2010-12-18
//
#include <graphics.h>
#include <conio.h>
#include <time.h> /////////////////////////////////////////////
// 定义常量、枚举量、结构体、全局变量
/////////////////////////////////////////////#define WIDTH 10 // 游戏区宽度
#define HEIGHT 22 // 游戏区高度
#define SIZE 20 // 每个游戏区单位的实际像素// 定义操作类型
enum CTRL
{
CTRL_ROTATE, // 方块旋转
CTRL_LEFT, CTRL_RIGHT, CTRL_DOWN, // 方块左、右、下移动
CTRL_SINK, // 方块沉底
CTRL_QUIT // 退出游戏
};// 定义绘制方块的方法
enum DRAW
{
SHOW, // 显示方块
HIDE, // 隐藏方块
FIX // 固定方块
};// 定义七种俄罗斯方块
struct BLOCK
{
WORD dir[4]; // 方块的四个旋转状态
COLORREF color; // 方块的颜色
} g_Blocks[7] = { {0x0F00, 0x4444, 0x0F00, 0x4444, RED}, // I
{0x0660, 0x0660, 0x0660, 0x0660, BLUE}, // 口
{0x4460, 0x02E0, 0x0622, 0x0740, MAGENTA}, // L
{0x2260, 0x0E20, 0x0644, 0x0470, YELLOW}, // 反L
{0x0C60, 0x2640, 0x0C60, 0x2640, CYAN}, // Z
{0x0360, 0x4620, 0x0360, 0x4620, GREEN}, // 反Z
{0x4E00, 0x4C40, 0x0E40, 0x4640, BROWN}}; // T// 定义当前方块、下一个方块的信息
struct BLOCKINFO
{
byte id; // 方块 ID
char x, y; // 方块在游戏区中的坐标
byte dir:2; // 方向
} g_CurBlock, g_NextBlock;// 定义游戏区
BYTE g_World[WIDTH][HEIGHT] = {0}; /////////////////////////////////////////////
// 函数声明
/////////////////////////////////////////////void Init(); // 初始化游戏
void Quit(); // 退出游戏
void NewGame(); // 开始新游戏
void GameOver(); // 结束游戏
CTRL GetControl(bool _onlyresettimer = false); // 获取控制命令
void DispatchControl(CTRL _ctrl); // 分发控制命令
void NewBlock(); // 生成新的方块
bool CheckBlock(BLOCKINFO _block); // 检测指定方块是否可以放下
void DrawBlock(BLOCKINFO _block, DRAW _draw = SHOW); // 画方块
void OnRotate(); // 旋转方块
void OnLeft(); // 左移方块
void OnRight(); // 右移方块
void OnDown(); // 下移方块
void OnSink(); // 沉底方块 /////////////////////////////////////////////
// 函数定义
/////////////////////////////////////////////// 主函数
void main()
{
Init(); CTRL c;
while(true)
{
c = GetControl();
DispatchControl(c); // 按退出时,显示对话框咨询用户是否退出
if (c == CTRL_QUIT)
{
HWND wnd = GetHWnd();
if (MessageBox(wnd, "您要退出游戏吗?", "提醒", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
Quit();
}
}
}
// 初始化游戏
void Init()
{
initgraph(640, 480);
srand((unsigned)time(NULL)); // 显示操作说明
setfont(14, 0, "宋体");
outtextxy(20, 330, "操作说明");
outtextxy(20, 350, "上:旋转");
outtextxy(20, 370, "左:左移");
outtextxy(20, 390, "右:右移");
outtextxy(20, 410, "下:下移");
outtextxy(20, 430, "空格:沉底");
outtextxy(20, 450, "ESC:退出"); // 设置坐标原点
setorigin(220, 20); // 绘制游戏区边界
rectangle(-1, -1, WIDTH * SIZE, HEIGHT * SIZE);
rectangle((WIDTH + 1) * SIZE - 1, -1, (WIDTH + 5) * SIZE, 4 * SIZE); // 开始新游戏
NewGame();
}
// 退出游戏
void Quit()
{
closegraph();
exit(0);
}
// 开始新游戏
void NewGame()
{
// 清空游戏区
setfillstyle(BLACK);
bar(0, 0, WIDTH * SIZE - 1, HEIGHT * SIZE - 1);
ZeroMemory(g_World, WIDTH * HEIGHT); // 生成下一个方块
g_NextBlock.id = rand() % 7;
g_NextBlock.dir = rand() % 4;
g_NextBlock.x = WIDTH + 1;
g_NextBlock.y = HEIGHT - 1; // 获取新方块
NewBlock();
}
// 结束游戏
void GameOver()
{
HWND wnd = GetHWnd();
if (MessageBox(wnd, "游戏结束。\n您想重新来一局吗?", "游戏结束", MB_YESNO | MB_ICONQUESTION) == IDYES)
NewGame();
else
Quit();
}
// 获取控制命令
CTRL GetControl(bool _onlyresettimer)
{
static DWORD oldtime = GetTickCount(); // 重置计时器
if (_onlyresettimer)
{
oldtime = GetTickCount();
return CTRL_DOWN; // 仅仅为了重置计时器,随便返回一个值
} // 获取控制值
while(true)
{
// 如果超时,自动下落一格
DWORD newtime = GetTickCount();
if (newtime - oldtime >= 500)
{
oldtime = newtime;
return CTRL_DOWN;
} // 如果有按键,返回按键对应的功能
if (kbhit())
{
switch(getch())
{
case 'w':
case 'W': return CTRL_ROTATE;
case 'a':
case 'A': return CTRL_LEFT;
case 'd':
case 'D': return CTRL_RIGHT;
case 's':
case 'S': return CTRL_DOWN;
case 27: return CTRL_QUIT;
case ' ': return CTRL_SINK;
case 0:
case 0xE0:
switch(getch())
{
case 72: return CTRL_ROTATE;
case 75: return CTRL_LEFT;
case 77: return CTRL_RIGHT;
case 80: return CTRL_DOWN;
}
}
}
}
}
// 分发控制命令
void DispatchControl(CTRL _ctrl)
{
switch(_ctrl)
{
case CTRL_ROTATE: OnRotate(); break;
case CTRL_LEFT: OnLeft(); break;
case CTRL_RIGHT: OnRight(); break;
case CTRL_DOWN: OnDown(); break;
case CTRL_SINK: OnSink(); break;
case CTRL_QUIT: break;
}
}
// 生成新的方块
void NewBlock()
{
g_CurBlock.id = g_NextBlock.id, g_NextBlock.id = rand() % 7;
g_CurBlock.dir = g_NextBlock.dir, g_NextBlock.dir = rand() % 4;
g_CurBlock.x = (WIDTH - 4) / 2;
g_CurBlock.y = HEIGHT + 2; // 下移新方块直到有局部显示
WORD c = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];
while((c & 0xF) == 0)
{
g_CurBlock.y--;
c >>= 4;
} // 绘制新方块
DrawBlock(g_CurBlock); // 绘制下一个方块
setfillstyle(BLACK);
bar((WIDTH + 1) * SIZE, 0, (WIDTH + 5) * SIZE - 1, 4 * SIZE - 1);
DrawBlock(g_NextBlock);
}
// 画方块
void DrawBlock(BLOCKINFO _block, DRAW _draw)
{
WORD b = g_Blocks[_block.id].dir[_block.dir];
int x, y; int color = BLACK;
switch(_draw)
{
case SHOW: color = g_Blocks[_block.id].color; break;
case HIDE: color = BLACK; break;
case FIX: color = g_Blocks[_block.id].color / 3; break;
}
setfillstyle(color); for(int i=0; i<16; i++)
{
if (b & 0x8000)
{
x = _block.x + i % 4;
y = _block.y - i / 4;
if (y < HEIGHT)
{
if (_draw != HIDE)
bar3d(x * SIZE + 2, (HEIGHT - y - 1) * SIZE + 2, (x + 1) * SIZE - 4, (HEIGHT - y) * SIZE - 4, 3, true);
else
bar(x * SIZE, (HEIGHT - y - 1) * SIZE, (x + 1) * SIZE - 1, (HEIGHT - y) * SIZE - 1);
}
}
b <<= 1;
}
}
// 检测指定方块是否可以放下
bool CheckBlock(BLOCKINFO _block)
{
WORD b = g_Blocks[_block.id].dir[_block.dir];
int x, y; for(int i=0; i<16; i++)
{
if (b & 0x8000)
{
x = _block.x + i % 4;
y = _block.y - i / 4;
if ((x < 0) || (x >= WIDTH) || (y < 0))
return false; if ((y < HEIGHT) && (g_World[x][y]))
return false;
}
b <<= 1;
} return true;
}
// 旋转方块
void OnRotate()
{
// 获取可以旋转的 x 偏移量
int dx;
BLOCKINFO tmp = g_CurBlock;
tmp.dir++; if (CheckBlock(tmp)) { dx = 0; goto rotate; }
tmp.x = g_CurBlock.x - 1; if (CheckBlock(tmp)) { dx = -1; goto rotate; }
tmp.x = g_CurBlock.x + 1; if (CheckBlock(tmp)) { dx = 1; goto rotate; }
tmp.x = g_CurBlock.x - 2; if (CheckBlock(tmp)) { dx = -2; goto rotate; }
tmp.x = g_CurBlock.x + 2; if (CheckBlock(tmp)) { dx = 2; goto rotate; }
return;rotate:
// 旋转
DrawBlock(g_CurBlock, HIDE);
g_CurBlock.dir++;
g_CurBlock.x += dx;
DrawBlock(g_CurBlock);
}
// 左移方块
void OnLeft()
{
BLOCKINFO tmp = g_CurBlock;
tmp.x--;
if (CheckBlock(tmp))
{
DrawBlock(g_CurBlock, HIDE);
g_CurBlock.x--;
DrawBlock(g_CurBlock);
}
}
// 右移方块
void OnRight()
{
BLOCKINFO tmp = g_CurBlock;
tmp.x++;
if (CheckBlock(tmp))
{
DrawBlock(g_CurBlock, HIDE);
g_CurBlock.x++;
DrawBlock(g_CurBlock);
}
}
// 下移方块
void OnDown()
{
BLOCKINFO tmp = g_CurBlock;
tmp.y--;
if (CheckBlock(tmp))
{
DrawBlock(g_CurBlock, HIDE);
g_CurBlock.y--;
DrawBlock(g_CurBlock);
}
else
OnSink(); // 不可下移时,执行“沉底方块”操作
}
// 沉底方块
void OnSink()
{
int i, x, y; // 连续下移方块
DrawBlock(g_CurBlock, HIDE);
BLOCKINFO tmp = g_CurBlock;
tmp.y--;
while (CheckBlock(tmp))
{
g_CurBlock.y--;
tmp.y--;
}
DrawBlock(g_CurBlock, FIX); // 固定方块在游戏区
WORD b = g_Blocks[g_CurBlock.id].dir[g_CurBlock.dir];
for(i = 0; i < 16; i++)
{
if (b & 0x8000)
{
if (g_CurBlock.y - i / 4 >= HEIGHT)
{ // 如果方块的固定位置超出高度,结束游戏
GameOver();
return;
}
else
g_World[g_CurBlock.x + i % 4][g_CurBlock.y - i / 4] = 1;
} b <<= 1;
} // 检查是否需要消掉行,并标记
int row[4] = {0};
bool bRow = false;
for(y = g_CurBlock.y; y >= max(g_CurBlock.y - 3, 0); y--)
{
i = 0;
for(x = 0; x < WIDTH; x++)
if (g_World[x][y] == 1)
i++;
if (i == WIDTH)
{
bRow = true;
row[g_CurBlock.y - y] = 1;
setfillstyle(WHITE, DIAGCROSS2_FILL);
bar(0, (HEIGHT - y - 1) * SIZE + SIZE / 2 - 2, WIDTH * SIZE - 1, (HEIGHT - y - 1) * SIZE + SIZE / 2 + 2);
}
} if (bRow)
{
// 延时 200 毫秒
Sleep(200); // 擦掉刚才标记的行
IMAGE img;
for(i = 0; i < 4; i++)
{
if (row[i])
{
for(y = g_CurBlock.y - i + 1; y < HEIGHT; y++)
for(x = 0; x < WIDTH; x++)
{
g_World[x][y - 1] = g_World[x][y];
g_World[x][y] = 0;
} getimage(&img, 0, 0, WIDTH * SIZE, (HEIGHT - (g_CurBlock.y - i + 1)) * SIZE);
putimage(0, SIZE, &img);
}
}
} // 产生新方块
NewBlock(); // 重新计算延时
GetControl(true);
}
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
在RLC电路中,谐振频率为___同期为___谐振条件为___? 电磁振荡并联 RLC振荡回路的谐振频率与振荡特性 佛手柑水培还是干放 中山市美派电器有限公司怎么样? 成都美派电器有限公司怎么样? 两条不同品牌的DDR3内存条可以一起用吗 驾驶证的牡丹卡多长时间能办下来 新衣服必须用洗衣液洗才能去甲醛吗? 梦见逛街被偷抢 2024年买什么品牌的运动男鞋比较好? 97南航5.8空难的幸存者忆914 域名备案成功了,现在想转备案怎么操作?2 请问哪个航空公司的服务更好一点,飞机更舒适88 c语言编一个俄罗斯方块(*.c)(不要复制的) 网站想转移备案怎么弄? 我是一个高三的学生`我很喜欢空姐这个职业`请问`当空姐高考要... 客机着陆时在地上蹦了几下是怎么回事?有没有安全问题?前几天坐...12 那个航空公司最好最安全15 计算机系统由哪几部分组成?简述各组成部分的基本功能。75 移动通信系统由哪几部分组成?39 汽车底盘由哪四大系统组成?各有什么作用?47 招行e招贷贷款4万,随借随还万4利率,分期还款1年3600利息... 相亲微信幽默打招呼方式有哪些?相亲平台上加了女生微信后怎么聊?_百 ... 一至十的繁体字怎么写599 数的繁体字怎么写?37 等字的繁体字怎么写1 如何查看网站日志文件如何查看网站日志文件内容 邮政管理局与物流局的区别 河北义和庄到北京北藏村坐什么车 济南泺源大街打车到义和庄多少钱3 新域名怎么转入备案,原来已有一个域名备案过。3 Java编写的俄罗斯方块的全套教学视频谁有呢2 一个简单的c语言写的俄罗斯方块程序?3 我注册了一个域名 想备案,该如何提交备案,都需要什么材料?谢...1 域名备案过了,现在想备案到另一家公司,要怎么操作? 如何用mfc编写俄罗斯方块游戏,求详细解决过程!!! 域名备案过了,怎么重新备案到另一家公司呢? 求一个简单的c语言写的俄罗斯方块程序26 如果你是一个小导游,打算怎样向游客介绍南京呢?请设计一段解说...1128 曼联的青训营叫什麼?2 假如你是一名导游你会怎样向游客们介绍你的家乡请将你的介绍写下...215 曼联队的小将罗西是左脚吗?他是曼联青训营培养出来的吗? 如果你是导游,你怎样介绍南京?6 能说一下曼联青训营的历史及成员吗 假如你是一名导游你该如何把这些石头介绍给游客请写一篇解说词2 曼联的中场究竟要买谁呢?还是说,就我们自己选青训营里的啊? 历史上曼联球星49 请问荷兰是不是有个左后卫在曼联?叫什么名字? 徐州话咋说109 徐州话怎么说5