C语言如何实现俄罗斯方块

这篇文章将为大家详细讲解有关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语言如何实现俄罗斯方块”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

发布于 2021-05-30 14:07:23
收藏
分享
海报
0 条评论
171
上一篇:C语言如何实现linux网卡检测精简版 下一篇:2048小游戏怎么使用C语言实现
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码