#include<windows.h>
#include<stdlib.h>
#include<time.h>
#include"definition.h"
#include"function.h"
LRESULT CALLBACK MyFirstProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
HWND hwnd;
MSG msg;
srand((unsigned)time(NULL));//这里是埋下随机数种子
WNDCLASS wndclass;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=MyFirstProc;
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName="cc";
wndclass.style=CS_HREDRAW|CS_VREDRAW;
RegisterClass(&wndclass);
hwnd=CreateWindow("cc","处女作",WS_OVERLAPPEDWINDOW &~WS_MAXIMIZEBOX &~WS_THICKFRAME&~WS_OVERLAPPED,400,0,(COLUMN+1)*23-9,(ROW+2)*23-9,NULL,NULL,hInstance,NULL);//23是位图的像素高度和宽度 可通过 char tm[100];sprintf(tm,"像素是:%d",bm.bmWidth);MessageBox(hwnd,tm,"像素", // MB_OK),来查看
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
Myrand();收获随机数种子并初始化box
while(GetMessage(&msg,NULL,0,0))
{
if(!JudgeFull())//判断是否到顶了
{
if(!JudgeFall(x,y))//判断是否到达底端
{
Puton(x,y);//用小盒子box填充大盒子State
ClearLine();//判断满行并销行
InvalidateRect(hwnd,NULL,TRUE);//发送WM_PAINT重绘窗口
x=0;
y=COLUMN/2;
Myrand();
}
}
else
PostMessage(hwnd,WM_CLOSE,0,0);//到顶了发送消息结束程序
DispatchMessage(&msg);//装换消息
TranslateMessage(&msg);//派遣消息
}
return msg.wParam;
}
LRESULT CALLBACK MyFirstProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
int i,j,temp;
PAINTSTRUCT ps;
HDC hdc;
HDC hdcmem;
HBITMAP hbitmap;
BITMAP bm;
switch(uMsg)
{
case WM_CREATE:
SetMap();//初始化地图
x=0;
y=COLUMN/2;
SetTimer(hwnd,ID_DOWN,250,NULL);
break;
case WM_TIMER:
if(ID_DOWN==wParam)
{
temp=x;
temp++;
if(Test(temp,y,box,State))
x++;
InvalidateRect(hwnd,NULL,TRUE);
}
break;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);//获取设备描述表
hbitmap=(HBITMAP)LoadImage(NULL,"blockunit.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);//加载位图大家可以找一个方块位图命名为"blockunit.bmp就可以了 当然像 //素的大小要调一下,可以通过前面介绍的方法获取方块像素大小
hdcmem=CreateCompatibleDC(hdc);//创建内存设备描述表 兼容DC
GetObject(hbitmap,sizeof(bm),&bm);获取位图信息
hbitmap=(HBITMAP)SelectObject(hdcmem,hbitmap);//将位图选入设备描述表
for(i=0;i<4;i++)//画小盒子
for(j=0;j<4;j++)
{
if(box[i][j]==1)
BitBlt(hdc,(y+j-1)*bm.bmWidth,(x+i)*bm.bmHeight,bm.bmWidth,bm.bmHeight,hdcmem,0,0,SRCCOPY);
}
for(i=0;i<ROW+1;i++)//画大盒子
for(j=1;j<COLUMN+2;j++)
if(State[i][j]==1)
{
BitBlt(hdc,(j-1)*bm.bmWidth,i*bm.bmHeight,bm.bmWidth,bm.bmHeight,hdcmem,0,0,SRCCOPY);
}
EndPaint(hwnd,&ps);
DeleteDC(hdcmem);
DeleteDC(hdc);
break;
case WM_KEYDOWN://效应按键消息
{
switch(wParam)//判断按键消息种类虚拟键
{
case VK_LEFT:
temp=y;
temp--;
if(Test(x,temp,box,State))
y--;
InvalidateRect(hwnd,NULL,TRUE);
break;
case VK_RIGHT:
temp=y;
temp++;
if(Test(x,temp,box,State))
y++;
InvalidateRect(hwnd,NULL,TRUE);
break;
case VK_UP:
if(TestRoll(x,y,box)==1)
UpRoll(box,box);
InvalidateRect(hwnd,NULL,TRUE);
break;
case VK_DOWN:
temp=x;
temp++;
if(Test(temp,y,box,State))
x++;
InvalidateRect(hwnd,NULL,TRUE);
break;
}
}
break;
case WM_CLOSE:
if(MessageBox(hwnd,"Game over","退出游戏",MB_OK))
DestroyWindow(hwnd);//摧毁窗口 注意此时并没有关闭应用程序只是摧毁了窗口 发送WM_DESTROY
break;
case WM_DESTROY:
PostQuitMessage(0);发送WM_QUIT关闭应用程序
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
}
void Myrand()//获取随机数
{
int type;
int i,j;
type=rand()%7;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
box[i][j]=BlockState[type][i][j];
}
void UpRoll(int boxOut[][4],int boxIn[][4])//方块翻转
{
int i,j;
int temp[4][4]={0};
for(i=0;i<4;i++)
for(j=3;j>=0;j--)
{
temp[j][3-i]=boxIn[i][j];
}
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{
boxOut[i][j]=temp[i][j];
}
}
int Test(int cx,int cy,int cbox[][4],int cState[][COLUMN+2])//测试方块是否到达边缘
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{
if(1==cState[i+cx][j+cy]&&cbox[i][j])
return 0;
}
return 1;
}
void Puton(int cx,int cy)//box填充State
{
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
{ if(box[i][j]==1)
State[i+cx][j+cy]=box[i][j];
}
}
int JudgeFull()
{
int i;
int flag=0;
for(i=1;i<COLUMN;i++)
if(State[0][i])
{
flag=1;
return 1;
}
return 0;
}
void ClearLine()//销行
{
int i,j;
int flag;
int cx,cy;
for(i=0;i<ROW;i++)
{
flag=1;
for(j=1;j<COLUMN;j++)
{
if(!State[i][j])
{
flag=0;
break;
}
}
if(1==flag)
{
for(cx=i;cx>=1;cx--)
for(cy=1;cy<COLUMN;cy++)
{
State[cx][cy]=State[cx-1][cy];
}
for(cy=1;cy<COLUMN;cy++)
State[0][cy]=0;
}
}
}
void SetMap()//初始化地图
{
int i,j;
for(i=0;i<ROW+1;i++)
for(j=0;j<COLUMN+2;j++)
{
if(j==0||j==COLUMN+1||i==ROW)//这是一个很巧妙的方法让大盒子的最左最右最下端让State[][]初始化为1始方块不能越过这三条边界,起到了围墙的作用
State[i][j]=1;
else State[i][j]=0;
}
}
int TestRoll(int cx,int cy,int cbox[][4])//判断方块是否能翻转
{
int testbox[4][4]={0};
UpRoll(testbox,cbox);
if(Test(cx,cy,testbox,State))
return 1;
return 0;
}
int JudgeFall(int cx,int cy)//判断方块是否到底部
{
int temp;
temp=x;
temp++;
if(Test(temp,cy,box,State))
return 1;
else
return 0;
}
--------------------------------------------------------------------------------------------definition.h
#define ROW 25
#define COLUMN 16
#define TYPE 7
#define ID_DOWN 1
int x,y;//记录小方块坐标
int State[ROW+1][COLUMN+2]={0};
int box[4][4]={0};
int BlockState[TYPE][4][4]={//方块七种形态
{
0,0,0,0,
0,1,1,0,
0,1,1,0,
0,0,0,0
},
{
0,1,0,0,
0,1,0,0,
0,1,1,0,
0,0,0,0
},
{
0,0,1,0,
0,0,1,0,
0,1,1,0,
0,0,0,0
},
{
0,0,0,0,
1,1,0,0,
0,1,1,0,
0,0,0,0
},
{
0,0,0,0,
0,0,1,1,
0,1,1,0,
0,0,0,0
},
{
0,1,0,0,
0,1,0,0,
0,1,0,0,
0,1,0,0
},
{
0,0,0,0,
0,1,0,0,
1,1,1,0,
0,0,0,0
}
};
---------------------------------------------function.h
void Myrand();
void ClearLine();
int JudgeFull();
int JudgeFall(int,int);
int Test(int,int,int[][4],int[][COLUMN+2]);
void SetMap();
void UpRoll(int boxOut[][4],int boxIn[][4]);
void Puton(int,int);
int TestRoll(int,int,int[][4]);
--------------------------------------------------------------
用到的主要API函数 多看看加强记忆
函数原型
int MessageBox(HWND hWnd,LPCTSTR lpText,LPCTSTR lpCaption,UINT UType);编辑本段参数
hWnd:标识将被创建的消息框的拥有窗口。如果此参数为NULL,则消息框没有拥有窗口。 lpText:指向一个以NULL结尾的、含有将被显示的消息的字符串的指针。 lpCaption:指向一个以NULL结尾的、用于对话框标题的字符串的指针。 uType:指定一个决定对话框的内容和行为的位标志集。缺省值为MB_OK;函数原型
BOOL UpdateWindow( HWND hWnd // 窗口的句柄 );如果窗口更新的区域不为空,UpdateWindow函数通过发送一个WM_PAINT消息来更新指定窗口的客户区。函数绕过应用程序的消息队列,直接发送WM_PAINT消息给指定窗口的窗口过程,如果更新区域为空,则不发送消息。函数原型
void srand(unsigned seed);经常这样用 srand((unsigned) time(NULL))来埋下种子SetTimer函数的用法
1.1 用WM_TIMER来设置定时器 先请看SetTimer这个API函数的原型 UINT_PTR SetTimer( HWND hWnd, // 窗口句柄 UINT_PTR nIDEvent, // 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器 UINT uElapse, // 时间间隔,单位为毫秒 TIMERPROC lpTimerFunc // 回调函数,设置了回调函数WM_TIMER直接发送到该函数不经过应用程序消息队列 );LoadImage
编辑本段简介
函数功能:该函数装载图标,光标,或位图。 函数原型:HANDLE LoadImage( HINSTANCE hinst, LPCTSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad );编辑本段
GetObject
编辑本段函数简介
函数功能:该函数得到指定图形对象的信息,根据图形对象,函数把填满的或结构,或表项(用于逻辑调色板)数目放入一个指定的缓冲区。 函数原型:int GetObject(HGDIOBJ hgdiobj, int cbBuffer, LPVOID lpvObject); 参数: hgdiobj:指向感兴趣的图形对象的句柄,它可以是这样的一个句柄:一个逻辑位图、一个刷子、一种字体、一个调色板、笔或通过调用CreateDIBsection函数创建的与设备无关位图。 cbBuffer:指定将要写到缓冲区的信息的字节数目。 lpvObject:指向一个缓冲区的指针,该缓冲区将要检索指定图形对象的信息。SelectObject
CPen* SelectObject( CPen* pPen );
CBrush* SelectObject( CBrush* pBrush );
virtual CFont* SelectObject( CFont* pFont );
CBitmap* SelectObject( CBitmap* pBitmap );
int SelectObject( CRgn* pRgn );
CGdiObject* SelectObject( CGdiObject* pObject );
函数功能:该函数选择一对象到指定的设备上下文环境中,该新对象替换先前的相同类型的对象。
函数原型:HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj);//返回值是被取代的对象句柄
编辑本段函数原型
BOOL BitBlt(HDC hdcDest,int nXDest,int nYDest,int nWidth,int nHeight,HDC hdcSrc,int nXSrc,int nYSrc,DWORD dwRop);函数功能
该函数对指定的源设备环境区域中的像素进行位块(bit_block)转换,以传送到目标设备环境。编辑本段参数
hdcDest:指向目标设备环境的句柄。 nXDest:指定目标矩形区域左上角的X轴逻辑坐标。 nYDest:指定目标矩形区域左上角的Y轴逻辑坐标。 nWidth:指定源和目标矩形区域的逻辑宽度。 nHeight:指定源和目标矩形区域的逻辑高度。 hdcSrc:指向源设备环境的句柄。 nXSrc:指定源矩形区域左上角的X轴逻辑坐标。 nYSrc:指定源矩形区域左上角的Y轴逻辑坐标。 dwRop:指定光栅操作代码。这些代码将定义源矩形区域的颜色数据,如何与目标矩形区域的颜色数据组合以完成最后的颜色。PostQuitMessage
函数功能:该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息。
函数原型:VOID PostQuitMessage(int nExitCode);
参数:
nExitCode:指定应用程序退出代码。此值被用作消息WM_QUIT的wParam参数。
返回值:无。