• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            DirectDraw 與 DirectInput 的游戲編程體驗

            原文地址:http://www.gameres.com/Articles/Program/Abstract/DirectDraw%E4%B8%8EDirectInput%E7%9A%84%E6%B8%B8%E6%88%8F%E7%BC%96%E7%A8%8B%E4%BD%93%E9%AA%8C.htm

              我想關(guān)于這個主題的文章,不算少,但也不算太多。但大多是分別介紹 DirectDraw 與 DirectInput,而并沒有將其結(jié)合起來,也許你會問:“分開與合并起來并沒有本質(zhì)區(qū)別啊!”。其實的確沒有本質(zhì)區(qū)別,但那樣使那些最初對游戲編程報有極大熱情的愛好者感到非常失望,因為這其中的一個并不能完全滿足他們的要求,并且使其感到巨大的阻力,從而失去信心。所以本文將 DirectDraw 與 DirectInput結(jié)合起來去講一個主題就是“游戲編程”,請注意是“游戲編程”,當(dāng)然這只是一個簡單的桌面游戲,但這已經(jīng)與先前有很大的不同了,這已不是簡單的 DirectDraw或 DirectInput編程。我想你現(xiàn)在應(yīng)該能夠體會出其中的區(qū)別了。

              聲明:在這之前需要你具有一定的 WIN32 API 函數(shù)的知識,并且可以熟練使用。和 DirectDraw的知識,關(guān)于DirectDraw可以參見 www.frontfree.net 中的 <<動畫程序編寫——DirectDraw之旅>> 1-3),或其它文章。最后是 c++ 語言,當(dāng)然也要包括面向?qū)ο蟮哪遣糠帧T?Visual C++ .NET 編譯環(huán)境下進(jìn)行開發(fā)的。

              首先 ,我們還是先簡要復(fù)習(xí)一下DirectDraw的概念吧!
            DirectDraw本質(zhì)上是顯存管理程序。它最重要的性能是允許程序員直接在顯存里存儲和操縱位圖。它使你能夠利用視頻硬件bliter(位塊傳輸器)在顯存內(nèi)部進(jìn)行位圖的blit(位塊傳輸)。用視頻硬件的blitter從顯存向顯存進(jìn)行blit比從內(nèi)存向顯存更快。這在64位顯卡向顯存提供64位數(shù)據(jù)路徑的今天顯得尤其重要,硬件獨立于促CPU進(jìn)行位塊傳輸操作,使得CPU得以繼續(xù)工作。另外DirectDraw支持顯卡的其他硬件加速特性,例如對精靈和z -buffering的硬件支持。

            DirectDraw的工作原理

            我們這里還是用圖表方式展現(xiàn)給大家吧!

              細(xì)心的朋友可以很明顯地注意到圖示中的右上角的圖解中說明,表面對象有兩個寬度,一個是WIDTH,一個是PITCH。WIDTH就是創(chuàng)建表面時所給出的那個寬度,而PITCH是表面的實際寬度,是按字節(jié)算的。在許多顯卡上,PITCH和WIDTH是相等的,比如在640x480的高彩模式下,PITCH為1280。而在某些顯卡上,PITCH比WIDTH要大。比如在640x480的256色模式下,當(dāng)WIDTH是640時,PITCH為1024而不是640,這些顯卡這樣做是為了更好地進(jìn)行數(shù)據(jù)對齊來提高性能或達(dá)到其它目的。所以,我們在實際編程時,為了保證程序的兼容性,必須按PITCH處理。 但這些硬件的底層問題,我們不用太關(guān)心,只要稍有了解就可以了。

            下面我們再簡要敘述一下,如何使用 DirectX 9.0 中提供的 DirectDraw 類庫來創(chuàng)建對象并使用操作對象。

            宏定義在先,定義刪除指針和釋放對象的宏

            #defineSAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
            #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

            先創(chuàng)建一個 CDisplay 的全局對象
            CDisplay就是ddutil.h中定義的類,用于處理表面之間的拷貝翻頁等操作的類,再次定義一個全局變量,用于以后對指向的表面之間進(jìn)行操作

            CDisplay* g_pDisplay = NULL;

            然后創(chuàng)建表面,當(dāng)然可以創(chuàng)建很多的表面,這些表面都是離屏表面,在更新畫面時,都可以用 CDisplay 類的對象中的方法,將其拷貝到后備緩沖區(qū)表面上。只要創(chuàng)建離屏表面,就要用到 CSurface 類。CSurface也是ddutil.h頭文件中定義的類,用于對表面本身進(jìn)行操作,如設(shè)置色彩鍵碼,在此定義的圖畫指針。
             

            CSurface* g_pBackSurface = NULL;

            DirectX 中就一共用這兩個類封裝了 DirectDraw 對象的大部分操作,如果你覺得這還不能滿足要求,那么你也可以在程序中用 DirectDraw API 函數(shù)編寫程序,不過在本文中不再介紹。

            這之后,我們會用到 InitDirectDraw 函數(shù)。這個函數(shù)是我們自己創(chuàng)建的。在此函數(shù)中作所有的 DirectDraw 的對象初始化工作。

            HRESULT InitDirectDraw( HWND hWnd )
            {
            ?????HRESULT hr;
            //接受返回值,其實是long型變量
            ?????LPDIRECTDRAWPALETTE pDDPal = NULL; //定義程序中的調(diào)色板
            ?????int iSprite;//定義與sprite個數(shù)有關(guān)的計數(shù)器
            ?????g_pDisplay = newCDisplay();//動態(tài)開辟一個CDisplay類
            ?????if( FAILED( hr = g_pDisplay->CreateFullScreenDisplay( hWnd, SCREEN_WIDTH,
            ???????????SCREEN_HEIGHT, SCREEN_BPP ) ) )
            /*設(shè)置程序為全屏,并且 g_pDisplay 就是動態(tài)開辟一個CDisplay類的指針,而在這個類的域中,有一個DirectDraw主表面指針,和一個后備緩沖區(qū)表面的指針。在從我建議你可以先去閱讀一下 ddutil.h 和 ddutil.cpp 文件。*/
            ?????{
            ???????????MessageBox( hWnd, TEXT("This display card does not support 1024x768x8. "),
            ?????????????????TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );

            ???????????return hr;
            ?????}

            ?????if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )//顧名思義,就是從bmp圖片中獲得調(diào)色板值,并賦值在pDDPal結(jié)構(gòu)指針?biāo)赶虻慕Y(jié)構(gòu)體中。
            ???????????returnhr;
            ?????if( FAILED( hr = g_pDisplay->SetPalette( pDDPal ) ) )//用剛才從IDB_DIRECTX中獲得的調(diào)色板制來設(shè)置程序調(diào)色板
            ???????????returnhr;
            ?????SAFE_RELEASE( pDDPal );
            //釋放指針,在用過后,一定要釋放,這是良好的編程習(xí)慣
            ??????// 用IDB_WINXP圖片創(chuàng)建一個表面,并用g_pBackSurface指向這個表面
            ?????if( FAILED( hr = g_pDisplay->CreateSurfaceFromBitmap( ??????&g_pBackSurface, MAKEINTRESOURCE( IDB_WINXP ),
            ??????SCREEN_WIDTH, SCREEN_HEIGHT ) ) )

            ???????????return hr;//設(shè)置色彩鍵碼為黑色,0代表黑色,這樣在表面的拷貝過程中黑色像素的點將不會被拷貝,這樣可以產(chǎn)生鏤空效果。當(dāng)然你可以任意設(shè)置關(guān)鍵顏色,而顏色的表示法可以用 RGB 宏定義。例如 紅色:RGB( 255,0,0 ), 黑色 RGB( 255,255,255 )
            ??????if( FAILED( hr = g_pBackSurface->SetColorKey( RGB( 255,255,255 ) ) ) )
            ???????????returnhr;
            ?????returnS_OK;
            }

            下面的函數(shù)是用于更新畫面的。
             

            HRESULT DisplayFrame()
            {
            ?????HRESULT hr;
            ?????g_pDisplay->Clear( 0 );
            //清空后備緩沖區(qū)表面
            ?????//將g_pBackSurface所指向的圖片拷貝到后備緩沖區(qū)表面
            ??????g_pDisplay->Blt( 0, 0, g_pBackSurface, NULL );//最關(guān)鍵的地方在這里,請看下面的語句,只要我們一執(zhí)行翻頁操作,就可以將改動了的圖像了顯示在屏幕上了
            ?????if( FAILED( hr = g_pDisplay->Present()/*翻頁操作*/) )
            ???????????returnhr;
            ?????returnS_OK;
            }

            下面的函數(shù)是用于在程序失去焦點時調(diào)用的。

            HRESULT RestoreSurfaces()
            {
            ?????HRESULT hr;
            ?????LPDIRECTDRAWPALETTE pDDPal = NULL;
            /*當(dāng)程序失去焦點,要保存當(dāng)前的畫面,請注意這里,g_pDisplay->GetDirectDraw()函數(shù)返回的才是真正的 DirectDraw 對象 */
            ?????if( FAILED( hr = g_pDisplay->GetDirectDraw()->RestoreAllSurfaces() ) )
            ???????????returnhr;//在此我們還要重新創(chuàng)建調(diào)色板
            ?????if( FAILED( hr = g_pDisplay->CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )
            ???????????returnhr;//重新設(shè)置調(diào)色板
            ?????if( FAILED( hr = g_pDisplay->SetPalette( pDDPal ) ) )
            ???????????returnhr;
            ?????SAFE_RELEASE( pDDPal );//重新畫出圖畫
            ?????if( FAILED( hr = g_pLogoSurface->DrawBitmap( MAKEINTRESOURCE( IDB_WINXP ),
            SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )

            ???????????returnhr;
            ?????returnS_OK;
            }

            下面這個函數(shù)是釋放表面指針?biāo)玫摹?/p>
            VOID FreeDirectDraw()
            {
            ??????SAFE_DELETE( g_pBackSurface );
            ??????SAFE_DELETE( g_pDisplay );
            }

            我們的回顧到此結(jié)束,下面我們開始本文要介紹的一個關(guān)鍵技術(shù),DirectInput 的使用。
            游戲編程可不僅僅是圖形程序的開發(fā)工作,實際上包含了許多方面,本文所要講述的就是關(guān)于如何使用 DirectInput 來對鍵盤編程的問題。
            而我們?yōu)槭裁匆x擇用 DirectInput 來處理游戲中的輸入問題呢?其實用 Win32 API 函數(shù)也完全可以處理這些工作,例如其中,有一個

            GetAsyncKeyState() 的函數(shù)可以返回一個指定鍵的當(dāng)前狀態(tài)是按下還是松開。這個函數(shù)還能返回該指定鍵在上次調(diào)用 GetAsyncKeyState() 函數(shù)以后,是否被按下過。雖然這個函數(shù)聽上去很不錯,但需要我們自己輪換查詢每個鍵盤的狀態(tài)。而在 DirectInput 中我們已經(jīng)可以脫離這些煩瑣的工作,只因它的功能更強大。

            由于本文重點在二者的結(jié)合,故在此只介紹 DirectInput 中比較簡單的,而且最容易上手的立即模式的工作方式。
            而這里我們要用到 DirectInput 的 API 函數(shù)。有人會問,為什么在 DirectDraw 中用 DirectX 提供的類庫編程,而對于 DirectInput 卻直接使用要用其 API 函數(shù)呢,是因為沒有提供 DirectInput 的類庫嗎?不是!而是因為使用類庫并不很方便而且不靈活。

            OK,讓我們開始我們游戲編程的第二部——DirectInput編程。

            前面講 DirectDraw 時,并沒有提到,微軟是按 COM 來設(shè)計DirectX的,所以就有了一個 DIRECTINPUT 對象來表示輸入設(shè)備,而某個具體的設(shè)備由 DIRECTINPUTDEVICE 對象來表示。也許會感到很無奈,怎么游戲編程需要這么多的知識啊,其實您也無需煩惱,只要知道一下就可以了,其實這并不;影響您的設(shè)計,而且就算您不知道,也同樣可以駕馭DIRECTINPUT。

            實際的建立過程是先創(chuàng)建一個 DIRECTINPUT 對象,然后在通過此對象的 CreateDevice 方法來創(chuàng)建 DIRECTINPUTDEVICE 對象。

            #include <dinput.h>
            #defineDINPUT_BUFFERSIZE 16
            LPDIRECTINPUT lpDirectInput;
            // DirectInput 對象實際上是一個com對象
            LPDIRECTINPUTDEVICE lpKeyboard; // DirectInput 設(shè)備
            BOOL InitDInput(HWND hWnd)
            {
            ??????HRESULT hr;
            // 創(chuàng)建一個 DIRECTINPUT 對象
            ?????if( FAILED( hr = DirectInputCreate(hInstanceCopy, DIRECTINPUT_VERSION, &lpDirectInput, NULL)))
            ?????{
            // 失敗提示或處理
            ???????returnhr;
            ??????}
            // 創(chuàng)建一個 DIRECTINPUTDEVICE 界面
            //參數(shù) GUID_SysKeyboard 指明了建立的是鍵盤對象

            ??????if( FAILED( hr = lpDirectInput->CreateDevice(GUID_SysKeyboard, &lpKeyboard, NULL)))
            ??????{

            ????????????// 失敗提示或處理
            ????????????returnhr;
            ???????}
            // 設(shè)定為通過一個 256 字節(jié)的數(shù)組返回查詢狀態(tài)值
            ??????if( FAILED(hr = lpKeyboard->SetDataFormat(&c_dfDIKeyboard)))
            ??????{

            ??????// 失敗提示或處理
            ????????????return hr;
            ??????}// 設(shè)定協(xié)作模式為獨占模式和前臺模式,獨占模式表面本程序在運行中占有所有鍵盤資源,而前臺模式指出當(dāng)程序具有焦點時才可以占有鍵盤資源
            ??????if( FAILED( hr = lpKeyboard->SetCooperativeLevel(hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
            ??????{

            ??????// 失敗提示或處理
            ????????????returnhr;
            ??????}

            ??????// 設(shè)定緩沖區(qū)大小
            ??????// 如果不設(shè)定,緩沖區(qū)大小默認(rèn)值為 0,程序就只能按立即模式工作
            ??????// 如果要用緩沖模式工作,必須使緩沖區(qū)大小超過 0
            ??????// 在此,我們沒有必要設(shè)定,因為我們就用立即模式工作(還有一種緩沖模式),所有我們將其注調(diào)了

            ??????/* DIPROPDWORD property;

            ??????property.diph.dwSize = sizeof(DIPROPDWORD);
            ??????property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
            ??????property.diph.dwObj = 0;
            ??????property.diph.dwHow = DIPH_DEVICE;
            ??????property.dwData = DINPUT_BUFFERSIZE;

            ??????if( FAILED(hr = lpKeyboard->SetProperty(DIPROP_BUFFERSIZE, &property.diph)))
            ??????{
            ??????// 失敗
            ????????????return FALSE;
            ??????}
            ??????*/

            ??????//此處是關(guān)鍵,我們要通過這個函數(shù)來鎖定鍵盤,記住,所有的DirectInput資源在使用前都要鎖定,在此即獲得鍵盤資源,在知識我們剛才設(shè)定的鍵盤模式才能起作用
            ??????hr = lpKeyboard->Acquire();
            ??????if FAILED(hr)
            ??????{

            ????????????// 失敗
            ????????????return FALSE;
            ??????}
            ??????returnTRUE;
            ??????}

            在這段代碼中,我們首先定義了 lpDirectInput 和 lpKeyboard 兩個指針,前者指向 DIRECTINPUT 對象,后者指向一個

            DIRECTINPUTDEVICE 界面。其順序就是這樣的。這和其它COM對象的使用方法都一樣,即先創(chuàng)建 COM 對象,然后創(chuàng)建界面,然后再獲得
            硬件資源,然后使用資源,然后釋放。

            通過 DirectInputCreate(), 我們?yōu)?lpDirectInput 創(chuàng)建了一個 DIRECTINPUT 對象。然后我們調(diào)用 CreateDevice 來建立一個DIRECTINPUTDEVICE 界面。
              
            完成這些工作以后,我們便調(diào)用 DIRECTINPUTDEVICE 對象的 Acquire 方法來激活對設(shè)備的訪問權(quán)限。在此要特別說明一點,任何一個

            DIRECTINPUT 設(shè)備,如果未經(jīng) Acquire,是無法進(jìn)行訪問的。還有,當(dāng)系統(tǒng)切換到別的進(jìn)程時,必須用 Unacquire 方法來釋放訪問權(quán)限,在系統(tǒng)切換回本進(jìn)程時再調(diào)用 Acquire 來重新獲得訪問權(quán)限。

            立即模式的數(shù)據(jù)查詢

            HRESULT ReadImmediateData( HWND hWnd )
            {
            ??????HRESULT hr;
            ??????BYTE diks[256];
            // 創(chuàng)建鍵盤狀態(tài)數(shù)據(jù)緩沖區(qū)存取鍵盤信息
            ??????inti; // 計數(shù)器
            ??????if( NULL == g_pKeyboard )
            ????????????returnS_OK;// 鍵盤狀態(tài)數(shù)據(jù)緩沖區(qū)清0
            ??????ZeroMemory( &diks, sizeof(diks) );// 獲得鍵盤所有鍵的信息,這只是檢查一次
            ??????hr = g_pKeyboard->GetDeviceState( sizeof(diks), &diks );
            ??????if( FAILED(hr) )
            ??????{

            ????????????// 如果鍵盤資源丟失,我們要重新獲得
            ????????????hr = g_pKeyboard->Acquire();
            ????????????while( hr == DIERR_INPUTLOST )
            ????????????hr = g_pKeyboard->Acquire();

            ????????????returnS_OK;
            ??????}
            // 進(jìn)行一下輪循,處理鍵盤信息。
            ??????for( i = 0; i < 256; i++ )
            ??????{

            ????????????if( diks[i] & 0x80 ) //記錄此鍵的狀態(tài),低字節(jié)最高位是 1 表示按下,0 表示松開,一般用 diks[i]&0x80 來測試
            ????????????{
            ??????????????????switch(i)
            ??????????????????{

            ??????????????????????????????//我們可以通過測試計數(shù)器i,來判斷是哪個鍵被按下了。
            ??????????????????????????????//我們提供幾個數(shù)據(jù) UP:200 down:208 left:203 right:205 enter:28 space:57
            ??????????????????????????????//其實你可以用DirectX中的Samples\C++\DirectInput\Bin\Keyboard.exe程序來測試,只不過那是用
            ??????????????????????????????//16進(jìn)制顯示的。
            ????????????????????????case200:
            ??????????????????????????????break;
            ????????????????????????case0xc8:
            ??????????????????????????????break;
            ??????????????????}
            ????????????}
            ??????}

            ??????returnS_OK;
            }

            請注意,上面的這段代碼只是一個示例,重在使你明白其原理,但并不能滿足游戲的需求,因為這其中只查詢了一次鍵盤的全部信息,做了一次輪循,而在游戲中要周期性地查詢,并輪循,這就需要你自己用Win32 API函數(shù) SetTimer和 KillTimer 設(shè)置初始化 DirectInput 對象函數(shù)中在相應(yīng)的地方設(shè)置計計時器,讓windows定時向程序發(fā)送 WM_TIMER消息,你要通過此消息進(jìn)行周期性地鍵盤查詢,并在相應(yīng)的地方解除計時器。

            最后一個函數(shù)是用于釋放指針或DirectInput對象的

            void ReleaseDInput(void)
            {

            ??????if(lpDirectInput)
            ??????{

            ????????????if(lpKeyboard)
            ????????????{

            ??????????????????// Always unacquire the device before calling Release().
            ??????????????????lpKeyboard->Unacquire();
            ??????????????????lpKeyboard->Release();
            ??????????????????lpKeyboard = NULL;
            ????????????}
            ????????????lpDirectInput->Release();
            ????????????lpDirectInput = NULL;
            ??????}
            }

            在這些函數(shù)中的注釋很明確,關(guān)鍵在于理解其原理,而怎樣將他們?nèi)谌氲?Win32 API 程序的基本框架中的,在<<動畫程序編寫——DirectDraw之旅>> 1-3中的示例代碼中已經(jīng)解釋得很明確了,在此不再贅述。不過我們提供其中的代碼示例下載。同時你也可以去仔細(xì)閱讀DirectX 8.0 SDK 包中的 samples\ multimedia\ directdraw\ fullscreenmode\ samples\ multimedia\ directdraw\ windowedmode 這兩個工程中的文件,因為為了我們的示例也是照這兩個工程改編過來的,讀者可以通過仔細(xì)閱讀代碼和對比我們的更改,而更加了解 DirectDraw的運行運行原理。(請注意:是 DirectX 8.0 SDK 包中的示例,而在 9.0 中 DirectX SDK 已經(jīng)不提供 DirectDraw的示例代碼了)

            我們就用這七個函數(shù)就已經(jīng)可以創(chuàng)造出一個小游戲了。

            我們下面就要利用<<動畫程序編寫——DirectDraw之旅>> 1-3 中所用的代碼進(jìn)行進(jìn)一部的游戲開發(fā)。
            我們先展示一下 DirectX中\ samples\ multimedia\ directdraw\ windowedmode 工程中的截圖
            在這個動畫中有黑色背景,并有很多 DirectX 精靈在漂浮。



            這是一個全屏的動畫程序,而我們在<<動畫程序編寫——DirectDraw之旅>> 1-3其中做的改動就是為其加了一個背景,改屏幕分辨率 640×480 為 1024×768.注意,因為我們應(yīng)用的是全屏模式,即可以獨占顯存資源,所以我們可以更改屏幕的分辨率。這只是做的小小的改動,而我們的目的只在于讓大家更加深入了解。且看下面的這副截圖:

            而我們還要繼續(xù)深入編程,我們的思路是,先將程序由先前的全屏程序改編成一個windows的窗口程序,然后將其所有的界面翻新,并改編 DirectX精靈為許多小蘑菇在漂浮,還要加入DirectInput 的組建,用鍵盤控制一個小娃娃。可以上下左右,并可以斜向飛行。
            我們先將此動畫的截圖展現(xiàn)給大家

            怎么樣,你有什么想法,是想說:“唉,這還不好辦,就是又多加了一個!”,但不要光看截圖,不要忘記,我們一定讓她動起來,并且是可以控制的,這就不是那么簡單的事了!
            什么?若有人看到這里感到有些迷茫和泄氣,不禁想問:“你說了這么多,那么源代碼在那里呢!,光給我們幾個函數(shù),又能做什么呢?”,如果你這么想,你也不要太急迫。我們還是先分析一下程序框架吧。

            不過,還有一件重要的事情,我還是要重申一邊。一定要將 DirectX 的頭文件價,和lib文件夾加入到 Visual C++.NET 的默認(rèn)目錄中去,這樣編譯器就可以正確地找到它們了。
            如果你不會加入,就請通過工具欄上的 Tool -> Option… 打開Option 對話框,設(shè)置如圖:



            好了,這樣我們的準(zhǔn)備工作就算已經(jīng)做好了。

            來看看我們的工程文件結(jié)構(gòu)吧,還有工程中的資源。

            在工程資源中我們的 ID 號是都用的字符串表示的,筆者認(rèn)為這樣更加方便。
            我想對于工程文件中的 ddutil.cpp 和 dxutil.cpp 文件,讀者如果了解有些 DirectDraw編程是不會感到陌生的,我們只是將其引入到我們的工程中了。而我們自己實際編程的文件是
            outfly.cpp 文件。

            我們的程序敘述如下:
            首先進(jìn)行宏定義,結(jié)構(gòu)設(shè)置,和全局變量的聲明。
            后在 WinMain (windows程序的入口點)中首先初始化一切需要初始化的物件(有windows窗口,DirectDraw對象,和 DirectInput對象),在此我們就調(diào)用前文講過的函數(shù),但要有寫改動,讀者在會在后面看到的。然后進(jìn)入消息循環(huán),在其中沒有消息時,程序會自動更新畫面,在有消息時處理消息。
            當(dāng)遇到 WM_QUIT 消息后,結(jié)束整個程序。

            我們在一些地方有一些小小的改動,我們來看看吧。

            1 我們在 HRESULT InitDirectInput( HWND hWnd )
            函數(shù)中的開始加入了

            KillTimer( hWnd, 0 );
            FreeDirectInput();

            關(guān)掉上一次使用的計時器,并釋放 DirectInput 設(shè)備。
            而在最后加入了

            SetTimer( hWnd, 0, 1000 / 100, NULL );

            用來重新設(shè)置計時器。

            2 我們在主窗口的消息處理函數(shù)中加入了

            case WM_ACTIVATE: //當(dāng)程序先失去焦點,而現(xiàn)在有重新得到焦點時,要重新鎖定鍵盤資源
            ??????if( WA_INACTIVE != wParam && g_pKeyboard )
            ??????{

            ????????????// Make sure the device is acquired, if we are gaining focus.
            ????????????g_pKeyboard->Acquire();
            ??????}

            ??????break;
            caseWM_TIMER: //因為設(shè)置了計時器所以要處理此消息
            ??????if( FAILED( ReadImmediateData( hWnd ) ) )
            ??????{
            ????????????KillTimer( hWnd, 0 );
            ????????????MessageBox( NULL, _T("Error reading input state. ")
            ????????????_T("The sample will now exit."),
            ????????????_T("Keyboard"), MB_ICONERROR | MB_OK );
            ??????}

            ??????break;
            caseWM_DESTROY:// Cleanup and close the app
            ??????FreeDirectDraw();
            ??????FreeDirectInput();
            // 釋放資源
            ??????PostQuitMessage( 0 );
            ??????return 0L;

            3 在HRESULT ReadImmediateData( HWND hWnd ) 函數(shù)中進(jìn)行了這樣的處理,來時時改變小娃娃的坐標(biāo)。

            for( i = 0; i < 256; i++ )
            {

            ??????if( diks[i] & 0x80 )
            ??????{

            ????????????switch(i)
            ????????????{

            ??????????????????case200: //上鍵
            ????????????????????????if( g_me.fPosY > g_me.fVelY)
            ??????????????????????????????g_me.fPosY -= g_me.fVelY;

            ????????????????????????else
            ??????????????????????????????g_me.fPosY = 0;
            ????????????????????????break;
            ??????????????????case208: //下鍵
            ????????????????????????if( g_me.fPosY <= WINDOW_HEIGHT - SPRITE_DIAMETER - g_me.fVelY)
            ??????????????????????????????g_me.fPosY += g_me.fVelY;

            ????????????????????????else
            ??????????????????????????????g_me.fPosY = WINDOW_HEIGHT- SPRITE_DIAMETER;
            ????????????????????????break;
            ??????????????????case203://左鍵
            ????????????????????????if( g_me.fPosX > g_me.fVelX)
            ??????????????????????????????g_me.fPosX -= g_me.fVelX;

            ????????????????????????else
            ??????????????????????????????g_me.fPosX = 0;
            ????????????????????????break;
            ??????????????????case205://右鍵
            ????????????????????????if( g_me.fPosX <= WINDOW_WIDTH - SPRITE_DIAMETER - g_me.fVelX)
            ??????????????????????????????g_me.fPosX += g_me.fVelX;

            ????????????????????????else
            ??????????????????????????????g_me.fPosX = WINDOW_WIDTH- SPRITE_DIAMETER;
            ????????????????????????break;
            ????????????}
            ??????}
            }

            這些只是其中一些比較重要的改動,還有許多改動,讀者會在實際的程序中看到的。如果你覺得:“啊!到這里就結(jié)束了,可是我還是感到似乎莫不到頭緒,就這樣草草收尾了?”,其實文章并沒有結(jié)束,重頭戲還在后面呢,那就不是我的工作了,而是看你有沒有耐心去仔細(xì)閱讀代碼了,因為想要把握程序的整體,與其讓我將代碼放在文章中,還不如讀者自己在編譯器中自己運行實踐一下好,其實我們已經(jīng)在第二個工程代碼中有過詳細(xì)的解釋。但記住一定要按照順序閱讀 工程1,工程2 ,工程3。工程1就是 DirectX中提供的原代碼,工程2就是我們改了一個背景的工程,而3就是我們討論的工程。

             

            放飛技術(shù)網(wǎng)?

            posted on 2006-06-20 15:26 楊粼波 閱讀(302) 評論(0)  編輯 收藏 引用 所屬分類: 文章收藏

            中文字幕乱码久久午夜| 久久综合久久自在自线精品自| 久久人妻少妇嫩草AV无码专区| 欧美久久一级内射wwwwww.| 久久精品人人做人人爽电影| 久久久久亚洲av无码专区| 国产亚洲精久久久久久无码77777| 久久午夜免费视频| 欧美午夜A∨大片久久 | 午夜精品久久久内射近拍高清| 久久综合九色综合久99| 日本三级久久网| 色成年激情久久综合| 国内精品久久久久久久coent| 亚洲国产精品久久久久婷婷软件| 91精品久久久久久无码| 91久久九九无码成人网站| 精品一久久香蕉国产线看播放| 久久精品国产精品亚洲人人| 久久综合久久性久99毛片| 久久青青草视频| 久久久久免费精品国产| 久久男人Av资源网站无码软件| 精品国产91久久久久久久| 国产99久久久国产精品~~牛| 久久国产成人亚洲精品影院| 看全色黄大色大片免费久久久| 久久午夜免费视频| 久久99精品久久久久婷婷| 久久精品这里热有精品| 久久一区二区三区免费| 狠狠色婷婷久久综合频道日韩| 精品久久久久久久久午夜福利| segui久久国产精品| 一本大道久久香蕉成人网| 久久久精品2019免费观看| 久久综合狠狠综合久久激情 | 亚洲国产成人久久精品99 | 国产成人久久AV免费| 国内精品久久久久久中文字幕| 久久久精品人妻一区二区三区蜜桃|