接上篇游戏编程入门(三):绘制图形图像。下面这篇文章会和大家分享如何使用键盘和鼠标控制游戏。
本文内容包括:
- 如何有效地检测和响应键盘输入
- 如何处理鼠标输入
- 如何开发带有动画图形对象的程序,并且可以使用键盘和鼠标来控制动画图形对象
用户输入设备
输入设备是允许用户与一个游戏进行交互的物理硬件。
所有输入设备都执行相同的操作:将用户提供的信息转换为一种计算机可以理解的格式。输入设备在用户与游戏之间建立联系。
有三种主要的输入设备类型:
键盘输入
我们知道,在Win32 API 中大量使用消息来提交有关各种事件的通知,如创建窗口、破坏窗口、激活窗口、使用窗口等,这个相同的信息传递系统也用来传递在键盘上按键的通知。
Win32 API 定义了名为 WM_KEYDOWN 和 WM_KEYUP 的消息,只需要按下或释放一个键,它们就会通知你。
但是,标准的Windows消息传递系统 传输键盘消息的速度慢的令人难以忍受,而游戏对快速响应的控制要求很高。
跟踪鼠标
在移动鼠标的时候,将会引发一系列事件,这些事件与键盘所引发的那些事件非常相似。
实际上,Win32 API 包括了一系列用来传送鼠标事件的鼠标消息,与键盘消息传递键盘事件的方式相似。
在前面,我们了解到 Win32键盘消息不适合为游戏提供有效输入的任务。而鼠标消息并不属于这种情况,通过消息处理鼠标事件的Win32方法对游戏很适用。
下面是用来向Windows程序通报鼠标事件的鼠标消息:
- WM_MOUSEMOVE:任何鼠标移动
- WM_LBUTTONDOWN:按下鼠标左键
- WM_LBUTTONUP:释放鼠标左键
- WM_RBUTTONDOWN:按下鼠标右键
- WM_RBUTTONUP:释放鼠标右键
- WM_MBUTTONDOWN:按下鼠标中键
- WM_MBUTTONUP:释放鼠标中键
实现鼠标拖动功能:单击鼠标的一个按钮,再按下一个按钮,之后释放这个按钮。通过记录 按下和释放鼠标按钮的时间并查看这段时间内的鼠标移动,就可以实现鼠标拖动功能。
在前面讲游戏引擎的时候,我们定义了一个HandleEvent( )方法,方法的原型如下:
LRESULT GameEngine::HandleEvent(HWND hWindow,UINT msg,WPARAM wParam,LPARAM lParam);
wParam 和 lParam参数是随着每一个Windows消息一起发送的,它们包含了消息专用的信息。
鼠标指针的位置是鼠标的一个重要性质,对于鼠标消息来说,lParam包含了鼠标指针的XY位置(包含其在低位和高位字节中)。
下面这个例子,从WM_MOUSEMOVE 消息处理程序的 lParam 参数中提取鼠标位置:
case WM_MOUSEMOVE:
WORD x=LOWORD(lParam);
WORD y=HIWORD(lParam); return 0;
而鼠标消息的wParam 参数包含有关鼠标按钮状态的信息以及一些键盘信息。更具体的说,wParam 使我们知道三个按钮(鼠标左键,中键,右键)中是否有一个处于被按下的状态,是否按下了键盘上的Shift键或Ctrl键。
下面是在处理鼠标消息是,用来解释wParam 参数值的一些常量:
- MK_LBUTTON:按下了鼠标左键
- MK_RBUTTON:按下了鼠标右键
- MK_MBUTTON:按下了鼠标中键
- MK_SHIFT:按下了Shift键
- MK_CONTROL:按下了Ctrl键
可以通过检查这些鼠标常量,以便确定在鼠标移动的过程中是否按下了一个按钮或键。
实际上,这些常量也可以在wParam 参数中将它们组合在一起,要想检查单个标志的存在性,必须使用按位AND 运算符(&)来检查标志是否存在。
下面是检查wParam 以查看是否按下鼠标右键的一个例子:
if(wParam & HK_RBUTTON)
向 游戏引擎 添加输入支持
因为我们已经开发了一个游戏引擎来完成与游戏管理有关的各种任务,所以将用户输入处理结合到游戏引擎中是很有意义的。处理用户输入的某个方面是游戏所特有的,因此必须在每个单独游戏的代码中进行处理。不过,键盘处理和鼠标处理存在一些通用的地方,可以将它们结合到游戏引擎中,从而简化特定游戏代码所需要完成的工作。
添加键盘支持
在前面我们已经了解到使用消息来处理键盘的标准Windows方法对于游戏来说是不够的(因为太慢了)。
处理键盘输入的一种更好的方法是反复检查键盘的状态,查看是否按下了特定的键,然后做出相应的反应。
使用这个策略,键盘输入处理的很多工作就转移给了游戏代码,这意味着游戏引擎主要只负责调用一个键盘处理函数,使游戏有机会相应按键。
下面是这个函数的原型:
void HandleKeys();
HandleKeys( ) 函数必须作为游戏代码的一部分提供,因此它不包括在游戏引擎中。如果不希望游戏支持键盘输入,那么只需要使HandleKeys( ) 函数保持为空白即可。
当然,游戏引擎必须确定以足够快的速度调用HandleKeys( ) 函数,从而使游戏能够立即响应。
这是在游戏引擎代码(GameEngine.cpp)中的WinMain( )函数中实现的。下面是对这个函数所作的修改:
if(iTickCount > iTickTrigger)
{
iTickTrigger = iTickCount GameEngine::GetEngine()->GetFrameDelay();
HandleKeys();
GameCycle();
}
对WinMain( ) 代码的唯一一处改动是对HandleKeys( )函数的新调用。注意,这个调用刚好在GameCycle( ) 函数之前发生,这表示游戏在每个周期之前都会获得相应键盘输入的机会。
不要忘了,处理键盘输入的具体细节是在各个特定的游戏中实现的,也就是在创建自己的HandleKeys( )函数时。
添加鼠标支持
要想支持鼠标输入,游戏必须支持以下3个函数,它们由游戏引擎在接受到鼠标事件时调用。
鼠标处理函数如下:
void MouseButtonDown(int x,int y,BOOL bLeft); void MouseButtonUp(int x,int y,BOOL bLeft); boid MouseMove(int x,int y);
要想将鼠标消息与这些鼠标处理函数联系起来,游戏引擎必须检查适当的鼠标消息并作出响应的响应。
下面这段代码包括了GameEngine::HandleEvent( )方法的一部分新内容,它们负责处理传递到主游戏窗口的鼠标消息。
CASE WM_LBUTTONDOWN: MouseButtonDown(LOWORD(lParam), HIWORD(lParam),TRUE); return 0; CASE WM_LBUTTONUP: MouseButtonUp(LOWORD(lParam), HIWORD(lParam),TRUE); return 0; CASE WM_RBUTTONDOWN: MouseButtonDown(LOWORD(lParam), HIWORD(lParam),FALSE); return 0; CASE WM_RBUTTONDOWN: MouseButtonUp(LOWORD(lParam), HIWORD(lParam),FALSE); return 0; CASE WM_MOUSEMOVE: MouseMove(LOWORD(lParam), HIWORD(lParam)); return 0;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
鼠标按钮函数的最后一个参数是一个布尔值,它标识了事件中是否涉及鼠标左键(TRUE)或鼠标右键(FALSE)
修改 Bitmap 类 使 位图透明
从技术上讲,这个修改与输入没有任何关系。
位图透明,可以使位图不是总显示为方块图形对象(虽然位图都是方块图形对象,但我们不一定必须按照这种方式来绘制)。
透明的意思是可以将一种颜色指定为透明色,然后使用这种颜色来表示一个位图的透明部分。在绘制位图时,不会绘制透明色的像素,背景将会透过它显示出来。
从创建图形的角度来看,创建带有透明位图的方法是选择一种图形中没有使用的颜色,例如深紫色,然后使用深紫色来填充位图中需要显示为透明的区域。
游戏开发群体在透明色的使用上有一些争论。过去,紫色(RGB:255,0, 255)是表示透明的标准颜色。现在,大多数商业3D游戏都使用纯黑色(RGB:0,0, 0)、纯蓝(RGB:0, 0, 255)或中度灰色(RGB:128, 128, 128)作为透明色。
本系列所有的例子,都使用紫色作为透明色,但是只要在某个特定游戏的图形中保持一致,就可以任意选择使用没有使用的颜色。
在游戏引擎中,实现位图透明的诀窍是扩展现有的 Bitmap::Draw( ) 方法,使之支持透明。这通过添加两个新的参数实现。
- bTran:布尔值,表示是否将位图绘制为透明的。FALSE:没有使用透明
- crTransColor:位图的透明色
对Draw( ) 的唯一一个重大更改是检查透明参数 bTran ,如果这个参数为TRUE,则使用Win32 的 TransparentBlt( ) 函数绘制带有透明的位图。否则,就像往常一样使用 BitBlt( ) 函数绘制不带透明的位图。
TransparentBlt( ) 函数,需要包括一个名为msimg32.lib的库,记得在工程”->”设置”->在”Project Setting”中,”对象/库模块”中,增加Msimg32.lib。
开发 UFO 示例
本文将着重讨论一个名为 UFO 的实例,虽然从技术上讲,这个程序不是一个游戏,但它是到目前为止读者所看到的最接近于游戏的程序。
它包括一个可以使用键盘或(和)鼠标控制的飞碟,可以使飞碟在一个位图背景图像上飞行。
本程序,在每一个游戏周期都重新绘制位图,因此通过改变位图的位置并不断重新绘制,就创建了UFO移动的效果。
UFO目录结构与效果图
UFO目录结构:

