打地鼠游戏的核心就是一个随机和一个坐标检测。随机的是地鼠(目标矩形)的位置,鼠标单击后就得到当前的鼠标的坐标,然后检测坐标是否在地鼠头部的范围内。如果在这个范围内,就表示击中了,就要加分,同时播放击中的爆炸效果和圆形的击中效果。然后显示总分。
我们先看看效果,运行的程序击中后有爆炸音效:
【win32实现的最简单的打地鼠游戏效果】
我们在WM_CREATE消息即窗口创建时就启动计时器计时。在计时器消息里,不断的产生随即矩形的起点坐标,也就是左上角的坐标。然后右下角的坐标实际上就是控制矩形的大小,我们利用左上角的坐标加上宽度和高度来确定。这样就可以固定矩形的大小。然后就是让客户区实现,让WM_PAINT消息来绘制矩形。代码如下:case WM_TIMER:
GetClientRect(hwnd,&rectClient);
rect.left = rand()%(rectClient.right-rectSize);
rect.right = rect.left+rectSize;
rect.top = rand()%(rectClient.bottom-rectSize);
rect.bottom = rect.top+rectSize;
InvalidateRect(hwnd,NULL,TRUE);
return 0;
在WM_PAINT消息中,我们要画出矩形,而矩形的范围则是在WM_TIMER消息中已经确定,所以只需要画出来即可。然后还要显示总分。那么客户区绘制消息就这么多了。那么这样就解决了第一个核心问题即随机矩形位置的实现。下面一个就是检测是否命中。
我们在鼠标左键单击消息WM_LBUTTONDOWN来做检测。首先需要获取鼠标的坐标,使用GET_X_LPARAM和GET_Y_LPARAM来提取坐标。然后就是要使用到一个检测函数PtInRect。这个函数是此游戏的第二个核心。
PtInRect函数是检测一个点是否在一个矩形内部,第一个参数就是一个矩形的地址,第二个参数就是点POINT变量。如果点在矩形内,则返回真,否则返回假。这样就可以实现检测功能了。如果检测击中了,就使用PlaySound函数来播放爆炸音效。同时在矩形内画一个白色的椭圆。默认的填充颜色就是白色,所以调用Ellipse函数即可达到这个效果,而椭圆的参数就是矩形的四个参数咯。
还要注意一个问题,PlaySound函数要正常使用,需要导入lib静态库。为了不增加项目的设置的麻烦,我们使用指令导入,即:
#pragma comment(lib,"WINMM.lib")
这样你只要将这个完整的代码复制,就不用担心设置的问题。下面是完整的代码:
#include "windows.h"
#include "Windowsx.h"
#include <tchar.h>
#pragma comment(lib,"WINMM.lib")
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
static int Sum=0;
static RECT rect,rectClient;
int rectSize=100;
static TCHAR Msg[100]=_T("");
SYSTEMTIME st;
switch (message)
{
case WM_CREATE:
SetTimer(hwnd,0,200,NULL);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd,&ps);
SelectObject(hdc,GetStockObject(GRAY_BRUSH));
Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom);
wsprintf(Msg,_T("当前得分:%d"),Sum*100);
TextOut(hdc,0,0,Msg,lstrlen(Msg));
EndPaint(hwnd,&ps);
return 0;
case WM_LBUTTONDOWN:
{
hdc=GetDC(hwnd);
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if(PtInRect(&rect,pt))
{
Sum++;
PlaySound(_T("b.wav"),NULL,SND_FILENAME|SND_ASYNC);
Ellipse(hdc,rect.left,rect.top,rect.right,rect.bottom);
}
ReleaseDC(hwnd,hdc);
}
return 0;
case WM_TIMER:
GetClientRect(hwnd,&rectClient);
rect.left = rand()%(rectClient.right-rectSize);
rect.right = rect.left+rectSize;
rect.top = rand()%(rectClient.bottom-rectSize);
rect.bottom = rect.top+rectSize;
InvalidateRect(hwnd,NULL,TRUE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
TCHAR ClassName[] = _T("MyClass");
TCHAR title1[] = _T("C++技术网http://www.cjjjs.com-打地鼠游戏简版");
WNDCLASS wndClass;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.hCursor=LoadCursor(NULL,IDC_HAND);
wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WinProc;
wndClass.lpszClassName = ClassName;
wndClass.lpszMenuName=NULL;
wndClass.style=CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wndClass))return 0;
HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
MSG msg;
while (GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}