6.1-6.2

 

C++封装游戏编程大师技巧

由于阿哲VS自己在以前也是自己做了C++封装这两本书,而我觉得确实夹生,DX不透,使用各种引擎夹生,所以认为他说的有道理,所以,要进行一下。决定一边学习一边总结,希望别半路总结不下去了,

--------20121014

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

6_1,DDRAW初始化(20121014)

 

这个封装虽然简单,是以前封装的,但是当时封装时并不轻松,费了N个脑细胞,3个小时,可能是基础太差的缘故吧。

其实无非说了两点,第一点,是创建DDRAW对象,第二步是与WINDOWS协作,这些是设备基本不变的,(当然可以传递参数),故把它们封装起来,

分为COMMON.H, DDraw_Interface.h, DDraw_Interface.cppmain.cpp

COMMON.H

 

/*

 

 

公共部分

*/

#define WIN32_LEAN_AND_MEAN  // just say no to MFC

#define INITGUID

 

#include <windows.h>   // include important windows stuff

#include <windowsx.h>

#include <mmsystem.h>

#include <iostream> // include important C/C++ stuff

#include <conio.h>

#include <stdlib.h>

#include <malloc.h>

#include <memory.h>

#include <string.h>

#include <stdarg.h>

#include <stdio.h>

#include <math.h>

#include <io.h>

#include <fcntl.h>

 

#include <ddraw.h>

 

// DEFINES

 

// defines for windows

#define WINDOW_CLASS_NAME                                 "WINCLASS1"

#define SCREEN_WIDTH                                       640

#define    SCREEN_HEIGHT                                          480

#define    SCREEN_BPP                                                 8

#define    MAX_COLORS                                               256

 

typedef unsigned short                                      USHORT;

typedef    unsigned short                                    WORD;

typedef unsigned char                                       UCHAR;

typedef unsigned char                                       BYTE;

 

 

 

// MACROS /

 

#define KEYDOWN(vk_code)                                 ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

#define KEYUP(vk_code)                                        ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)

 

#define DD_INIT_STRUCT( ddstruct )                     { memset( &ddstruct, 0, sizeof( ddstruct ) ); ddstruct.dwSize = sizeof( ddstruct ); }

 

当然, COMMON.H肯定不好,因为输入部分将来会封装到DXINPUT中,先将就下吧。

 

 

DDraw_Interface.h

#include "common.h"

 

class DDRAW_Interface

{

private:

 

 

       LPDIRECTDRAW7                            m_lpdd;                //ddraw对象

 

       HWND                                      m_hWnd;                     //窗口句柄

       DWORD                                    m_dwFlags;           //DDRAWWINDOWS协同方式标志

 

public:

       DDRAW_Interface();

       ~DDRAW_Interface();

 

       HRESULT InitDDraw( HWND hWnd, DWORD dwFlags );

};

       其中核心肯定是在InitDDraw中,设置了三个成员变量m_lpdd用于外界传参数

 

DDraw_Interface.CPP代码如下

#include "DDraw_Interface.h"

 

DDRAW_Interface::DDRAW_Interface()

{

       m_lpdd = NULL;

       m_hWnd = NULL;

       m_dwFlags = 0;

}

 

DDRAW_Interface::~DDRAW_Interface()

{

       if( m_lpdd )

       {

              m_lpdd->Release();

              m_lpdd = NULL;

       }

 

}

      

HRESULT DDRAW_Interface::InitDDraw(HWND hWnd, DWORD dwFlags)

{

       m_dwFlags = dwFlags;

       if( FAILED( DirectDrawCreateEx( NULL, ( void ** ) & m_lpdd, IID_IDirectDraw7, NULL ) ) ) 

              return ( 0 );

 

       m_lpdd->SetCooperativeLevel( hWnd,  m_dwFlags );

 

       return TRUE;

}

 

Main.cpp代码如下

 

#include "common.h"

#include "DDraw_Interface.h"

#include <windef.h>

// GLOBALS

