<form id="hz9zz"></form>
  • <form id="hz9zz"></form>

      <nobr id="hz9zz"></nobr>

      <form id="hz9zz"></form>

    1. 明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

      通向DirectDraw之捷徑

      [摘要]作者:Johnny Watson 譯者:藍色feel From:www.x-temple.com 這篇文章描述了怎樣通過使用DirectX SDK中的通用庫文件來輕松地建立一個 Direct...
      作者:Johnny Watson 譯者:藍色feel From:www.x-temple.com

          這篇文章描述了怎樣通過使用DirectX SDK中的通用庫文件來輕松地建立一個 DirectDraw對象及其顯示表面(surface)。(這篇文章)對那些想要在不破壞原應用程序架構的情況下快速掌握它來做些事的人特別有幫助,請注意事實上這些類中抽象了相當多且復雜的事物,因此我強烈地推薦你在掌握它們功能的同時,盡量關注一下其底層的實現,這樣有助于你盡快掌握它們的工作方式。

      1.DirectDraw的安裝 

          在本文中,我假定你擁有微軟公司的 Visual C++ , 和 DirectX 8.1 SDK。如果沒有,就快去準備一份吧。 首先,啟動你的 Visual C++, 創建一個新的 Win32 應用程序工程。 然后進入 你 DirectX SDK 文件夾中的 multimedia\common\include 目錄 , 拷貝 dxutil.h 和 ddutil.h 至你新建工程的目錄下。 然后將你 DirectX SDK文件夾中的 \multimedia\common\src目錄下的dxutil.cpp 和 ddutil.cpp 也拷貝至你新建工程的目錄下。把四個文件加入你的工程, 然后連接上下列庫文件: dxguid.lib ,ddraw.lib,winmm.lib。現在,你創建一個新的 C++源文件文件, 而且也把它加入你的工程。 這些是整個教程中我們將會用到的工作文件。

      2.DirectDraw程序代碼

          既然我們已經準備好了, 讓我們開始寫一些代碼什么的實在的東西吧!



      #define WIN32_LEAN_AND_MEAN

      #include <windows.h>

      #include "dxutil.h"
      #include "ddutil.h"


           這是標準的代碼。#define WIN32_LEAN_AND_MEAN,這句的目的是指示編譯器不要包含與MFC相關的操作。( 只是一個好的練習——如果你不在使用 MFC) 然后我們包括 dxutil.h 和 ddutil.h,這是兩個很有用的頭文件。 他們能夠使你以一種比通常的DirectX編程更輕松的方式來工作。



      //globals

      bool g_bActive = false;

      CDisplay *g_pDisplay = NULL;
      CSurface *g_pText = NULL;


      //function prototypes

      bool InitDD(HWND);
      void CleanUp();
      void GameLoop();


          代碼自身說的很清楚,不是嗎?我們的第一個全局變量,g_bActive,是一個讓我們的應用程序知道是否應該運行游戲的標志。 如果我們沒有這個全局變量, 我們的應用程序可能在它自己被注銷之後還在嘗試著在我們已經創建的 DirectDraw 的表面上畫點兒什么呢!雖然這通常是一個在程序結束的時候出現的一個不大的問題,但它會導致一個非法操作的錯誤,我們并不想那樣,不是嗎? g_pDisplay 是我們的顯示對象。CDisplay 在 ddutil.h 中是最主要的類。它控制著我們前后的緩沖區,并提供一些針對該緩沖區的功能,如訪問及存儲緩沖區,將表面寫入緩沖區,創建一個表面,等等。 g_pText 是一個文本表面。 我們將會在這個表面 (你或許已經有所理解 ) 之上寫文本, 然后將它傳送到我們的屏幕之上。 注意它們兩者都是指向對象的指針, 而且被初始化為NULL。
           現在來看看函數的原型。 InitDD() 只是用來初始化 DirectDraw 。 多虧了 DirectDraw 的通用文件(common files),這還算是一個簡單的程序。( 但是晚些時候我們才會接觸到它們) CleanUp()調用了對象 g_pDisplay 的析構函數來釋放 ( release)我們所創建的DirectDraw對象及其表面。很明顯, GameLoop() 則是將來用來放你的游戲的地方。


          LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg,
                                      WPARAM wParam, LPARAM lParam)
          {
              switch(uMsg)
              {
                  case WM_CREATE:
                      InitDD(hWnd);
                      g_bActive=true;
                      break;
                  case WM_CLOSE:
                      g_bActive=false;
                      CleanUp();
                      DestroyWindow(hWnd);
                      break;
                  case WM_DESTROY:
                      PostQuitMessage(0);
                      break;
                  case WM_MOVE:
                      g_pDisplay->UpdateBounds();
                      break;
                  case WM_SIZE:
                      g_pDisplay->UpdateBounds();
                      break;
                  default:
                      return DefWindowProc(hWnd,uMsg,wParam,lParam);
                      break;
              }
              return 0;
          }


           這里是標準的 Windows 程序消息處理機制的代碼。 當產生 WM_CREATE 消息時,我們初始化 DirectDraw, 并將我們的全局變量 g_bActive 設定為true,這樣就可以執行游戲循環 GameLoop() 了。當消息 WM_CLOSE 被傳遞的時候,我們就把全局變量 g_bActive 設定為 false ( 這樣我們的應用程序就不會在它自己被注銷之後還在嘗試著向我們已經創建的 DirectDraw 的表面上寫數據了)。然后調用 CleanUp() 函數,最終注銷我們的窗口程序。處理 WM_MOVE 和 WM_SIZE 事件非常重要,因為若處理不當,DirectDraw 將不顧窗口本身是否已經被移動或重新設定其大小,仍然在屏幕上原來的位置上繼續作畫,從而造成錯誤。

          bool InitDD(HWND hWnd)
          {
              //dd init code
              g_pDisplay = new CDisplay();

              if(FAILED(g_pDisplay->CreateWindowedDisplay(hWnd,640,480)))
              {
                  MessageBox(NULL,"Failed to Initialize DirectDraw",
                              "DirectDraw Initialization
                  Failure",MB_OK MB_ICONERROR);
                  return false;
              }
              return true;
          }


           該死的 InitDD() 函數... 不過別急,它只不過幾行而已! 這兒就是通常那些個庫文件的用武之地,F在那些妨礙我們建立 DirectDraw 對象的冗長的玩意兒已被我們輕松搞定了,而你將會再次注意到它挺麻煩的,不是嗎?如果你真的不想弄明白那些惹人煩的玩意兒,那么至少你得知道個梗概吧!如果你得回去改變協作等級什么的,它也許幫得上忙。注意到這是一個返回 bool 值的函數, 因此如果你不厭倦的話, 你應當做一下錯誤檢查。(基于你所可以理解的篇幅問題之原因,我決定在這篇文章中省略)

          void CleanUp()
          {
              SAFE_DELETE(g_pDisplay);
          }


           真是夠簡單的! 這個函數調用了在 dxutil.h 中定義的宏 SAFE_DELETE 來刪除我們的顯示對象,同時調用析構函數。

          void MainLoop()
          {
              g_pDisplay->CreateSurfaceFromText(&g_pText,NULL,"DDraw using Common Files",
              RGB(0,0,0),RGB(0,255,0));

              g_pDisplay->Clear(0);
              g_pDisplay->Blt(0,0,g_pText,0);
              g_pDisplay->Present();

              g_pText->Destroy();
          }


           這兒就是你將來放游戲的地方。 為了要給你一個表面對象(surface object)如何工作的例子,我們已經做了一個簡單的文本表面而且寫了一些文本上去。注意我們在最後釋放(destroy)了全局指針變量 g_pText,否則每次循環它都將被重新創建一次,直到吃光最后一點兒內存。

          int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                              LPSTR lpCmdLine, int iShowCmd)
          {
              WNDCLASSEX wc;
              HWND hWnd;
              MSG lpMsg;

              wc.cbClsExtra=0;
              wc.cbSize=sizeof(WNDCLASSEX);
              wc.cbWndExtra=0;
              wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
              wc.hCursor=LoadCursor(NULL,IDC_ARROW);
              wc.hIcon=LoadIcon(NULL,IDI_APPLICATION);
              wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
              wc.hInstance=hInstance;
              wc.lpfnWndProc=WndProc;
              wc.lpszClassName="wc";
              wc.lpszMenuName=0;
              wc.style=CS_HREDRAW CS_VREDRAW;

              if(!RegisterClassEx(&wc))
              {
                  MessageBox(NULL,"Couldn't Register Window Class",
                              "Window Class Registration
                              Failure",MB_OK MB_ICONERROR);
                  return 0;
              }

              hWnd = CreateWindowEx(NULL,"wc","DirectDraw Common Files in Action",
                                      WS_POPUPWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,640,480,0,0,
                                      hInstance,0);
              if(hWnd == NULL)
              {
                  MessageBox(NULL,"Failed to Create Window","Window Creation
                              Failure", MB_OK MB_ICONERROR);
                  return 0;
              }

              ShowWindow(hWnd,SW_SHOW);
              UpdateWindow(hWnd);

              while(lpMsg.message != WM_QUIT)
              {
                  if(PeekMessage(&lpMsg,0,0,0,PM_REMOVE))
                  {
                      TranslateMessage(&lpMsg);
                      DispatchMessage(&lpMsg);
                  }
                  else if(g_bActive)
                  {
                      MainLoop();
                  }
              }
              return lpMsg.wParam;
          }


           這就是我們的應用程序中最長的函數——WinMain()。像往常一樣, 我們創建一個窗口類,然后再創建一個窗口,顯示及更新它, 并且進入消息循環?瓷先ブ餮h不同於平常是因為我們不想要主游戲進程被消息的處理所干擾。我們通過觀察全局指針變量 g_bActive 的狀態 來判斷該時刻調用游戲循環是否安全以及在循環中向屏幕上傳送(blit)圖象,而最后全部結束的時候我們返回一個長指針 lpMsg.wParam.( 至于為什么我實在是不敢肯定,可其它每個 Win32 應用程序都是這樣做的,對,就是這樣)
           實在是太簡單了,嗯!?我們只用了 135 行程序編碼就已經將對象寫到了屏幕上。自由地去進一步探究這些類的結構,做一些載入位圖至表面一類的實驗等等。這是使用 DDraw的一個很棒的捷徑。它能在不犧牲控制 (你總是能在你需要的時候回去編輯那些類) 和性能的情況下而使事情變得容易些。有一件事得要注意的是在計算機上如果我使用了這個結構卻不繪制任何對象到屏幕上, 應用程序將會鎖定。( 對,這就是我為什麼把文本輸出也包括在這里) 如果我說做游戲很大程度上就是把對象傳送( blit )到屏幕上,大概不會引起什么爭議(除非又有一些新的藝術風格誕生了)。


      日韩精品一区二区三区高清