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 }