程序代码:
#include<windows.h>
#include<time.h>
#include<stdlib.h>
#define W 14 //游戏区域宽度
#define H 26 //游戏区域高度
#define W1 6 //右边状态栏宽度
#define BSIZE 25 //游戏方格边长
#define Y1 6 //放置照片的纵坐标
#define Y2 11 //分数显示栏顶端纵坐标
#define Y3 14 //等级显示栏顶端纵坐标
#define Y4 17 //帮助栏顶端纵坐标
#define Cur_x W/2-1 //游戏方块初始状态左上角横坐标
#define Cur_y 1 //初始状态左上角纵坐标
#define BgColor RGB(0xF5,0xF5,0xDC) //米色
#define FgColor RGB(255,153,204) //淡红色
#define RED RGB(255,0,0)
#define ORANGE RGB(250,128,10)
#define YELLOW RGB(255,255,0)
#define GREEN RGB(0,255,0)
#define CYAN RGB(0,255,255)
#define LIGHT_BLUE RGB(0xA6,0xCA,0xF0) //天蓝色
#define PURPLE RGB(255,0,255)
#define PINK RGB(233,45,143)
#define BLUE RGB(79,195,242)
#define DARKGREEN RGB(0,94,9)
#define GRAY RGB(60,60,60)
#define LIGHTGREEN RGB(114,249,184)
#define MAX_BOX 30
#define MS_NEWBLOCK WM_USER+1 // 消息ID,产生新的【方块】
int score=0,level=0,level_step=100; //分数等级以及每等级所需分数的定义及初始化
int top=H-1; //最顶端的纵坐标
int x,y; //方块当前位置的横坐标及纵坐标
int cur_boxnum,next_boxnum; //cur_boxnum是当前方块编号,next_boxnum是下一个方块编号
int flag_fullrow=0;
int Pause=0;
struct BOARD
{
int var; //状态,1代表已被占用,0代表未被占用
int color; //颜色
}board[H][W]; //定义游戏主板,H行N列
struct BLOCK
{
int a[8][2]; //定义方块形状的数组
int color; //方块颜色
int next; //下一个方块的号码
};
struct BLOCK block[MAX_BOX]=
{ //初始化各个游戏方块
{{1,1,1,2,1,3,2,3,-1,-1},RED,1},
{{0,2,1,2,2,2,0,3,-1,-1},RED,2},
{{0,1,1,1,1,2,1,3,-1,-1},RED,3},
{{2,1,0,2,1,2,2,2,-1,-1},RED,0},
{{1,1,1,2,0,3,1,3,-1,-1},ORANGE,5},
{{0,1,0,2,1,2,2,2,-1,-1},ORANGE,6},
{{1,1,2,1,1,2,1,3,-1,-1},ORANGE,7},
{{0,2,1,2,2,2,2,3,-1,-1},ORANGE,4},
{{1,1,0,2,1,2,2,2,-1,-1},LIGHT_BLUE,9},
{{1,1,1,2,2,2,1,3,-1,-1},LIGHT_BLUE,10},
{{0,2,1,2,2,2,1,3,-1,-1},LIGHT_BLUE,11},
{{1,1,0,2,1,2,1,3,-1,-1},LIGHT_BLUE,8},
{{1,1,1,2,2,2,2,3,-1,-1},GREEN,13},
{{1,2,2,2,0,3,1,3,-1,-1},GREEN,12},
{{2,1,1,2,2,2,1,3,-1,-1},CYAN,15},
{{0,2,1,2,1,3,2,3,-1,-1},CYAN,14},
{{1,0,1,1,1,2,1,3,-1,-1},PURPLE,17},
{{0,2,1,2,2,2,3,2,-1,-1},PURPLE,16},
{{1,1,2,1,1,2,2,2,-1,-1},YELLOW,18},
{{0,1,2,1,0,2,1,2,2,2,-1,-1},PINK,20},
{{1,1,2,1,1,2,1,3,2,3,-1,-1},PINK,21},
{{0,2,1,2,2,2,0,3,2,3,-1,-1},PINK,22},
{{0,1,1,1,1,2,0,3,1,3,-1,-1},PINK,19},
{{0,1,1,1,1,2,1,3,2,3,-1,-1},BLUE,24},
{{2,1,0,2,1,2,2,2,0,3,-1,-1},BLUE,23},
{{1,1,2,1,1,2,0,3,1,3,-1,-1},DARKGREEN,26},
{{0,1,0,2,1,2,2,2,2,3,-1,-1},DARKGREEN,25},
{{1,1,0,2,2,2,1,3,-1,-1},LIGHTGREEN,27},
{{0,0,3,0,1,1,2,1,1,2,2,2,0,3,3,3},GRAY,28},
{{0,0,3,0,1,1,2,1,1,2,2,2,0,3,3,3},GRAY,29},//炸弹方块
};
void Paint(HDC hdc,HPEN hpen) //此函数用于初始化界面
{
int i,j;
HPEN hpen1; //定义画笔,用于绘制分隔线
HBRUSH hbrush=GetStockObject(NULL_BRUSH); //定义画刷并赋初值,画刷颜色采用背景色
hpen1=CreatePen(PS_DASHDOTDOT,3,FgColor); //给画笔赋初值,颜色为前景色,线宽为3,双点划线
SelectObject(hdc,hpen1); //选择画笔
MoveToEx(hdc,W*BSIZE,0,NULL); //将光标移动到(W*BSIZE,0)处
LineTo(hdc,W*BSIZE,H*BSIZE); //从光标所在位置画线到(W*BSIZE,H*BSIZE)处
DeleteObject(hpen1); //删除之前所选用的画笔
SelectObject(hdc,hpen); //重新选择画笔
SelectObject(hdc,hbrush); //选择画刷
for(i=1;i<H-1;i++) //绘制游戏区域方格线
for(j=1;j<W-1;j++)
Rectangle(hdc,j*BSIZE,i*BSIZE,(j+1)*BSIZE,(i+1)*BSIZE);
for(i=1;i<5;i++) //绘制右边状态栏游戏预览区域方格线
for(j=W+1;j<W+W1-1;j++)
Rectangle(hdc,j*BSIZE,i*BSIZE,(j+1)*BSIZE,(i+1)*BSIZE);
Rectangle(hdc,(W+1)*BSIZE,Y2*BSIZE,(W+W1-1)*BSIZE,(Y2+2)*BSIZE); //绘制分数栏方格线
Rectangle(hdc,(W+1)*BSIZE,Y3*BSIZE,(W+W1-1)*BSIZE,(Y3+2)*BSIZE); //绘制等级栏方格线
Rectangle(hdc,(W+1)*BSIZE,Y4*BSIZE,(W+W1-1)*BSIZE,(Y4+5)*BSIZE); //绘制帮助栏方格线
TextOut(hdc,(W+2)*BSIZE,(Y2+0.2)*BSIZE,"分 数",8); //输出文字
TextOut(hdc,(W+2)*BSIZE,(Y3+0.2)*BSIZE,"等 级",8); //同上
TextOut(hdc,(W+1)*BSIZE,(H-3)*BSIZE,"制作人:袁峰",strlen("制作人:袁峰"));
TextOut(hdc,(W+1)*BSIZE,(H-2)*BSIZE,"QQ:775141406",strlen("QQ:775141406"));
DeleteObject(hpen); //删除画笔
DeleteObject(hbrush); //删除画刷
}
void ShowScore(HDC hdc) //显示分数的函数
{
char score_str[5]; //定义字符串用于保存分数值
SetBkColor(hdc,BgColor);
wsprintf(score_str,"%4d",score); //将数字score转换成字符串后保存到score_str之中
TextOut(hdc,(W+2.2)*BSIZE,(Y2+1.2)*BSIZE,score_str,4); //在游戏板上显示分数
}
void ShowLevel(HDC hdc) //显示等级的,具体同上
{
char level_str[3];
SetBkColor(hdc,BgColor);
wsprintf(level_str,"%2d",level);
TextOut(hdc,(W+2.7)*BSIZE,(Y3+1.2)*BSIZE,level_str,2);
}
void ShowHelp(HDC hdc) //显示帮助的,该函数只在初始化界面时调用
{
char help1[]="↑ - 旋转",
help2[]="↓ - 下移",
help3[]="← - 左移",
help4[]="→ - 右移",
help5[]="空格-暂停";
TextOut(hdc,(W+1.8)*BSIZE,(Y4+0.2)*BSIZE,help1,9);
TextOut(hdc,(W+1.8)*BSIZE,(Y4+1.2)*BSIZE,help2,9);
TextOut(hdc,(W+1.8)*BSIZE,(Y4+2.2)*BSIZE,help3,9);
TextOut(hdc,(W+1.8)*BSIZE,(Y4+3.2)*BSIZE,help4,9);
TextOut(hdc,(W+1.8)*BSIZE,(Y4+4.2)*BSIZE,help5,9);
}
void EraseBox(HDC hdc,int x,int y,int num) //清除(x,y)处编号为num,的方块
{
int i;
HPEN hpen=CreatePen(PS_SOLID,1,FgColor);
HBRUSH hbrush=CreateSolidBrush(BgColor);
SelectObject(hdc,hpen);
SelectObject(hdc,hbrush);
for(i=0;i<8;i++) //用背景色填充方块所在区域,使方块隐藏
{
if(block[num].a[i][0]<0) break;
Rectangle(hdc,(x+block[num].a[i][0])*BSIZE,(y+block[num].a[i][1])*BSIZE,
(x+block[num].a[i][0]+1)*BSIZE,(y+block[num].a[i][1]+1)*BSIZE);
}
DeleteObject(hpen);
DeleteObject(hbrush);
}
void ShowBox(HDC hdc,int x,int y,int num) //显示(x,y)处编号为num,的方块
{
int i;
HPEN hpen=CreatePen(PS_SOLID,1,FgColor);
HBRUSH hbrush=CreateSolidBrush(block[num].color); //创建画刷,颜色和方块颜色相同
SelectObject(hdc,hpen);
SelectObject(hdc,hbrush);
for(i=0;i<8;i++) //显示方块的过程
{
if(block[num].a[i][0]<0) break;
Rectangle(hdc,(x+block[num].a[i][0])*BSIZE,(y+block[num].a[i][1])*BSIZE,
(x+block[num].a[i][0]+1)*BSIZE,(y+block[num].a[i][1]+1)*BSIZE);
}
DeleteObject(hpen);
DeleteObject(hbrush);
}
void RePaint(HDC hdc,HPEN hpen,int org_top)
{
int i,j;
HBRUSH hbrush;
SelectObject(hdc,hpen);
if(flag_fullrow) //如果有满行,则重绘主板
{
for(i=org_top;i<y+4;i++) //原来的最顶端
{
if(i<=0||i>=H-1) continue; //越界了,就跳出本次循环
for(j=1;j<W-1;j++)
{ //注意这里绘制主板时,每次都要选择不同的画刷,用完后一定要删除
hbrush=CreateSolidBrush(board[i][j].color);
SelectObject(hdc,hbrush);
Rectangle(hdc,j*BSIZE,i*BSIZE,(j+1)*BSIZE,(i+1)*BSIZE);
DeleteObject(hbrush);
}
}
flag_fullrow=0;
}
else if(cur_boxnum==MAX_BOX-1||cur_boxnum==MAX_BOX-2)
{
hbrush=CreateSolidBrush(BgColor);
SelectObject(hdc,hbrush);
for(i=y-2;i<y+6;i++)
{
if(i<=0||i>=H-1) continue;
for(j=x-2;j<x+6;j++)
{
if(j<=0||j>=W-1) continue;
Rectangle(hdc,j*BSIZE,i*BSIZE,(j+1)*BSIZE,(i+1)*BSIZE);
}
}
DeleteObject(hbrush);
}
DeleteObject(hpen);
}
void SetFullRow(HDC hdc,HPEN hpen) //满行处理函数,重置游戏板状态并重绘主板
{
int i,ii,j;
int k=0;
int org_top=top;
if(cur_boxnum!=MAX_BOX-1&&cur_boxnum!=MAX_BOX-2) //如果不是炸弹方块,则执行以下过程
{
for(i=y;i<y+4;i++) //从y行开始,从上到下遍历游戏区域
{
if(i<=0||i>=H-1) continue; //越界了,就跳出本次循环
for(j=1;j<W-1;j++)
if(!board[i][j].var) break; //一旦该行有一个为空,即跳出
if(j==W-1) //找到满行了
{
for(ii=i;ii>=top;ii--) //重置游戏区域各个方格的状态,top为最顶端,i为找到的满行
for(j=1;j<W-1;j++)
board[ii][j]=board[ii-1][j];
top++;
k++; //找到的满行数
flag_fullrow=1; //标志符
}
}
if(k==1) score+=10;
else if(k==2) score+=25;
else if(k==3) score+=40;
else if(k==4) score+=60;
if(level!=score/level_step) //这里是程序优化部分,也可省略
level=score/level_step;
ShowScore(hdc); //更新分数
ShowLevel(hdc); //更新等级
}
RePaint(hdc,hpen,org_top);
}
void ChangeVar(void) //改变游戏主板的状态
{
int i,j;
if(cur_boxnum==MAX_BOX-1||cur_boxnum==MAX_BOX-2) //如果该方块为炸弹方块
{
for(i=y-2;i<y+6;i++)
{
if(i<=0||i>=H-1) continue;
for(j=x-2;j<x+6;j++)
{
if(j<=0||j>=W-1) continue;
board[i][j].color=BgColor;
board[i][j].var=0;
}
}
}
else
{
for(i=0;i<8;i++)
{
if(block[cur_boxnum].a[i][0]<0) break;
board[y+block[cur_boxnum].a[i][1]][x+block[cur_boxnum].a[i][0]].var=1; //状态置1,表示有方块填充
board[y+block[cur_boxnum].a[i][1]][x+block[cur_boxnum].a[i][0]].color=block[cur_boxnum].color;
}
}
}
BOOL CanMove(void) //判断方块是否能移动
{
int i;
for(i=0;i<8;i++)
{
if(block[cur_boxnum].a[i][0]<0) break;
if(board[y+block[cur_boxnum].a[i][1]][x+block[cur_boxnum].a[i][0]].var) //如果该位置以及有方块填充,则不能移动
return FALSE;
}
return TRUE;
}
BITMAPFILEHEADER * DibLoadImage (PTSTR pstrFileName)
{
BOOL bSuccess ;
DWORD dwFileSize,dwHighSize,dwBytesRead;
HANDLE hFile;
BITMAPFILEHEADER *pbmfh;
hFile=CreateFile(pstrFileName,GENERIC_READ,FILE_SHARE_READ,NULL,
OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(hFile==INVALID_HANDLE_VALUE)
return NULL;
dwFileSize=GetFileSize(hFile,&dwHighSize);
if(dwHighSize)
{
CloseHandle(hFile);
return NULL ;
}
pbmfh=malloc(dwFileSize) ;
if(!pbmfh)
{
CloseHandle(hFile);
return NULL ;
}
bSuccess=ReadFile(hFile,pbmfh,dwFileSize,&dwBytesRead,NULL) ;
CloseHandle(hFile);
if(!bSuccess||(dwBytesRead!=dwFileSize)
||(pbmfh->bfType!=*(WORD *)"BM")
||(pbmfh->bfSize!=dwFileSize))
{
free(pbmfh);
return NULL;
}
return pbmfh;
}