HWND      main_window_handle = NULL; // globally track main window

HINSTANCE hinstance_app      = NULL; // globally track hinstance

 

char buffer[80];                    // general printing buffer

 

// FUNCTIONS //

LRESULT CALLBACK WindowProc(HWND hwnd,

                                                            UINT msg,

                            WPARAM wparam,

                            LPARAM lparam)

{

// this is the main message handler of the system

PAINTSTRUCT                 ps;             // used in WM_PAINT

HDC                                     hdc; // handle to a device context

char buffer[80];        // used to print strings

 

// what is the message

switch(msg)

         {      

         case WM_CREATE:

        {

                   // do initialization stuff here

        // return success

                   return(0);

                   } break;

  

         case WM_PAINT:

                   {

                   // simply validate the window

          hdc = BeginPaint(hwnd,&ps);   

       

        // end painting

        EndPaint(hwnd,&ps);

 

        // return success

                   return(0);

                } break;

 

         case WM_DESTROY:

                   {

 

                   // kill the application, this sends a WM_QUIT message

                   PostQuitMessage(0);

 

        // return success

                   return(0);

                   } break;

 

         default:break;

 

    } // end switch

 

// process any messages that we didn't take care of

return (DefWindowProc(hwnd, msg, wparam, lparam));

 

} // end WinProc

 

///

 

int Game_Main(void *parms = NULL,int num_parms = 0)

