1 #include <windows.h>
2 #include <tchar.h> //swprintf_s函数所需的头文件
3
4 #pragma comment(lib, "winmm.lib") //playSound
5 #pragma comment(lib, "Msimg32.lib") //TransparentBlt
6
7 #define WINDOW_WIDTH 800
8 #define WINDOW_HEIGHT 600
9 #define WINDOW_TITLE L"Windows鼠标键盘消息处理"
10
11 // 环境,内存句柄
12 HDC g_hdc = NULL, g_mdc = NULL, g_bufdc = NULL;
13 // 四张方向图,存储背景图的句柄, 人物2
14 HBITMAP g_hSprite[4] = { NULL }, g_hBackGround = NULL, g_hMan = NULL;
15 // 上一次绘图时间,此次准备绘图的时间
16 DWORD g_tPre = 0, g_tNow = 0;
17 // 图号,人物1横纵坐标,鼠标坐标,鼠标控制人物2坐标
18 int g_iNum = 0, g_iX = 0, g_iY = 0, g_mouseX = 0, g_mouseY = 0, g_iXnow = 0, g_iYnow = 0;
19 // 人物移动方向,以0,1,2,3代表人物上,下,左,右
20 int g_iDirection = 0;
21
22 // 回调函数,窗口过程函数
23 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
24 BOOL Game_Init(HWND hwnd);
25 VOID Game_Paint(HWND hwnd);
26 BOOL Game_CleanUp(HWND hwnd);
27
28
29 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
30 {
31 WNDCLASSEX wndClass = { 0 };
32 wndClass.cbSize = sizeof(WNDCLASSEX);
33 wndClass.style = CS_HREDRAW | CS_VREDRAW;
34 wndClass.lpfnWndProc = WndProc;
35 wndClass.cbClsExtra = 0;
36 wndClass.cbWndExtra = 0;
37 wndClass.hInstance = hInstance;
38 wndClass.hIcon = 0;
39 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
40 // 白色画刷句柄
41 wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
42 // 用一个以空终止的字符串,指定菜单资源的名字
43 wndClass.lpszMenuName = NULL;
44 //窗口类的名字
45 wndClass.lpszClassName = L"Game Develop";
46
47 if (!RegisterClassEx(&wndClass))
48 return -1;
49
50 // 正式创建窗口
51 HWND hwnd = CreateWindow(L"Game Develop", WINDOW_TITLE,
52 WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
53 WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
54
55 MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
56 ShowWindow(hwnd, nShowCmd);
57 UpdateWindow(hwnd);
58
59 if (!Game_Init(hwnd))
60 {
61 MessageBox(hwnd, L"资源初始化失败", L"消息窗口", 0);
62 return FALSE;
63 }
64
65 PlaySound(L"music.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
66
67 MSG msg = { 0 };
68 while (msg.message != WM_QUIT)
69 {
70 // 查看应用程序消息队列,有消息时将队列中的消息派发出去
71 if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
72 {
73 TranslateMessage(&msg);
74 DispatchMessage(&msg);
75 }
76 else
77 {
78 g_tNow = GetTickCount();
79 // 重绘
80 if (g_tNow - g_tPre >= 40)
81 Game_Paint(hwnd);
82 }
83 }
84
85 // 程序准备结束,注销窗口类
86 UnregisterClass(L"Game Develop", wndClass.hInstance);
87 return 0;
88 }
89
90 LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
91 {
92
93 switch (message)
94 {
95 //键盘消息
96 case WM_KEYDOWN:
97 switch (wParam)
98 {
99 //按下Esc键
100 case VK_ESCAPE:
101 DestroyWindow(hwnd);
102 PostQuitMessage(0);
103 break;
104 case VK_UP:
105 g_iY -= 10;
106 g_iDirection = 0;
107 if (g_iY < 0)
108 g_iY = 0;
109 break;
110 case VK_DOWN:
111 g_iY += 10;
112 g_iDirection = 1;
113 if (g_iY > WINDOW_HEIGHT - 135)
114 g_iY = WINDOW_HEIGHT - 135;
115 break;
116 case VK_LEFT:
117 g_iX -= 10;
118 g_iDirection = 2;
119 if (g_iX < 0)
120 g_iX = 0;
121 break;
122 case VK_RIGHT:
123 g_iX += 10;
124 g_iDirection = 3;
125 if (g_iX > WINDOW_WIDTH - 75)
126 g_iX = WINDOW_WIDTH - 75;
127 break;
128 }
129 break;
130
131 // 单击鼠标左键消息
132 case WM_LBUTTONDOWN:
133 break;
134
135 // 鼠标移动消息
136 case WM_MOUSEMOVE:
137 // 取得鼠标X坐标
138 g_mouseX = LOWORD(lParam);
139 if (g_mouseX > WINDOW_WIDTH - 292)
140 g_mouseX = WINDOW_WIDTH - 292;
141 else if (g_mouseX < 0)
142 g_mouseX = 0;
143 // 取得鼠标Y坐标
144 g_mouseY = HIWORD(lParam);
145 if (g_mouseY > WINDOW_HEIGHT - 190)
146 g_mouseY = WINDOW_HEIGHT - 190;
147 else if (g_mouseY < 0)
148 g_mouseY = 0;
149 break;
150
151 case WM_DESTROY:
152 Game_CleanUp(hwnd);
153 PostQuitMessage(0);
154 break;
155
156 //调用缺省的窗口过程
157 default:
158 return DefWindowProc(hwnd, message, wParam, lParam);
159 }
160 return 0;
161 }
162
163 BOOL Game_Init(HWND hwnd)
164 {
165 HBITMAP bmp;
166 g_hdc = GetDC(hwnd);
167 // 创建一个和hdc兼容的内存DC
168 g_mdc = CreateCompatibleDC(g_hdc);
169 // hdc兼容的缓冲DC
170 g_bufdc = CreateCompatibleDC(g_hdc);
171 bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
172
173 g_iX = 100;
174 g_iY = 350;
175 g_mouseX = 300;
176 g_mouseY = 100;
177 g_iXnow = 300;
178 g_iYnow = 100;
179 g_iDirection = 3;
180 g_iNum = 0;
181
182 SelectObject(g_mdc, bmp);
183 g_hSprite[0] = (HBITMAP)LoadImage(NULL, L"go1.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
184 g_hSprite[1] = (HBITMAP)LoadImage(NULL, L"go2.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
185 g_hSprite[2] = (HBITMAP)LoadImage(NULL, L"go3.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
186 g_hSprite[3] = (HBITMAP)LoadImage(NULL, L"go4.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
187 g_hBackGround = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
188 g_hMan = (HBITMAP)LoadImage(NULL, L"man2.bmp", IMAGE_BITMAP, 292, 190, LR_LOADFROMFILE);
189
190 POINT pt, lt, rb;
191 RECT rect;
192 // 设定光标位置
193 pt.x = 300;
194 pt.y = 100;
195 // 将指定点或者矩形的用户坐标转换成屏幕坐标
196 ClientToScreen(hwnd, &pt);
197 SetCursorPos(pt.x, pt.y);
198 // 隐藏鼠标光标
199 ShowCursor(false);
200 // 限制鼠标光标移动区域
201 // 取得窗口内部矩形
202 GetClientRect(hwnd, &rect);
203 // 将矩形左上点坐标存入lt中
204 lt.x = rect.left;
205 lt.y = rect.top;
206 // 将矩形右下坐标存入rb中
207 rb.x = rect.right;
208 rb.y = rect.bottom;
209 // 将lt和rb的窗口坐标转换为屏幕坐标
210 ClientToScreen(hwnd, <);
211 ClientToScreen(hwnd, &rb);
212 // 以屏幕坐标重新设定矩形区域
213 rect.left = lt.x;
214 rect.top = lt.y;
215 rect.right = rb.x;
216 rect.bottom = rb.y;
217 // 限制鼠标光标移动区域
218 ClipCursor(&rect);
219
220 Game_Paint(hwnd);
221 return TRUE;
222 }
223
224 VOID Game_Paint(HWND hwnd)
225 {
226 // 先在mdc中贴上背景图
227 SelectObject(g_bufdc, g_hBackGround);
228 // 将源矩形区域直接拷贝到目标矩形区域
229 BitBlt(g_mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);
230
231 // 按照目前的移动方向取出对应人物的连续走动图,并确定截取人物图的宽度与高度
232 SelectObject(g_bufdc, g_hSprite[g_iDirection]);
233 // 使用AND(与)操作符来将源和目标矩形区域内的颜色合并
234 BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 108, SRCAND);
235 // 使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并
236 BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 0, SRCPAINT);
237
238 // 计算人物2的贴图坐标,设定每次进行贴图时,其坐标(g_iXnow,g_iYnow)会以每20个单位慢慢向鼠标光标所在的目的点(x,y)接近,直到两个坐标相同为止
239 if (g_iXnow < g_mouseX)
240 {
241 g_iXnow += 20;
242 if (g_iXnow > g_mouseX)
243 g_iXnow = g_mouseX;
244 }
245 else
246 {
247 g_iXnow -= 20;
248 if (g_iXnow < g_mouseX)
249 g_iXnow = g_mouseX;
250 }
251
252 if (g_iYnow < g_mouseY)
253 {
254 g_iYnow += 20;
255 if (g_iYnow > g_mouseY)
256 g_iYnow = g_mouseY;
257 }
258 else
259 {
260 g_iYnow -= 20;
261 if (g_iYnow < g_mouseY)
262 g_iYnow = g_mouseY;
263 }
264 // 贴上人物2图
265 SelectObject(g_bufdc, g_hMan);
266 // 对指定的源设备环境中的矩形区域数据进行位块转换,并将结果置于目标设备环境
267 TransparentBlt(g_mdc, g_iXnow, g_iYnow, 292, 190, g_bufdc, 0, 0, 292, 190, RGB(0, 0, 0));
268
269 HFONT hFont;
270 // 创建字体
271 hFont = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, TEXT("微软雅黑"));
272 SelectObject(g_mdc, hFont);
273 // 设置文字背景透明
274 SetBkMode(g_mdc, TRANSPARENT);
275 // 设置文字颜色
276 SetTextColor(g_mdc, RGB(255, 255, 0));
277 //在左上角进行文字输出
278 wchar_t str[20] = {};
279 swprintf_s(str, L"鼠标X坐标为%d", g_mouseX);
280 TextOut(g_mdc, 0, 0, str, wcslen(str));
281 swprintf_s(str, L"鼠标Y坐标为%d", g_mouseY);
282 TextOut(g_mdc, 0, 20, str, wcslen(str));
283
284 // 贴上背景图
285 BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
286
287 // 记录此次绘图时间
288 g_tPre = GetTickCount();
289 // go1.bmp有8个人物1动作图,用来实现人物1运动
290 g_iNum++;
291 if (g_iNum == 8)
292 g_iNum = 0;
293 }
294
295 BOOL Game_CleanUp(HWND hwnd)
296 {
297 // 释放资源对象
298 DeleteObject(g_hBackGround);
299 for (int i = 0; i<4; i++)
300 {
301 DeleteObject(g_hSprite[i]);
302 }
303 DeleteObject(g_hMan);
304 DeleteDC(g_bufdc);
305 DeleteDC(g_mdc);
306 ReleaseDC(hwnd, g_hdc);
307 return TRUE;
308 }