本系列文章由@二货梦想家张程 所写,转载请注明出处。
作者:ZeeCoder 微博链接:http://weibo.com/zc463717263
我的邮箱:michealfloyd@126.com 欢迎大家发邮件来和我交流编程心得
you are what you read!与大家共勉!
-------------------------------------------------分割线:ZeeCoder--------------------------------------------
在PC端我们常用到键盘上的快捷键来控制PC机进行相应的操作,游戏中也是如此。这篇笔记主要介绍如何通过键盘来控制人物跑动。
一、键盘输入消息
Windows系统是一个消息驱动的环境,一旦使用者在键盘上进行了输入操作,那么系统便会接收到对应的键盘消息。
整个消息响应的过程是:
使用者按下键盘、弹起键盘→产生虚拟键码→程序通过判断虚拟键码信息得知那个按键被按下→通过响应的函数来处理键盘消息。
常见的键盘消息有:按下键盘消息(WM_KEYDOWN)、弹起键盘消息(WM_KEYUP)和字符消息(WM_CHAR)。
二、键盘消息处理
WINDOWS程序通过WinProc函数来观察消息并响应。其原型:
<strong>LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)</strong>
其中,wParam的值为按下按键的虚拟键码。在程序中即通过判断这个变量来确定哪个按键按下。其具体处理函数示例如下:
<strong>LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN://按下键盘消息 switch (wParam)//通过判断wParam来确定按下的按键 { case VK_ESCAPE: //按下【ESC】键 //添加处理程序 PostQuitMessage(0);//退出程序 break; case VK_UP: //按下【↑】键 //添加处理程序 break; } break; case WM_DESTROY://窗口结束消息 PostQuitMessage(0); //向系统申请终止程序 break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }</strong>
三、键盘控制人物移动实现
本笔记要通过【↑】【↓】【←】【→】实现控制人物移动。
首先我们需要四个方向的人物跑动图(下图以左移动示例)。
为了让动画更具备真实性,本程序中还要用到当没有键盘消息时人物站立的分解图。
当然我们还需要一张背景图。
OK,准备工作已经完成,下面看具体的代码实现。
四、代码实现
#include "stdafx.h" #include "MyGame.h" #define MAX_LOADSTRING 100 // Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name // Forward declarations of functions included in this code module: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //定义全局变量 HDC hdc , mdc , bufdc; HWND hWnd; HBITMAP bg , Walker[8]; DWORD tNow , tPre ; int dir , char_x = 0 , char_y = 0;//char_x,char_y为人物贴图坐标 int num;//人物跑动图中的编号 //定义自定义函数 void MyPaint(HDC hdc); //***************************主函数********************************** int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_MYGAME, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } // Main message loop: GetMessage(&msg,NULL,NULL,NULL); //初始化msg while (msg.message != WM_QUIT) { if ( PeekMessage( &msg , NULL ,0 ,0 ,PM_REMOVE))//PM_REMOVE消息从队列里除掉 { TranslateMessage(&msg); DispatchMessage(&msg); } else { tNow = GetTickCount();//获取当前时间 if (tNow - tPre >= 100)//实现游戏循环 { MyPaint(hdc);//循环贴图 } } } return (int) msg.wParam; } //***************************窗口类函数********************************** ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYGAME)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MYGAME); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } //***************************初始化函数********************************** BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { TCHAR filename[20]; HBITMAP bmp; memset(filename , 0 ,sizeof(TCHAR)*20); int i ; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(_T("MyGame"), _T("Game"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } MoveWindow(hWnd , 10 , 10 , 1100 ,700 ,true); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hdc = GetDC(hWnd); mdc = CreateCompatibleDC(hdc); bufdc = CreateCompatibleDC(hdc); bmp = CreateCompatibleBitmap(hdc , 1100 , 720); SelectObject(mdc , bmp); //载入4方向跑动和站立图 for ( i = 0 ; i <= 7 ;i++) { _stprintf_s(filename , TEXT("%d.bmp") , i); Walker[i] = (HBITMAP)LoadImage(NULL , filename , IMAGE_BITMAP , 536 ,182, LR_LOADFROMFILE); } //载入背景图 bg = (HBITMAP)LoadImage(NULL , _T("res.bmp") , IMAGE_BITMAP , 1100 ,720 , LR_LOADFROMFILE); //初始化各变量 char_x = 300; char_y = 300; num = 0 ; //调用自定义绘图程序 MyPaint(hdc); return TRUE; } //***************************消息响应函数********************************** //按下【↑】【↓】【←】【→】使人物跑动 //按下鼠标左键使人物跑动到指定位置 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_KEYDOWN: switch (wParam) { case VK_ESCAPE: //按下【ESC】键退出 PostQuitMessage(0); break; case VK_UP: //按下【↑】键 char_y -= 10 ; if (char_y <=0) { char_y = 0; } dir = 3; break; case VK_DOWN://按下【↓】键 char_y += 10; if (char_y >= 1100) { char_y = 1100; } dir = 0; break; case VK_LEFT://按下【←】键 char_x -= 10; if (char_x <= 0) { char_x =0; } dir = 1; break; case VK_RIGHT://按下【→】键 char_x += 10; if (char_x >= 720) { char_x = 720; } dir = 2; break; } break; case WM_KEYUP: switch (wParam) { case VK_UP: //弹起【↑】键 dir = 7; break; case VK_DOWN://弹起【↓】键 dir = 4; break; case VK_LEFT://弹起【←】键 dir = 5; break; case VK_RIGHT://弹起【→】键 dir = 6; break; } break; case WM_DESTROY: int i; DeleteDC(mdc); DeleteDC(bufdc); for ( i = 0 ; i < 8 ; i++) { DeleteObject(Walker[i]); } DeleteObject(bg); ReleaseDC(hWnd , hdc); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void MyPaint(HDC hdc) { //贴背景图 SelectObject(bufdc , bg); BitBlt(mdc , 0 , 0 , 1100 , 720 , bufdc , 0 , 0 ,SRCCOPY); //贴人物行走或站立 SelectObject(bufdc , Walker[dir]); BitBlt(mdc , char_x , char_y , 67 , 91 , bufdc , num*67 , 91 , SRCAND); BitBlt(mdc , char_x , char_y , 67 , 91 , bufdc , num*67 , 0 , SRCPAINT); //将最后的画面显示在窗口上 BitBlt(hdc , 0 ,0 , 1100 , 720 ,mdc , 0 , 0 ,SRCCOPY); //获取当前时间 tPre = GetTickCount(); //动作分解图的图号+1 num++; if (num == 8) { num = 0; } }
五、实现效果
---end
本笔记配套代码已上传,欢迎下载:【Visual C++】游戏编程学习笔记之七--配套代码
You are what you read!与大家共勉~