副标题#e#
1. 实现一个可重用的Windows Class(WEWindow)
下面的内容大概需要你知道一点简朴的Windows措施编写的常识, 假如发明看不太懂, 也不消找许多的资料, 只要看看DirectX SDK中附带的Direct3D Turtorial就行了.
窗体的成立主要是有如下的难点:
1) 动静轮回中的On Idle的处理惩罚函数不太好放.
2) WinMain函数进口处的HInstance需要生存
3) 窗体成立之后的HWND也是需要生存的
为了利便起见,我利用了单件模式作为设计,假如各人有更好的想法,也接待接头
WEWindow类的声明看起来有点像这个样子:
1: /* IRenderable.h : 处理惩罚初始化窗体的类,利用单件模式
2: Programer : Tan Wangda(LeftNotEasy)
3: Email : [email protected]
4: Created Time : 2009 - 8 - 10 */
5:
6: #ifndef _WEWINDOW_H
7: #define _WEWINDOW_H
8:
9: # include "WuguiEngine.h"
10:
11: namespace WuguiEngine
12: {
13: //这是一个Singleton
14: class WEWindow
15: {
16: public:
17: //获得窗体类的实例
18: static WEWindow* GetInstance();
19:
20: //配置HInstance
21: void SetHInstance(HINSTANCE hInst);
22: //获取HInstance
23: HINSTANCE GetHInstance();
24:
25: //配置窗体
26: void SetWEWindow(LPCWSTR szTitle, //窗体标题
27: int iWidth, //宽度
28: int iHeight, //高度
29: DWORD iStyle); //样式
30:
31: void CreateMainWindow();
32:
33: int GetWidth();
34: int GetHeight();
35:
36: //获取窗体句柄
37: HWND GetHWnd();
38: protected:
39: HINSTANCE hInst;
40: HWND hWnd;
41:
42: //窗体标题
43: LPCWSTR szTitle;
44:
45: //宽度
46: int iWidth;
47:
48: //高度
49: int iHeight;
50:
51: //样式
52: DWORD iStyle;
53:
54: //建设窗体
55: void CreateWEWindow(LPCWSTR szTitle, //窗体标题
56: int iWidth, //宽度
57: int iHeight, //高度
58: DWORD iStyle); //样式
59:
60: //进入动静轮回
61: void EnterMessageLoop();
62: private:
63: static WEWindow* weInstance;
64: WEWindow();
65: };
66: }
67:
68: #endif
代码的定名根基上也可以或许看出意义, 别的再给一段利用WEWindow的函数,位于Program.cpp内里
1: INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
2: {
3: //第一步,配置窗体
4: WEWindow* weWindow = WEWindow::GetInstance();
5: weWindow->SetHInstance(hInstance);
6: weWindow->SetWEWindow(L"Hello World", 640, 480, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
7: weWindow->CreateMainWindow();
首先代码获取处WEWindow类的实例,然后配置参数,最后挪用CreateMainWindow就完成了操纵了
#p#副标题#e#
2. 完成一个基本的游戏类(BaseGame)
照旧先给出面文件的声明:
1: class BaseGame : virtual public IDisposed, virtual public IRenderable, virtual public IUpdatable
2: {
3: public:
4: BaseGame(string name); //Constructor
5: GraphicsDevice* GetGraphicsDevice(); //获取GraphicsDevice
6: void Tick(); //一帧完整的游戏
7: virtual void Run() = 0; //开始一场游戏,内里成立动静轮回
8: virtual void Dispose();
9: virtual void Update(DWORD dt);
10: virtual void Render(DWORD dt);
11: virtual void Initialize();
12: void RegisterCamera(BaseCamera* camera);
13: BaseCamera* GetCamera();
14: protected:
15: //要领:
16: void SetTimeUsed(); //配置耗费的时间
17: void ShowFPS();
18: void UpdateCamera(DWORD dt);
19:
20: //变量:
21: GraphicsDevice* pDevice; //指向GraphicsDevice的指针
22: bool isInitialized; //是否初始化
23: BaseCamera* pCamera;
24: };
个中, IDisposed,IRenderable, IUpdatable等I开头的类是接口类,内里具有纯虚函数,重写就可以实现详细的代码了.
#p#分页标题#e#
GraphicsDevice类是我筹备将Direct3D中的IDirect3DDevice9类封装获得,使得利用起来更利便,并且增加一些实用的成果,不外今朝的成果和原来的Device成果差不多,这里就不多说了.
别的值得留意的是Tick函数,其描写的是一帧游戏的进程:
1: void BaseGame::Tick()
2: {
3: SetTimeUsed(); //配置耗费了的时间
4: Update(TimeUsed::LastTickTimeUsed); //挪用更新函数
5: Render(TimeUsed::LastTickTimeUsed); //挪用渲染函数
6: }
Update和Render都是虚函数, 当我们将一个类担任自BaseGame的时候, 也就会挪用相应的Update和Render类.
代码中的TimeUsed是静态类,内里存储了时间相关的参数,好比一帧时间的长度, 从启动游戏到此刻的时间长度等等.
其他的函数都有注释, 假如尚有不太领略的处所,也可以从GoogleCode上面把源代码下下来,很快就会大白了
3. 下面举一个根基的例子,来说明这些措施是奈何一步步举办的
主要的类: TestGame(担任自BaseGame), WEWindow, BaseGame.
1) 在WinMain()中,首先完成成立窗体:
1: INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int)
2: {
3: //第一步,配置窗体
4: WEWindow* weWindow = WEWindow::GetInstance();
5: weWindow->SetHInstance(hInstance);
6: weWindow->SetWEWindow(L"Hello World", 640, 480, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
7: weWindow->CreateMainWindow();
2)在WinMain()中,建设一个TestGame类的实例,而且挪用TestGame->Run(担任自BaseGame的纯虚函数)
1: //第二部,初始化游戏
2: TestGame* game = new TestGame("Matrix");
3:
4: //第三步,开始游戏
5: game->Run();
3)在TestGame->Run()中, 举办初始化与成立动静轮回的操纵
1: void TestGame::Run()
2: {
3: //举办初始化
4: this->Initialize();
5:
6: //进入动静轮回
7: this->EnterMessageLoop();
8: }
4)在TestGame::Initialize()中,完成一些初始化的事情, 为进入游戏的主轮回做好筹备
1: void TestGame::Initialize()
2: {
3: this->BaseGame::Initialize();
4: if (!isInitialized)
5: {
6: InitGeometry();
7: pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
8: pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
9: isInitialized = true;
10: }
11: }
这里的内容,每个差异的游戏逻辑都是纷歧样的, 只有挪用this->BaseGame::initialize()是各个逻辑共有的
5)在TestGame::EnterMessageLoop()中,完成动静轮回的成立,开始游戏的主轮回
1: void TestGame::EnterMessageLoop()
2: {
3: MSG kMessage;
4: HWND hWnd = WEWindow::GetInstance()->GetHWnd();
5:
6: while (1)
7: {
8: if (PeekMessage(&kMessage, hWnd, 0, 0, PM_REMOVE))
9: {
10: if (WM_QUIT == kMessage.message)
11: {
12: Dispose();
13: return;
14: }
15: else
16: {
17: TranslateMessage(&kMessage);
18: DispatchMessage(&kMessage);
19: }
20: }
21: else
22: {
23: Tick();
24: }
25: }
26: }
可以看到,第4行的内容就是单件模式方法挪用WEWindow获取HWnd,这样就乐成了成立了动静轮回了
6)在动静轮回中. 每次都凭据先Update,后Render的方法, 和许多的引擎就较量雷同了.在这个处所,我主要参考了一下XNA的做法
7)完成了!
#p#分页标题#e#
此刻只需要在Initialize和Update,Render中添加相应的代码就可以完成需要的逻辑了.不算太巨大吧~!. 假如需要对这块的内容更清晰的相识,但愿你可以将我的代码下载下来看看.地点在第一篇文章中就有
4. 下集预告:
下一篇文章的主要内容是渲染中,包罗Model, Effect, Texture, Transformation, Camera等类的组织.