{

// this is the main loop of the game, do all your processing

// here

 

// for now test if user is hitting ESC and send WM_CLOSE

if (KEYDOWN(VK_ESCAPE))

   SendMessage(main_window_handle,WM_CLOSE,0,0);

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Main

 

 

int Game_Init(void *parms = NULL,int num_parms = 0)

{

// this is called once after the initial window is created and

// before the main event loop is entered, do all your initialization

// here

 

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Init

 

/

 

int Game_Shutdown(void *parms = NULL,int num_parms = 0)

{

// this is called after the game is exited and the main event

// loop while is exited, do all you cleanup and shutdown here

 

 

 

// return success or failure or your own return code here

return(1);

 

} // end Game_Shutdown

 

// WINMAIN

int WINAPI WinMain(      HINSTANCE hinstance,

                                               HINSTANCE hprevinstance,

                                               LPSTR lpcmdline,

                                               int ncmdshow)

{

 

WNDCLASSEX winclass; // this will hold the class we create

HWND        hwnd; // generic window handle

MSG                      msg;             // generic message

HDC        hdc;      // graphics device context

 

// first fill in the window class stucture

winclass.cbSize         = sizeof(WNDCLASSEX);

winclass.style                      = CS_DBLCLKS | CS_OWNDC |

                          CS_HREDRAW | CS_VREDRAW;

winclass.lpfnWndProc       = WindowProc;

winclass.cbClsExtra           = 0;

winclass.cbWndExtra                 = 0;

winclass.hInstance             = hinstance;

winclass.hIcon                    = LoadIcon(NULL, IDI_APPLICATION);

winclass.hCursor                = LoadCursor(NULL, IDC_ARROW);

winclass.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);

winclass.lpszMenuName  = NULL;

winclass.lpszClassName   = WINDOW_CLASS_NAME;

winclass.hIconSm        = LoadIcon(NULL, IDI_APPLICATION);

 

// save hinstance in global

hinstance_app = hinstance;

 

// register the window class

if (!RegisterClassEx(&winclass))

         return(0);

 

// create the window

if (!(hwnd = CreateWindowEx(NULL,                 // extended style

                            WINDOW_CLASS_NAME,     // class

                                                            "T3D Game Console Version 1.0", // title

                                                            WS_OVERLAPPEDWINDOW | WS_VISIBLE,

                                                           0,0,     // initial x,y

                                                            400,300, // initial width, height

                                                            NULL,         // handle to parent

                                                            NULL,         // handle to menu

                                                            hinstance,// instance of this application

                                                            NULL)))    // extra creation parms

return(0);

 

// save main window handle

main_window_handle = hwnd;

 

//?始化DDRAW

DDRAW_Interface  * ddraw = new DDRAW_Interface();

 

ddraw->InitDDraw( hwnd, DDSCL_NORMAL );

// initialize game here

Game_Init();

 

// enter main event loop

while(TRUE)

         {

    // test if there is a message in queue, if so get it

         if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

            {

            // test if this is a quit

       if (msg.message == WM_QUIT)

           break;

        

            // translate any accelerator keys

            TranslateMessage(&msg);

 

            // send the message to the window proc

            DispatchMessage(&msg);

            } // end if

   

       // main game processing goes here

       Game_Main();

      

         } // end while

 

// closedown game here

Game_Shutdown();

 

delete ddraw;

 

// return to Windows like this

return(msg.wParam);

 

} // end WinMain

 

///

肯定了,由于这个是初始函数,所以,NEW一个对象,在GAME_INIT()前进行,并且,在GAME_SHUTDOWN()之后进行delete,

代码相应部分如下。

 

//初始化DDRAW

DDRAW_Interface  * ddraw = new DDRAW_Interface();

 

ddraw->InitDDraw( hwnd, DDSCL_NORMAL );

// initialize game here

Game_Init();

 

// enter main event loop

while(TRUE)

         {

    // test if there is a message in queue, if so get it

         if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

            {

            // test if this is a quit

       if (msg.message == WM_QUIT)

           break;

        

            // translate any accelerator keys

            TranslateMessage(&msg);

 

            // send the message to the window proc

            DispatchMessage(&msg);

            } // end if

   

       // main game processing goes here

       Game_Main();

      

         } // end while

 

// closedown game here

Game_Shutdown();

 

delete ddraw;

这一部分到这里结束了,

 

附图

总结:无非就是DDRAW的初始化和与WINDOWS的协作,当然,还要看看在主函数里,写在哪里,才能和WINAPI结合,另外,如果用VS2010或一些版本,注意在WINNT.H中,要加上#define POINT_64 _ptr64

还要记得在INCLUDE,LIB中,找到DX相应的文件夹,MULTIBYTE形式,以及加上winmm.libddraw.lib,如果找不到libci.lib,直接在忽略库中加上即OK


6_2设置模式(20121014)

首先感叹下,封装起来的东西才是自己的,要不老得翻书,还是那个起点。看明白和写出来是两码事。

首先试一下原来的代码,6_1的代码,再对比下6_2有什么差别,应该只有设置模式这一部分,在协调级这里也根据全屏或者窗口改成全屏了,改动结果如下

DDRAW_Interface.h代码如下

#include "common.h"

 

class DDRAW_Interface

{

private:

 

 

         LPDIRECTDRAW7                             m_lpdd;                     //ddraw对象

 

         HWND                                                    m_hWnd;                           //窗口句柄       

DWORD                                                 m_dwCooprativeFlags;             //DDRAWWINDOWS协同方式标志    

DWORD                                                 m_dwHeight;

         DWORD                                                 m_dwWidth;

         DWORD                                                 m_dwBPP;

         DWORD                                                 m_dwRefreshRate;

         DWORD                                                 m_dwDisplayModeFlags;

 

 

public:

         DDRAW_Interface();

         ~DDRAW_Interface();

 

         HRESULT InitDDraw(HWND hWnd, DWORD dwCooperativeFlags, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD DisplayModeFlags );

};

        

DDRAW_Interface.cpp代码如下

#include "DDraw_Interface.h"

 

DDRAW_Interface::DDRAW_Interface()

{

         m_lpdd = NULL;

         m_hWnd = NULL;

         m_dwCooprativeFlags = 0;

         m_dwWidth = 0;

         m_dwHeight = 0;

         m_dwBPP = 0;

         m_dwRefreshRate = 0;

         m_dwDisplayModeFlags = 0;

}

 

DDRAW_Interface::~DDRAW_Interface()

{

         if( m_lpdd )

         {

                   m_lpdd->Release();

                   m_lpdd = NULL;

         }

 

}

        

HRESULT DDRAW_Interface::InitDDraw(HWND hWnd, DWORD dwCooperativeFlags, DWORD dwWidth, DWORD dwHeight, DWORD dwBPP, DWORD dwRefreshRate, DWORD DisplayModeFlags )

{

         m_hWnd = hWnd;

         m_dwCooprativeFlags = dwCooperativeFlags;

         m_dwWidth = dwWidth;

         m_dwHeight = dwHeight;

         m_dwBPP = dwBPP;

         m_dwRefreshRate = dwRefreshRate;

         m_dwDisplayModeFlags = DisplayModeFlags;

         if( FAILED( DirectDrawCreateEx( NULL, (void ** ) & m_lpdd, IID_IDirectDraw7, NULL ) ) )        

                   return ( 0 );

 

         m_lpdd->SetCooperativeLevel( m_hWnd,  m_dwCooprativeFlags );

         m_lpdd->SetDisplayMode( m_dwWidth, m_dwHeight, m_dwBPP, m_dwRefreshRate, m_dwDisplayModeFlags );

 

         return TRUE;

}

 

当然,在wimmain()中,也要进行改动如下

ddraw->InitDDraw( hwnd, DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT,SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0 , 0 );

,OK,出了个全屏。

但是,真的这一个DEMO完了么?我们去看看第八章末尾,P419页,函数原型最终是这样的,

Int DDRAW_INIT(int width, int height, int bpp, int windowed = 0 ),说明了什么呢?暂时不看源代码,说明了窗口句柄不要了,是否为窗口可变,当然,我宁愿这里为bool windowed = false;

如果是我,如何才能改变窗口的全屏与否呢?

设个BOOL量m_windowed,,在构造函数中初始化为false;

If( m_windowed == false )

  m_dwCooperativeFlags = DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT,SCREEN_WIDTH;

else

if( m_windowed == true )

m_dwCooperativeFlags = DDSCL_NORMAL;

在WINMAIN()中,当然只需要传递长宽以及是否为窗口标志。试下看。但是我们仍然保留窗口句柄

m_dwRefreshRate和m_dwDisplayModeFlags本来就默认为0,传递实属无益。

运行后OK,图示分别为窗口和非窗口,

现在,该看看答案了,看看书上是怎么封装的,OK,提前揭晓答案。

 

int DDraw_Init(int width, int height, int bpp, int windowed)

{

// this function initializes directdraw

int index; // looping variable

 

// create IDirectDraw interface 7.0 object and test for error

if (FAILED(DirectDrawCreateEx(NULL, (void **)&lpdd, IID_IDirectDraw7, NULL)))

   return(0);

 

// based on windowed or fullscreen set coorperation level

if (windowed)

   {

   // set cooperation level to windowed mode

   if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,DDSCL_NORMAL)))

       return(0);

 

   } // end if

else

   {

   // set cooperation level to fullscreen mode

   if (FAILED(lpdd->SetCooperativeLevel(main_window_handle,

              DDSCL_ALLOWMODEX | DDSCL_FULLSCREEN |

              DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT | DDSCL_MULTITHREADED )))

       return(0);

 

   // set the display mode

   if (FAILED(lpdd->SetDisplayMode(width,height,bpp,0,0)))

      return(0);

 

   } // end else

 

// set globals

screen_height   = height;

screen_width    = width;

screen_bpp      = bpp;

screen_windowed = windowed;

。。。。。}

后面是离屏表面的东西,以后再说,

看看不同的地方,在这里

如果是windowed,则没有SetDisplayMode,说明我这里有个概念错误,应该是全屏才有分辨率之说,另外遗漏了screen_windowed = windowed;,这些都是不严谨的地方,切记!

main()里面更换FALSETRUE值,果然如此,但是窗口太小了。所以,我觉得应该是我的正确。

如下图所示。

总结:

这一个DEMO就是添加了个显示模式,不只是窗口了,还可全屏。

 


6_3

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值