转载自
https://www.cnblogs.com/ht-beyond/p/4445439.html
#include <windows.h>
#include <tchar.h> //swprintf_s函数所需的头文件
#pragma comment(lib, "winmm.lib") //playSound
#pragma comment(lib, "Msimg32.lib") //TransparentBlt
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE L"Windows鼠标键盘消息处理"
// 环境,内存句柄
HDC g_hdc = NULL, g_mdc = NULL, g_bufdc = NULL;
// 四张方向图,存储背景图的句柄, 人物2
HBITMAP g_hSprite[4] = { NULL }, g_hBackGround = NULL, g_hMan = NULL;
// 上一次绘图时间,此次准备绘图的时间
DWORD g_tPre = 0, g_tNow = 0;
// 图号,人物1横纵坐标,鼠标坐标,鼠标控制人物2坐标
int g_iNum = 0, g_iX = 0, g_iY = 0, g_mouseX = 0, g_mouseY = 0, g_iXnow = 0, g_iYnow = 0;
// 人物移动方向,以0,1,2,3代表人物上,下,左,右
int g_iDirection = 0;
// 回调函数,窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL Game_Init(HWND hwnd);
VOID Game_Paint(HWND hwnd);
BOOL Game_CleanUp(HWND hwnd);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WNDCLASSEX wndClass = { 0 };
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = 0;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
// 白色画刷句柄
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
// 用一个以空终止的字符串,指定菜单资源的名字
wndClass.lpszMenuName = NULL;
//窗口类的名字
wndClass.lpszClassName = L"Game Develop";
if (!RegisterClassEx(&wndClass))
return -1;
// 正式创建窗口
HWND hwnd = CreateWindow(L"Game Develop", WINDOW_TITLE,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true);
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
if (!Game_Init(hwnd))
{
MessageBox(hwnd, L"资源初始化失败", L"消息窗口", 0);
return FALSE;
}
PlaySound(L"music.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP);
MSG msg = { 0 };
while (msg.message != WM_QUIT)
{
// 查看应用程序消息队列,有消息时将队列中的消息派发出去
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_tNow = GetTickCount();
// 重绘
if (g_tNow - g_tPre >= 40)
Game_Paint(hwnd);
}
}
// 程序准备结束,注销窗口类
UnregisterClass(L"Game Develop", wndClass.hInstance);
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//键盘消息
case WM_KEYDOWN:
switch (wParam)
{
//按下Esc键
case VK_ESCAPE:
DestroyWindow(hwnd);
PostQuitMessage(0);
break;
case VK_UP:
g_iY -= 10;
g_iDirection = 0;
if (g_iY < 0)
g_iY = 0;
break;
case VK_DOWN:
g_iY += 10;
g_iDirection = 1;
if (g_iY > WINDOW_HEIGHT - 135)
g_iY = WINDOW_HEIGHT - 135;
break;
case VK_LEFT:
g_iX -= 10;
g_iDirection = 2;
if (g_iX < 0)
g_iX = 0;
break;
case VK_RIGHT:
g_iX += 10;
g_iDirection = 3;
if (g_iX > WINDOW_WIDTH - 75)
g_iX = WINDOW_WIDTH - 75;
break;
}
break;
// 单击鼠标左键消息
case WM_LBUTTONDOWN:
break;
// 鼠标移动消息
case WM_MOUSEMOVE:
// 取得鼠标X坐标
g_mouseX = LOWORD(lParam);
if (g_mouseX > WINDOW_WIDTH - 292)
g_mouseX = WINDOW_WIDTH - 292;
else if (g_mouseX < 0)
g_mouseX = 0;
// 取得鼠标Y坐标
g_mouseY = HIWORD(lParam);
if (g_mouseY > WINDOW_HEIGHT - 190)
g_mouseY = WINDOW_HEIGHT - 190;
else if (g_mouseY < 0)
g_mouseY = 0;
break;
case WM_DESTROY:
Game_CleanUp(hwnd);
PostQuitMessage(0);
break;
//调用缺省的窗口过程
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}
BOOL Game_Init(HWND hwnd)
{
HBITMAP bmp;
g_hdc = GetDC(hwnd);
// 创建一个和hdc兼容的内存DC
g_mdc = CreateCompatibleDC(g_hdc);
// hdc兼容的缓冲DC
g_bufdc = CreateCompatibleDC(g_hdc);
bmp = CreateCompatibleBitmap(g_hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
g_iX = 100;
g_iY = 350;
g_mouseX = 300;
g_mouseY = 100;
g_iXnow = 300;
g_iYnow = 100;
g_iDirection = 3;
g_iNum = 0;
SelectObject(g_mdc, bmp);
g_hSprite[0] = (HBITMAP)LoadImage(NULL, L"go1.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
g_hSprite[1] = (HBITMAP)LoadImage(NULL, L"go2.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
g_hSprite[2] = (HBITMAP)LoadImage(NULL, L"go3.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
g_hSprite[3] = (HBITMAP)LoadImage(NULL, L"go4.bmp", IMAGE_BITMAP, 480, 216, LR_LOADFROMFILE);
g_hBackGround = (HBITMAP)LoadImage(NULL, L"bg.bmp", IMAGE_BITMAP, WINDOW_WIDTH, WINDOW_HEIGHT, LR_LOADFROMFILE);
g_hMan = (HBITMAP)LoadImage(NULL, L"man2.bmp", IMAGE_BITMAP, 292, 190, LR_LOADFROMFILE);
POINT pt, lt, rb;
RECT rect;
// 设定光标位置
pt.x = 300;
pt.y = 100;
// 将指定点或者矩形的用户坐标转换成屏幕坐标
ClientToScreen(hwnd, &pt);
SetCursorPos(pt.x, pt.y);
// 隐藏鼠标光标
ShowCursor(false);
// 限制鼠标光标移动区域
// 取得窗口内部矩形
GetClientRect(hwnd, &rect);
// 将矩形左上点坐标存入lt中
lt.x = rect.left;
lt.y = rect.top;
// 将矩形右下坐标存入rb中
rb.x = rect.right;
rb.y = rect.bottom;
// 将lt和rb的窗口坐标转换为屏幕坐标
ClientToScreen(hwnd, <);
ClientToScreen(hwnd, &rb);
// 以屏幕坐标重新设定矩形区域
rect.left = lt.x;
rect.top = lt.y;
rect.right = rb.x;
rect.bottom = rb.y;
// 限制鼠标光标移动区域
ClipCursor(&rect);
Game_Paint(hwnd);
return TRUE;
}
VOID Game_Paint(HWND hwnd)
{
// 先在mdc中贴上背景图
SelectObject(g_bufdc, g_hBackGround);
// 将源矩形区域直接拷贝到目标矩形区域
BitBlt(g_mdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_bufdc, 0, 0, SRCCOPY);
// 按照目前的移动方向取出对应人物的连续走动图,并确定截取人物图的宽度与高度
SelectObject(g_bufdc, g_hSprite[g_iDirection]);
// 使用AND(与)操作符来将源和目标矩形区域内的颜色合并
BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 108, SRCAND);
// 使用布尔型的OR(或)操作符将源和目标矩形区域的颜色合并
BitBlt(g_mdc, g_iX, g_iY, 60, 108, g_bufdc, g_iNum * 60, 0, SRCPAINT);
// 计算人物2的贴图坐标,设定每次进行贴图时,其坐标(g_iXnow,g_iYnow)会以每20个单位慢慢向鼠标光标所在的目的点(x,y)接近,直到两个坐标相同为止
if (g_iXnow < g_mouseX)
{
g_iXnow += 20;
if (g_iXnow > g_mouseX)
g_iXnow = g_mouseX;
}
else
{
g_iXnow -= 20;
if (g_iXnow < g_mouseX)
g_iXnow = g_mouseX;
}
if (g_iYnow < g_mouseY)
{
g_iYnow += 20;
if (g_iYnow > g_mouseY)
g_iYnow = g_mouseY;
}
else
{
g_iYnow -= 20;
if (g_iYnow < g_mouseY)
g_iYnow = g_mouseY;
}
// 贴上人物2图
SelectObject(g_bufdc, g_hMan);
// 对指定的源设备环境中的矩形区域数据进行位块转换,并将结果置于目标设备环境
TransparentBlt(g_mdc, g_iXnow, g_iYnow, 292, 190, g_bufdc, 0, 0, 292, 190, RGB(0, 0, 0));
HFONT hFont;
// 创建字体
hFont = CreateFont(20, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, TEXT("微软雅黑"));
SelectObject(g_mdc, hFont);
// 设置文字背景透明
SetBkMode(g_mdc, TRANSPARENT);
// 设置文字颜色
SetTextColor(g_mdc, RGB(255, 255, 0));
//在左上角进行文字输出
wchar_t str[20] = {};
swprintf_s(str, L"鼠标X坐标为%d", g_mouseX);
TextOut(g_mdc, 0, 0, str, wcslen(str));
swprintf_s(str, L"鼠标Y坐标为%d", g_mouseY);
TextOut(g_mdc, 0, 20, str, wcslen(str));
// 贴上背景图
BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, SRCCOPY);
// 记录此次绘图时间
g_tPre = GetTickCount();
// go1.bmp有8个人物1动作图,用来实现人物1运动
g_iNum++;
if (g_iNum == 8)
g_iNum = 0;
}
BOOL Game_CleanUp(HWND hwnd)
{
// 释放资源对象
DeleteObject(g_hBackGround);
for (int i = 0; i<4; i++)
{
DeleteObject(g_hSprite[i]);
}
DeleteObject(g_hMan);
DeleteDC(g_bufdc);
DeleteDC(g_mdc);
ReleaseDC(hwnd, g_hdc);
return TRUE;
}