C语言如何实现俄罗斯方块
作者
这篇文章将为大家详细讲解有关C语言如何实现俄罗斯方块,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
本文实例为大家分享了C语言实现俄罗斯方块的具体代码,供大家参考,具体内容如下
Head.h
#ifndef_HEAD_H_ #define_HEAD_H_ #include<graphics.h> #include<stdio.h> #include<conio.h> #include<stdlib.h> #include<time.h> #include<string.h> #define_CRT_SECURE_NO_WARNINGS1 //界面的相关的参数 #defineWALL_SQUARE_WIDTH10//围墙方块的宽度 #definexWALL_SQUARE_NUM30//x轴方向的方块的数目 #defineyWALL_SQUARE_WIDTH46//y轴方向的方块的数目 #defineGAME_WALL_WIDTH(WALL_SQUARE_WIDTH*xWALL_SQUARE_NUM)//游戏区域的宽度300 #defineGAME_WALL_HTGH(WALL_SQUARE_WIDTH*yWALL_SQUARE_WIDTH)//游戏区域的高度460 #defineWINDOW_WIDTH480//游戏总窗口宽度480 #defineWINDOW_HIGH460//游戏总窗口高度460 //定义俄罗斯方块的相关参数 #defineROCK_SQUARE_WIDTH(2*WALL_SQUARE_WIDTH)//俄罗斯方块的大小是围墙的两倍20 #definexROCK_SQUARE_NUM((GAME_WALL_WIDTH-20)/ROCK_SQUARE_WIDTH)//游戏区x轴放的方块数目:14 #defineyROCK_SQUARE_NUM((GAME_WALL_HTGH-20)/ROCK_SQUARE_WIDTH)//游戏区y轴放的方块数目:22 //定义移动方块的相关操作 #defineDIRECT_UP3 #defineDIRECT_DOWN2 #defineDIRECT_LEFT-1 #defineDIRECT_RIGHT1 /*数据结构-线性表(结构体数组)*/ typedefstructROCK { //用来表示方块的形状(每一个字节是8位,用每4位表示方块中的一行) unsignedshortrockShapeBits; intnextRockIndex;//下一个方块,在数组中的下标 }RockType; //方块在图形窗口中的位置(即定位4*4大块的左上角坐标) typedefstructLOCATE { intleft; inttop; }RockLocation_t; //全局变量-游戏板的状态描述(即表示当前界面哪些位置有方块) //0表示没有,1表示有(多加了两行和两列,形成一个围墙,便于判断方块是否能够移动) intgame_board[yROCK_SQUARE_NUM+2][xROCK_SQUARE_NUM+2]={0}; intgame_socres=0;//全局分数 //把俄罗斯方块的19种类放到数组中 introckTypeNum=19; RockTypeRockArray[19]={(0,0)}; //预览区的方块的位置 RockLocation_tpreRockLocation={GAME_WALL_WIDTH+70,70}; //每次生成初始化方块的位置 RockLocation_tinitRockLocation={(WALL_SQUARE_WIDTH+100),WALL_SQUARE_WIDTH}; //分数显示的位置 //各个文件中的函数 //画出界面以及画出方块Draw.h中 voidDrawGameWindow(); voidDisplayRock(introckIdx,RockLocation_t*LocatePtr,booldisplayed); //初始化Init源文件 voidInitGame(); //game.h voidPlayGame(); boolIsGameOver(); #endif
Draw.h
#include"Head.h" //画出游戏界面 voidDrawGameWindow() { //先画出围墙 setcolor(BLUE); setlinestyle(PS_SOLID,NULL,0); setfillcolor(BLUE); //画出上下围墙 for(intx=WALL_SQUARE_WIDTH;x<=GAME_WALL_WIDTH;x+=WALL_SQUARE_WIDTH) { fillrectangle(x-WALL_SQUARE_WIDTH,0,x,WALL_SQUARE_WIDTH);//上 fillrectangle(x-WALL_SQUARE_WIDTH,GAME_WALL_HTGH-WALL_SQUARE_WIDTH,x,GAME_WALL_HTGH);//下 } //画出左右围墙 for(inty=WALL_SQUARE_WIDTH;y<=GAME_WALL_HTGH;y+=WALL_SQUARE_WIDTH) { fillrectangle(0,y,WALL_SQUARE_WIDTH,y+WALL_SQUARE_WIDTH);//左 fillrectangle(GAME_WALL_WIDTH-WALL_SQUARE_WIDTH,y,GAME_WALL_WIDTH,y+WALL_SQUARE_WIDTH);//右 } //画出右边统计分数及相关东西 //画出分割线 setcolor(WHITE); setlinestyle(PS_DASH,2); line(GAME_WALL_WIDTH+20,0,GAME_WALL_WIDTH+20,GAME_WALL_HTGH); //设置字体 LOGFONTfont; gettextstyle(&font); settextstyle(18,0,_T("宋体")); font.lfQuality=ANTIALIASED_QUALITY;//设置输出效果为抗锯齿 //1显示预览形状 outtextxy(GAME_WALL_WIDTH+80,30,_T("预览")); outtextxy(GAME_WALL_WIDTH+80,170,_T("分数")); outtextxy(GAME_WALL_WIDTH+65,250,_T("操作说明")); outtextxy(GAME_WALL_WIDTH+40,290,_T("wasd控制方向")); outtextxy(GAME_WALL_WIDTH+40,335,_T("空格暂停")); //显示分数 setcolor(RED); outtextxy(GAME_WALL_WIDTH+90,200,'0'); } //在游戏区显示编号为rockIdx的方块 voidDisplayRock(introckIdx,RockLocation_t*LocatePtr,booldisplayed) { intcolor;//方块的填充颜色 intlineColor=WHITE;//线的颜色 intboardFalg=0; intxRock=0; intyRock=0; unsignedshortrockCode=RockArray[rockIdx].rockShapeBits; //如果displayed为true的话,将方块块颜色设置为white,game_board对应的位置设置为1; //如果displayed为false的话,将方块块颜色设置为black,game_board对应的位置设置为0; displayed?(color=RED,boardFalg=1):(color=BLACK,lineColor=BLACK,boardFalg=0); setcolor(lineColor); setfillcolor(color); setlinestyle(PS_SOLID);//设置为实线, xRock=LocatePtr->left; yRock=LocatePtr->top; intcount=0;//每4个换行,记录坐标偏移量 unsignedshortmask=1; for(inti=1;i<=16;++i) { mask=1<<(16-i); if((rockCode&mask)!=0)//如果不为0的话,就画出小方块 { fillrectangle(xRock,yRock,xRock+ROCK_SQUARE_WIDTH,yRock+ROCK_SQUARE_WIDTH); } if(i%4==0)//换行 { yRock=yRock+ROCK_SQUARE_WIDTH; xRock=xRock=LocatePtr->left; } else { xRock+=ROCK_SQUARE_WIDTH; } } }
Init.h
#include"Head.h" staticvoidShapeStrToBit(unsignedchar*rockShapeStr,unsignedshort&rockShapeBit); staticvoidReadRcok(); voidInitGame() { //把全局游戏游戏版初始化,边界初始化为1 for(inti=0;i<xROCK_SQUARE_NUM+2;i++) { game_board[0][i]=1;//上边界 game_board[yROCK_SQUARE_NUM+1][i]=1;//下边界 } for(inti=0;i<yROCK_SQUARE_NUM+2;i++) { game_board[i][0]=1;//左边界 game_board[i][xROCK_SQUARE_NUM+1]=1;//右边界 } //读取俄罗斯方块 ReadRcok(); } //从文件中读取方块的形状存储到rockArray中 voidReadRcok() { FILE*fp=fopen("RockShape.ini","r"); if(NULL==fp) { printf("打开文件失败\n"); return; } unsignedcharreadBuf[1024];//fp读取到字符串readbuf中 unsignedshortrockShapeBit=0;//存放方块形状,占16比特位 unsignedcharrockShapeStr[16];//存放方块字符串 intShapeStrIdx=0; introckNum=0;//统计方块的个数以及存放方块数组RockArray的下标 introcknext=0;//方块数组中下一个形状 introckShapeStart=0;//同一类型的形状 while(true) { size_treadSize=fread(readBuf,1,1024,fp); if(readSize==0) break; //处理readbuf for(size_tidx=0;idx<readSize;++idx) { //将字符存放到rockShapeStr中 while(ShapeStrIdx<16&&idx<readSize) { if(readBuf[idx]=='@'||readBuf[idx]=='#') { rockShapeStr[ShapeStrIdx]=(unsignedchar)readBuf[idx]; ++ShapeStrIdx; } ++idx;//可能idx==readSize了 if(readBuf[idx]=='*')//修改上一次方块的next值 { idx+=5; RockArray[--rockNum].nextRockIndex=rockShapeStart; rockNum++; rockShapeStart=rockNum; rocknext=rockShapeStart; } } //可能没有填满 if(ShapeStrIdx<16) { break; } else//填满shapestr { ShapeStrIdx=0;//置0 //将rockShapeStr转为rockShapeBit ShapeStrToBit(rockShapeStr,rockShapeBit); rocknext++; RockArray[rockNum].rockShapeBits=rockShapeBit; RockArray[rockNum].nextRockIndex=rocknext; rockNum++; } } } fclose(fp); } //将从文件中读取的字符串(长度默认为16)转换成unsignedshort voidShapeStrToBit(unsignedchar*rockShapeStr,unsignedshort&rockShapeBit) { rockShapeBit=0; for(size_tidx=0;idx<16;++idx) { if(rockShapeStr[idx]=='@')//1 { rockShapeBit|=(1<<(16-idx-1)); } //#为0不需要处理 } }
game.h
#include"Head.h" #define_CRT_SECURE_NO_WARNINGS1 boolMoveAble(introckIndex,RockLocation_t*currentLocatePtr,intf_direction); voidSetGameBoardFlag(introckIdx,RockLocation_t*curRockLocation); voidUserHitKeyBoard(charuserHit,int*RockIndex,RockLocation_t*curRockLocation); voidFullLine(); voidUpdateSocres(intscores); voidDelCurLine(introwIdx); boolIsGameOver(); voidPlayGame() { charuserHit=0;//用户敲击键盘 intcurRockIndex=0;//当前方块的rockArray下标 intnextRockIndex=0;//下次 RockLocation_tcurRockLocation; curRockLocation.left=initRockLocation.left; curRockLocation.top=initRockLocation.top; DWORDoldtime=0; srand((unsignedint)time(NULL)); curRockIndex=rand()%rockTypeNum; nextRockIndex=rand()%rockTypeNum; //画出预览区初始化方块 //在初始位置和预览区显示方块形状 DisplayRock(curRockIndex,&initRockLocation,1); DisplayRock(nextRockIndex,&preRockLocation,1); boolmoveAbled=false; while(true) { //判断当前方块是否落地(判断能否再下移):如果落地,判断是否满行,再判断是否结束游戏,改变game_board,画出下次初始化的方块,以及生成新的预览方块 // moveAbled=MoveAble(curRockIndex,&curRockLocation,DIRECT_DOWN); if(!moveAbled)//判断是否落地,不能下移表示落地 { //修改game_board的值 SetGameBoardFlag(curRockIndex,&curRockLocation); FullLine(); if(IsGameOver()) { MessageBox(NULL,_T("游戏结束"),_T("GAMEOVER"),MB_OK); exit(0); } //为下次生成模块开始准备 DisplayRock(nextRockIndex,&preRockLocation,false);//擦除旧的方块 curRockIndex=nextRockIndex; nextRockIndex=rand()%rockTypeNum;//生成新的预览方块 DisplayRock(curRockIndex,&initRockLocation,1); DisplayRock(nextRockIndex,&preRockLocation,1); FlushBatchDraw(); //修改curRockLocation的值 curRockLocation.left=initRockLocation.left; curRockLocation.top=initRockLocation.top; } if(kbhit())//如果敲击键盘了就处理按键 { userHit=getch(); UserHitKeyBoard(userHit,&curRockIndex,&curRockLocation); } //没有就自动下移一个单位:不能用else,因为可能按键不是上下左右 DWORDnewtime=GetTickCount(); if(newtime-oldtime>=(unsignedint)(300)&&moveAbled==TRUE) { oldtime=newtime; DisplayRock(curRockIndex,&curRockLocation,false); curRockLocation.top+=ROCK_SQUARE_WIDTH;//下落一格 } //AutomaticDownMove(curRockIndex,&curRockLocation); //画出新方块 DisplayRock(curRockIndex,&curRockLocation,1); FlushBatchDraw(); Sleep(20); } } //响应键盘命令时间 voidUserHitKeyBoard(charuserHit,int*RockIndex,RockLocation_t*curRockLocation) { switch(userHit) { case'W': case'w'://↑ if(MoveAble(RockArray[*RockIndex].nextRockIndex,curRockLocation,DIRECT_UP)) { DisplayRock(*RockIndex,curRockLocation,false); *RockIndex=RockArray[*RockIndex].nextRockIndex; } break; case'S': case's'://↓ if(MoveAble(*RockIndex,curRockLocation,DIRECT_DOWN)) { DisplayRock(*RockIndex,curRockLocation,false); curRockLocation->top+=2*(ROCK_SQUARE_WIDTH); if(!MoveAble(*RockIndex,curRockLocation,DIRECT_DOWN)) { curRockLocation->top-=ROCK_SQUARE_WIDTH; } } break; case'A': case'a'://← if(MoveAble(*RockIndex,curRockLocation,DIRECT_LEFT)) { DisplayRock(*RockIndex,curRockLocation,false); curRockLocation->left-=ROCK_SQUARE_WIDTH; } break; case'D': case'd'://→ if(MoveAble(*RockIndex,curRockLocation,DIRECT_RIGHT)) { DisplayRock(*RockIndex,curRockLocation,FALSE); curRockLocation->left+=ROCK_SQUARE_WIDTH; } break; case''://暂停 while(1) { userHit=getch(); if(userHit=='') break; } break; default: break; } } //判断是否满行,满行消除,然后计算得分 voidFullLine() { boollinefull=true; intidx=yROCK_SQUARE_NUM;//从最后一行往上查找22 intcount=0; while(count!=xROCK_SQUARE_NUM)//遇到空行14 { linefull=true; count=0; for(inti=1;i<=xROCK_SQUARE_NUM;++i) { if(game_board[idx][i]==0) { linefull=false; count++; } } if(linefull)//满行,消除当前行,更新分数 { DelCurLine(idx); game_socres+=3; UpdateSocres(game_socres); idx++;//因为下面要减1 } idx--; } } voidUpdateSocres(intscores) { setcolor(RED); TCHARs[10]; _stprintf(s,_T("%d"),scores); outtextxy(GAME_WALL_WIDTH+90,200,s); } //消除当前行 voidDelCurLine(introwIdx) { //擦除当前行 setcolor(BLACK); setfillcolor(BLACK); for(inti=1;i<xROCK_SQUARE_NUM;++i) { fillrectangle(WALL_SQUARE_WIDTH+(i-1)*ROCK_SQUARE_WIDTH,(rowIdx-1)*ROCK_SQUARE_WIDTH+WALL_SQUARE_WIDTH, WALL_SQUARE_WIDTH+i*ROCK_SQUARE_WIDTH,rowIdx*ROCK_SQUARE_WIDTH+WALL_SQUARE_WIDTH); } //把上面的向下移 intcnt=0; while(cnt!=xROCK_SQUARE_NUM)//直到遇到是空行的为止 { cnt=0; for(inti=1;i<=xROCK_SQUARE_NUM;i++) { game_board[rowIdx][i]=game_board[rowIdx-1][i]; //擦除上面的一行 setcolor(BLACK); setfillcolor(BLACK); fillrectangle(WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-ROCK_SQUARE_WIDTH, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*(rowIdx-1)-ROCK_SQUARE_WIDTH, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*(rowIdx-1)); //显示下面的一行 if(game_board[rowIdx][i]==1) { setcolor(WHITE); setfillcolor(RED); fillrectangle(WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-ROCK_SQUARE_WIDTH, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx-ROCK_SQUARE_WIDTH, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i, WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx); } if(game_board[rowIdx][i]==0) cnt++;//统计一行是不是都是空格 }//for rowIdx--; } } //是否可以移动方块 boolMoveAble(introckIndex,RockLocation_t*currentLocatePtr,intf_direction) { intmask; introckX; introckY; rockX=currentLocatePtr->left; rockY=currentLocatePtr->top; mask=(unsignedshort)1<<15; for(inti=1;i<=16;i++) { //与掩码相与为1的即为方块上的点 if((RockArray[rockIndex].rockShapeBits&mask)!=0) { //判断能否移动(即扫描即将移动的位置是否与设置的围墙有重叠) //若是向上(即翻滚变形) if(f_direction==DIRECT_UP) { //因为此情况下传入的是下一个方块的形状,故我们直接判断此方块的位置是否已经被占 //判断下一个方块 if(game_board[(rockY-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] [(rockX-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]==1) returnfalse; } //如果是向下方向移动 elseif(f_direction==DIRECT_DOWN) { if(game_board[(rockY-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+2] [(rockX-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]==1) returnfalse; } else//如果是左右方向移动 {//f_direction的DIRECT_LEFT为-1,DIRECT_RIGHT为1,故直接加f_direction即可判断。 if(game_board[(rockY-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] [(rockX-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1+f_direction]==1) returnfalse; } } //每4次换行转到下一行继续 i%4==0?(rockY+=ROCK_SQUARE_WIDTH,rockX=currentLocatePtr->left) :rockX+=ROCK_SQUARE_WIDTH; mask>>=1; } returntrue; } //给游戏game_board设置标记表示已经占了 voidSetGameBoardFlag(introckIdx,RockLocation_t*curRockLocation) { intmask; introckX; introckY; rockX=curRockLocation->left; rockY=curRockLocation->top; mask=(unsignedint)1<<15; for(inti=1;i<=16;i++) { //与掩码相与为1的即为方块上的点 if((RockArray[rockIdx].rockShapeBits&mask)!=0) { game_board[(rockY-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] [(rockX-WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]=1; } //每4次换行转到下一行继续画 i%4==0?(rockY+=ROCK_SQUARE_WIDTH,rockX=curRockLocation->left) :rockX+=ROCK_SQUARE_WIDTH; mask>>=1; } } //判断游戏是否结束 boolIsGameOver() { booltopLineHaveRock=false;//顶行是否有方块 boolbottomLineHaveRock=false; for(inti=1;i<xROCK_SQUARE_NUM;++i) { if(game_board[1][i]==1) topLineHaveRock=true; if(game_board[yROCK_SQUARE_NUM][i]==1) bottomLineHaveRock=true; } if(bottomLineHaveRock&&topLineHaveRock) returntrue; else returnfalse; }
main.cpp
#include"Head.h" #include"Draw.h" #include"Init.h" #include"game.h" intmain() { initgraph(WINDOW_WIDTH,WINDOW_HIGH); DrawGameWindow(); //使用API函数修改窗口名称 HWNDhWnd=GetHWnd(); SetWindowText(hWnd,_T("俄罗斯方块")); InitGame(); PlayGame(); getchar(); closegraph(); system("pause"); return0; }
配置文件:RockShape.ini
@### @### @@## #### @@@# @### #### #### @@## #@## #@## #### ##@# @@@# #### #### **** #@## #@## @@## #### @### @@@# #### #### @@## @### @### #### @@@# ##@# #### #### **** #@## @@@# #### #### @### @@## @### #### @@@# #@## #### #### #@## @@## #@## #### **** #@## @@## @### #### @@## #@@# #### #### **** @### @@## #@## #### #@@# @@## #### #### **** @### @### @### @### @@@@ #### #### #### **** @@## @@## #### #### ****
关于“C语言如何实现俄罗斯方块”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
目录
推荐阅读
0 条评论
本站已关闭游客评论,请登录或者注册后再评论吧~