当前位置:天才代写 > tutorial > C语言/C++ 教程 > 设计本身的3D图像引擎(3):WuguiEngine之基本轮回的实现

设计本身的3D图像引擎(3):WuguiEngine之基本轮回的实现

2017-11-05 08:00 星期日 所属: C语言/C++ 教程 浏览:585

副标题#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上面把源代码下下来,很快就会大白了

#p#副标题#e#

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等类的组织.

 

    关键字:

天才代写-代写联系方式