UFO效果图:

UFO 源代码
Resource.h
#define IDI_UFO 1000 #define IDI_UFO_SM 1001 #define IDB_BACKGROUND 2000 #define IDB_SAUCER 2001
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
UFO.h
#pragma once #include #include "Resource.h" #include "GameEngine.h" #include "Bitmap.h" HINSTANCE g_hInstance; GameEngine* g_pGame; const int g_iMAXSPEED = 8; Bitmap* g_pBackground; Bitmap* g_pSaucer; int g_iSaucerX, g_iSaucerY; int g_iSpeedX, g_iSpeedY;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
Bitmap.h
#pragma once // // 包含的文件
// #include // // Bitmap 类
// class Bitmap {
protected:
// 成员变量 HBITMAP m_hBitmap; //位图句柄
int m_iWidth, m_iHeight;//位图的宽和高
// 帮助器方法,用来释放与位图有关的内存并清除位图句柄
void Free();
public:
// 构造函数和析构函数 3个构造函数分别对应一种创建位图的不同方法 Bitmap();
//从一个文件中创建位图 Bitmap(HDC hDC, LPTSTR szFileName);
//从一个资源中创建位图 Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance);
//创建纯色的空白位图 Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor = RGB(0, 0, 0));
virtual ~Bitmap();
// 常规方法 create()用来处理加载位图数据并将其创建为一个GDI 对象,3个Create分别对应3个构造函数 BOOL Create(HDC hDC, LPTSTR szFileName); BOOL Create(HDC hDC, UINT uiResID, HINSTANCE hInstance); BOOL Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor);
//提供将位图绘制到设备环境上的方法 bTrans=FALSE,不将位图绘制成透明
void Draw(HDC hDC, int x, int y, BOOL bTrans = FALSE, COLORREF crTransColor = RGB(255, 0, 255));
int GetWidth() {
return m_iWidth;
};
int GetHeight() {
return m_iHeight;
};
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
GameEngine.h
#pragma once /*该头文件仅编译一次(因为同一头文件会在许多源文件中多次引用。如 果没有指定编译一次,则编译时出现重定义错误。*/ #include int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); BOOL GameInitialize(HINSTANCE hInstance); void GameStart(HWND hWindow); void GameEnd(); void GameActivate(HWND hWindow); void GameDeactivate(HWND hWindow); void GamePaint(HDC hDC); void GameCycle(); void HandleKeys(); void MouseButtonDown(int x, int y, BOOL bLeft); void MouseButtonUp(int x, int y, BOOL bLeft); void MouseMove(int x, int y); class GameEngine
{
protected: static GameEngine* m_pGameEngine; HINSTANCE m_hInstance; HWND m_hWindow; TCHAR m_szWindowClass[32]; TCHAR m_szTitle[32]; WORD m_wIcon, m_wSmallIcon; int m_iWidth, m_iHeight; int m_iFrameDelay; BOOL m_bSleep; public: GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass, LPTSTR szTitle,
WORD wIcon, WORD wSmallIcon, int iWidth = 640, int iHeight = 480);
virtual ~GameEngine(); static GameEngine* GetEngine()
{ return m_pGameEngine;
}; BOOL Initialize(int iCmdShow); LRESULT HandleEvent(HWND hWindow, UINT msg, WPARAM wParam,
LPARAM lParam); void ErrorQuit(LPTSTR szErrorMsg); HINSTANCE GetInstance()
{ return m_hInstance;
};
HWND GetWindow()
{ return m_hWindow;
}; void SetWindow(HWND hWindow)
{
m_hWindow = hWindow;
};
LPTSTR GetTitle()
{ return m_szTitle;
};
WORD GetIcon()
{ return m_wIcon;
};
WORD GetSmallIcon()
{ return m_wSmallIcon;
}; int GetWidth()
{ return m_iWidth;
}; int GetHeight()
{ return m_iHeight;
}; int GetFrameDelay()
{ return m_iFrameDelay;
}; void SetFrameRate(int iFrameRate)
{
m_iFrameDelay = 1000 /iFrameRate;
}; BOOL GetSleep()
{ return m_bSleep;
}; void SetSleep(BOOL bSleep)
{
m_bSleep = bSleep;
};
};
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
UFO.cpp
#include "UFO.h" BOOL GameInitialize(HINSTANCE hInstance)
{ g_pGame = new GameEngine(hInstance, TEXT("UFO"),
TEXT("UFO"), IDI_UFO, IDI_UFO_SM, 500, 400); if (g_pGame == NULL) return FALSE; g_pGame->SetFrameRate(30); g_hInstance = hInstance; return TRUE;
} void GameStart(HWND hWindow)
{ HDC hDC = GetDC(hWindow);
g_pBackground = new Bitmap(hDC, IDB_BACKGROUND, g_hInstance);
g_pSaucer = new Bitmap(hDC, IDB_SAUCER, g_hInstance); g_iSaucerX = 250 - (g_pSaucer->GetWidth() / 2);
g_iSaucerY = 200 - (g_pSaucer->GetHeight() / 2);
g_iSpeedX = 0; g_iSpeedY = 0;
} void GameEnd()
{ delete g_pBackground;
delete g_pSaucer; delete g_pGame;
} void GameActivate(HWND hWindow)
{
} void GameDeactivate(HWND hWindow)
{
} void GamePaint(HDC hDC)
{ g_pBackground->Draw(hDC, 0, 0); g_pSaucer->Draw(hDC, g_iSaucerX, g_iSaucerY, TRUE);
} void GameCycle()
{ g_iSaucerX = min(500 - g_pSaucer->GetWidth(), max(0, g_iSaucerX g_iSpeedX));
g_iSaucerY = min(320, max(0, g_iSaucerY g_iSpeedY)); InvalidateRect(g_pGame->GetWindow(), NULL, FALSE);
} void HandleKeys()
{ if (GetAsyncKeyState(VK_LEFT) < 0)
g_iSpeedX = max(-g_iMAXSPEED, --g_iSpeedX); else if (GetAsyncKeyState(VK_RIGHT) < 0)
g_iSpeedX = min(g_iMAXSPEED, g_iSpeedX); if (GetAsyncKeyState(VK_UP) < 0)
g_iSpeedY = max(-g_iMAXSPEED, --g_iSpeedY); else if (GetAsyncKeyState(VK_DOWN) < 0)
g_iSpeedY = min(g_iMAXSPEED, g_iSpeedY);
} void MouseButtonDown(int x, int y, BOOL bLeft)
{ if (bLeft)
{ g_iSaucerX = x - (g_pSaucer->GetWidth() / 2);
g_iSaucerY = y - (g_pSaucer->GetHeight() / 2);
} else { g_iSpeedX = 0;
g_iSpeedY = 0;
}
} void MouseButtonUp(int x, int y, BOOL bLeft)
{
} void MouseMove(int x, int y)
{
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
Bitmap.cpp
#include "Bitmap.h" Bitmap::Bitmap()
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
} Bitmap::Bitmap(HDC hDC, LPTSTR szFileName)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, szFileName);
} Bitmap::Bitmap(HDC hDC, UINT uiResID, HINSTANCE hInstance)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, uiResID, hInstance);
} Bitmap::Bitmap(HDC hDC, int iWidth, int iHeight, COLORREF crColor)
: m_hBitmap(NULL), m_iWidth(0), m_iHeight(0)
{
Create(hDC, iWidth, iHeight, crColor);
}
Bitmap::~Bitmap()
{
Free();
} void Bitmap::Free()
{ if (m_hBitmap != NULL)
{ DeleteObject(m_hBitmap);
m_hBitmap = NULL;
}
} BOOL Bitmap::Create(HDC hDC, LPTSTR szFileName)
{ Free(); HANDLE hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return FALSE; BITMAPFILEHEADER bmfHeader;
DWORD dwBytesRead; BOOL bOK = ReadFile(hFile, &bmfHeader, sizeof(BITMAPFILEHEADER),
&dwBytesRead, NULL); if ((!bOK) || (dwBytesRead != sizeof(BITMAPFILEHEADER)) ||
(bmfHeader.bfType != 0x4D42))
{
CloseHandle(hFile); return FALSE;
}
BITMAPINFO* pBitmapInfo = (new BITMAPINFO); if (pBitmapInfo != NULL)
{ bOK = ReadFile(hFile, pBitmapInfo, sizeof(BITMAPINFOHEADER),
&dwBytesRead, NULL); if ((!bOK) || (dwBytesRead != sizeof(BITMAPINFOHEADER)))
{
CloseHandle(hFile);
Free(); return FALSE;
} m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight; pBitmapInfo->bmiHeader.biSizeImage =
m_iHeight*m_iWidth*((int)pBitmapInfo->bmiHeader.biBitCount)/8; PBYTE pBitmapBits;
m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
(PVOID*)&pBitmapBits, NULL, 0); if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
{
SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN);
bOK = ReadFile(hFile, pBitmapBits, pBitmapInfo->bmiHeader.biSizeImage,
&dwBytesRead, NULL); if (bOK) return TRUE;
}
} Free(); return FALSE;
} BOOL Bitmap::Create(HDC hDC, UINT uiResID, HINSTANCE hInstance)
{ Free(); HRSRC hResInfo = FindResource(hInstance, MAKEINTRESOURCE(uiResID), RT_BITMAP); if (hResInfo == NULL) return FALSE; HGLOBAL hMemBitmap = LoadResource(hInstance, hResInfo); if (hMemBitmap == NULL) return FALSE; PBYTE pBitmapImage = (BYTE*)LockResource(hMemBitmap); if (pBitmapImage == NULL)
{
FreeResource(hMemBitmap); return FALSE;
} BITMAPINFO* pBitmapInfo = (BITMAPINFO*)pBitmapImage;
m_iWidth = (int)pBitmapInfo->bmiHeader.biWidth;
m_iHeight = (int)pBitmapInfo->bmiHeader.biHeight; pBitmapInfo->bmiHeader.biSizeImage =
m_iHeight*m_iWidth*((int)pBitmapInfo->bmiHeader.biBitCount)/8; PBYTE pBitmapBits;
m_hBitmap = CreateDIBSection(hDC, pBitmapInfo, DIB_RGB_COLORS,
(PVOID*)&pBitmapBits, NULL, 0); if ((m_hBitmap != NULL) && (pBitmapBits != NULL))
{ const PBYTE pTempBits = pBitmapImage pBitmapInfo->bmiHeader.biSize pBitmapInfo->bmiHeader.biClrUsed * sizeof(RGBQUAD);
CopyMemory(pBitmapBits, pTempBits, pBitmapInfo->bmiHeader.biSizeImage); UnlockResource(hMemBitmap);
FreeResource(hMemBitmap); return TRUE;
} UnlockResource(hMemBitmap);
FreeResource(hMemBitmap);
Free(); return FALSE;
} BOOL Bitmap::Create(HDC hDC, int iWidth, int iHeight, COLORREF crColor)
{ m_hBitmap = CreateCompatibleBitmap(hDC, iWidth, iHeight); if (m_hBitmap == NULL) return FALSE; m_iWidth = iWidth;
m_iHeight = iHeight; HDC hMemDC = CreateCompatibleDC(hDC); HBRUSH hBrush = CreateSolidBrush(crColor); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap); RECT rcBitmap = { 0, 0, m_iWidth, m_iHeight };
FillRect(hMemDC, &rcBitmap, hBrush); SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
DeleteObject(hBrush); return TRUE;
} void Bitmap::Draw(HDC hDC, int x, int y, BOOL bTrans, COLORREF crTransColor)
{ if (m_hBitmap != NULL)
{ HDC hMemDC = CreateCompatibleDC(hDC); HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap); if (bTrans)
TransparentBlt(hDC, x, y, GetWidth(), GetHeight(), hMemDC, 0, 0,
GetWidth(), GetHeight(), crTransColor); else BitBlt(hDC, x, y, GetWidth(), GetHeight(), hMemDC, 0, 0, SRCCOPY); SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
GameEngine.cpp
#include "GameEngine.h" GameEngine *GameEngine::m_pGameEngine = NULL; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
MSG msg; static int iTickTrigger = 0; int iTickCount; if (GameInitialize(hInstance)) { if (!GameEngine::GetEngine()->Initialize(iCmdShow)) return FALSE; while (TRUE)
{ if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{ if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
} else { if (!GameEngine::GetEngine()->GetSleep())
{ iTickCount = GetTickCount(); if (iTickCount > iTickTrigger)
{
iTickTrigger = iTickCount
GameEngine::GetEngine()->GetFrameDelay();
HandleKeys(); GameCycle();
}
}
}
} return (int)msg.wParam;
} GameEnd(); return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{ return GameEngine::GetEngine()->HandleEvent(hWindow, msg, wParam, lParam);
} GameEngine::GameEngine(HINSTANCE hInstance, LPTSTR szWindowClass,
LPTSTR szTitle, WORD wIcon, WORD wSmallIcon, int iWidth, int iHeight)
{ m_pGameEngine = this;
m_hInstance = hInstance;
m_hWindow = NULL; if (lstrlen(szWindowClass) > 0)
lstrcpy(m_szWindowClass, szWindowClass); if (lstrlen(szTitle) > 0)
lstrcpy(m_szTitle, szTitle);
m_wIcon = wIcon;
m_wSmallIcon = wSmallIcon;
m_iWidth = iWidth;
m_iHeight = iHeight;
m_iFrameDelay = 50; m_bSleep = TRUE;
}
GameEngine::~GameEngine()
{
} BOOL GameEngine::Initialize(int iCmdShow)
{
WNDCLASSEX wndclass; wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_hInstance;
wndclass.hIcon = LoadIcon(m_hInstance,
MAKEINTRESOURCE(GetIcon()));
wndclass.hIconSm = LoadIcon(m_hInstance,
MAKEINTRESOURCE(GetSmallIcon()));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = m_szWindowClass; if (!RegisterClassEx(&wndclass)) return FALSE; int iWindowWidth = m_iWidth GetSystemMetrics(SM_CXFIXEDFRAME) * 2,
iWindowHeight = m_iHeight GetSystemMetrics(SM_CYFIXEDFRAME) * 2 GetSystemMetrics(SM_CYCAPTION); if (wndclass.lpszMenuName != NULL)
iWindowHeight = GetSystemMetrics(SM_CYMENU); int iXWindowPos = (GetSystemMetrics(SM_CXSCREEN) - iWindowWidth) / 2,
iYWindowPos = (GetSystemMetrics(SM_CYSCREEN) - iWindowHeight) / 2; m_hWindow = CreateWindow(m_szWindowClass, m_szTitle, WS_POPUPWINDOW |
WS_CAPTION | WS_MINIMIZEBOX, iXWindowPos, iYWindowPos, iWindowWidth,
iWindowHeight, NULL, NULL, m_hInstance, NULL); if (!m_hWindow) return FALSE; ShowWindow(m_hWindow, iCmdShow);
UpdateWindow(m_hWindow); return TRUE;
} LRESULT GameEngine::HandleEvent(HWND hWindow, UINT msg, WPARAM wParam, LPARAM lParam)
{ switch (msg)
{ case WM_CREATE: SetWindow(hWindow);
GameStart(hWindow); return 0; case WM_SETFOCUS: GameActivate(hWindow);
SetSleep(FALSE); return 0; case WM_KILLFOCUS: GameDeactivate(hWindow);
SetSleep(TRUE); return 0; case WM_PAINT:
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hWindow, &ps); GamePaint(hDC);
EndPaint(hWindow, &ps); return 0; case WM_LBUTTONDOWN: MouseButtonDown(LOWORD(lParam), HIWORD(lParam), TRUE); return 0; case WM_LBUTTONUP: MouseButtonUp(LOWORD(lParam), HIWORD(lParam), TRUE); return 0; case WM_RBUTTONDOWN: MouseButtonDown(LOWORD(lParam), HIWORD(lParam), FALSE); return 0; case WM_RBUTTONUP: MouseButtonUp(LOWORD(lParam), HIWORD(lParam), FALSE); return 0; case WM_MOUSEMOVE: MouseMove(LOWORD(lParam), HIWORD(lParam)); return 0; case WM_DESTROY: GameEnd();
PostQuitMessage(0); return 0;
} return DefWindowProc(hWindow, msg, wParam, lParam);
} void GameEngine::ErrorQuit(LPTSTR szErrorMsg)
{
MessageBox(GetWindow(), szErrorMsg, TEXT("Critical Error"), MB_OK | MB_ICONERROR);
PostQuitMessage(0);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
源代码 下载
http://pan.baidu.com/s/1ge2Vzr1