電腦遊戲製作開發設計論壇 首頁 電腦遊戲製作開發設計論壇
任何可以在PC上跑的遊戲都可以討論,主要以遊戲之製作開發為主軸,希望讓台灣的遊戲人有個討論、交流、教學、經驗傳承的園地
 
 常見問題常見問題   搜尋搜尋   會員列表會員列表   會員群組會員群組   會員註冊會員註冊 
 個人資料個人資料   登入檢查您的私人訊息登入檢查您的私人訊息   登入登入 

Google
[程式0]空視窗架構

 
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 槍戰射擊遊戲
上一篇主題 :: 下一篇主題  
發表人 內容
yag
Site Admin


註冊時間: 2007-05-02
文章: 684

2639.56 果凍幣

發表發表於: 2007-6-8, AM 11:50 星期五    文章主題: [程式0]空視窗架構 引言回覆

因為版面寬度不足,所以註解超過寬度的地方看起來會怪怪的,不過只要直接copy下來貼到VC++上,看起來就會正常了。
這是一個最基本的空視窗架構範例,整個架構內有許多地方是因應Windows的運作規則而設計的,這個要詳細解說可不得了,所以我只能大略介紹一下。

首先,熟悉ANSI C++的人可能會覺得很不習慣,但這是正常的,畢竟Windows是事件驅動型的系統,跟DOS那種命令列系統可大是不同,最顯而易見的,就是main不見了,相對地,我們使用WinMain來當作程式的啟始點。

WinMain中做了什麼,在註解裡都已大致解釋過,重點是在於訊息迴圈,在一般主控台專案中,我們是一步一步告訴程式該如何如何做,如何要求使用者輸入,然後我們如何在經過轉換後做輸出。
但在Windows中,我們會建立一個訊息處理函式,然後用一個迴圈去等待接收命令,之後再依使用者輸入之命令,進入訊息處理函式中找尋對應的處理方式,並且做出輸出。

如此一來,程式就不會在每次要求輸入時停住,使用者可以在他們高興的時候再做輸入的動作,而且也不必照著我們要求的格式一步一步輸入,他們想做什麼都可以,要移動視窗、要最大化最小化、要關閉、要移動遊戲中的人物、要一邊砍怪物一邊喝藥水,通通可以隨意做到,不用等程式告訴他們現在該輸入什麼。

這就是事件驅動的中心思想,每一個輸入都是一個事件,而當事件發生時,Windows才會去呼叫我們程式中的訊息處理函式,而不是程式設計師決定好何時該做什麼輸入。
現在應該了解這個程式做了什麼吧?它就只是建立一個視窗,然後建立一個對應的訊息處理函式而已,這樣一個空視窗架構就誕生了,接著就是在其中加入些東西,讓它變成遊戲...
代碼:
//******************************************
// 基本視窗範例(程式碼 by Charles Petzold)
// 2007年6月8日 上午11:43 註解&修改完畢
// by yag
//******************************************
#include <windows.h>

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
   static TCHAR szAppName[] = TEXT( "空視窗架構" );
   HWND hwnd;
   MSG msg;
   WNDCLASS wndclass;

   wndclass.style = CS_HREDRAW | CS_VREDRAW;   // 視窗水平方向大小 | 垂直方向大小改變時,視窗要完全重繪
   wndclass.lpfnWndProc = WndProc;      // 以此類別建立之所有視窗所使用的視窗訊息處理函式的名稱(也就是其位址)
   wndclass.cbClsExtra = 0;      // 給視窗類別結構預留的額外空間,不使用則設為0
   wndclass.cbWndExtra = 0;      // 給Windows內部保存的視窗結構預留的額外空間,不使用則設為0
   wndclass.hInstance = hInstance;      // WinMain的第一個參數傳過來,程式的實體代號
   wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION );      // 小的點陣圖圖像,會出現在工作列中和視窗的標題列左端
                                             // LoadIcon使用預先定義的圖示要將第一個參數設為NULL
                                             // 如果要載入自訂的圖示,第一個參數要傳入WinMain的hInstance
   wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );      // 視窗中使用的滑鼠遊標,跟LoadIcon一樣,預先定義的設NULL
                                             // 自訂的遊標,第一個參數傳hInstance
   wndclass.hbrBackground = (HBRUSH) GetStockObject( WHITE_BRUSH );   // 取得備用(stock)畫刷,塗滿視窗背景顏色
   wndclass.lpszMenuName = NULL;   // 指定視窗類別功能表,無功能表設NULL
   wndclass.lpszClassName = szAppName;      // 類別名稱

   if( !RegisterClass( &wndclass ) )   // 建立視窗第一步:註冊視窗類別
   {
      MessageBox( NULL, TEXT( "註冊視窗類別失敗!" ), szAppName, MB_ICONERROR );
      return 0;
   }

   // 建立視窗第二步:利用已註冊之視窗類別建立視窗,回傳視窗代號(hwnd)
   hwnd = CreateWindow( szAppName,      // 視窗類別名稱,這是視窗與視窗類別聯結的管道
                   TEXT( "基礎視窗架構" ),   // 標題列文字
                   WS_OVERLAPPED | WS_SYSMENU,   // 視窗樣示
                   CW_USEDEFAULT,      // 視窗左上角出現位置的X座標,CW_USEDEFAULT代表使用Windows內定位置
                   CW_USEDEFAULT,      // 視窗左上角出現位置的Y座標,Windows內定位置會依視窗重疊情況遞增
                   CW_USEDEFAULT,      // 視窗寬度,使用內定尺寸
                   CW_USEDEFAULT,      // 視窗高度,使用內定尺寸
                   NULL,      // 父視窗代號,如果父視窗是桌面,填NULL即可
                   NULL,      // 視窗功能表代號,無功能表填NULL
                   hInstance,      // 傳入執行實體代號(WinMain第一個參數)
                   NULL );   // "建立參數"指標,可用此參數存取程式中可能引用到的資料

   ShowWindow( hwnd, iCmdShow );   // 建立視窗第三步:第一及第二步在記憶體中已完成視窗建立之配置,此步驟將其顯示出來
                           // 第一個參數是已在記憶體中建立好的視窗之代號,第二個參數是WinMain的第四參數,決定顯示的方法
                           // 如最大化:SW_SHOWMAXIMIZED,只顯示在工作列上:SW_SHOWMINNOACTIVE,一般是SW_SHOWNORMAL
   UpdateWindow( hwnd );   // 此函式會送出一個WM_PAINT給視窗訊息處理函式(在此為WndProc),此訊息會導致視窗重繪

   // 建立視窗第四步(最後一步):視窗基本上已建立,但還需要一個"訊息迴圈"才能讓使用者有輸入的管道
   // 此為一般視窗之訊息迴圈,如果是遊戲程式,有另一種特殊的訊息迴圈
   while( GetMessage( &msg, NULL, 0, 0 ) )      // 從訊息佇列中取得訊息,只要msg.message不為WM_QUIT,傳回非零值,否則傳回0
   {
      TranslateMessage( &msg );   // 訊息鍵盤轉換
      DispatchMessage( &msg );   // 將訊息丟給視窗訊息處理函式(在此為WndProc)
   }

   return (int)msg.wParam;      // 這會是PostQuitMessage函式的參數的值(通常是0)
}

// 共用同一個視窗類別的多個視窗也會共用同一個視窗訊息處理函式
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )   // 此四參數跟MSG結構的前四個欄位是相同的
{
   HDC hdc;
   PAINTSTRUCT ps;
   RECT rect;

   switch( message )
   {
   case WM_KEYUP:
      if( wParam == VK_ESCAPE )   // 按下ESC
      {
         DestroyWindow( hwnd );   // 就消滅視窗
      }
      return 0;

   case WM_PAINT:   // 視窗無效時重繪,變更大小、移動、重疊、最大最小化,皆會被標誌為無效
      // WM_PAINT幾乎總是從BeginPaint呼叫開始,並以一個EndPaint呼叫結束
      hdc = BeginPaint( hwnd, &ps );   // 取得裝置內容代號(hdc)

      GetClientRect( hwnd, &rect );   // 取得視窗顯示區域的尺寸

      // 第三個參數-1代表第二個參數的字串是以位元組0終結的
      DrawText( hdc, TEXT( "空視窗範例" ), -1, &rect, DT_SINGLELINE |DT_CENTER | DT_VCENTER );
      
      EndPaint( hwnd, &ps );

      return 0;

   case WM_DESTROY:
      PostQuitMessage( 0 );
      return 0;
   }

   return DefWindowProc( hwnd, message, wParam, lParam );   // 呼叫Windows內定的訊息處理函式
}

執行結果:
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
話術師
對這略感興趣的新人


註冊時間: 2007-06-02
文章: 17
來自: 耗電量很高的地方
0.00 果凍幣

發表發表於: 2007-6-8, PM 1:45 星期五    文章主題: 引言回覆

已經開始寫視窗了 Very Happy 不過PO到VC++版比較好 Very Happy
先說明類別以及關於DC裝置的取得比較好 Smile
MSDN有不錯的說明 但是對新手都看不懂 Razz
寫篇關於視窗建立的方法是不錯的選擇 Cool

_________________
人生真累呀


話術師 在 2007-6-8, PM 2:09 星期五 作了第 1 次修改
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
yag
Site Admin


註冊時間: 2007-05-02
文章: 684

2639.56 果凍幣

發表發表於: 2007-6-8, PM 2:02 星期五    文章主題: 引言回覆

話術師 寫到:
已經開始寫視窗了 Very Happy 不過PO到C++版比較好 Very Happy
先說明類別以及關於DC裝置的取得比較好 Smile
MSDN有不錯的說明 但是對新手都看不懂 Razz
寫篇關於視窗建立的方法是不錯的選擇 Cool

呵呵,視窗相關的東西可不是ANSI C/C++的內容吶
要po的話,應該開個VC++的版面才是
不過我是希望跟這個遊戲相關的東西就先放在這個版面
這樣之後加入的人比較方便得到基礎學習的知識
等到專案完畢後,再看情況把一部份基礎的東西移到VC++版面中
至於非基礎、跟遊戲相關的部份,就會留在這裡了吧

類別的部份屬於C++的範圍,我不打算在這講解,那個C++教學我會慢慢補
至於DC那是下一個主題,講到GDI時就會介紹

MSDN方面,我有時在介紹函式或識別字時,會附上連結,猜拳遊戲那篇裡面就有附過了,有興趣的自然會去看。

趁這個機會說一下,視窗相關的函式有上千個,沒有人能夠都背起來,何況很多函式的參數都嘛十來個,背得起來就有鬼,因此在寫程式時,一部「字典」就是很重要的工具,而目前以VC++來說,最重要也最常見的工具就是MSDN,雖然裡面內容很多是英文的,但還是要看,不會查MSDN的人跟本寫不了視窗程式,所以有心想從事程式設計工作的人,請務必學習如何查詢MSDN。

另外,視窗類別結構跟建立視窗函式都有很多個欄位跟參數要填,也沒有人會去背這種東西的,大家都是理解,然後要修改的時候查查MSDN,平時要寫一個新程式時,都是直接copy舊的空視窗架構來加功能,所以不要呆呆的想說「哇~~這麼多欄位跟參數,是要背到什麼時候?」,跟本就不需要去背...重點是看得懂以及會查MSDN就行了。
回頂端
檢視會員個人資料 發送私人訊息 發送電子郵件
從之前的文章開始顯示:   
發表新主題   回覆主題    電腦遊戲製作開發設計論壇 首頁 -> 槍戰射擊遊戲 所有的時間均為 台灣時間 (GMT + 8 小時)
1頁(共1頁)

 
前往:  
無法 在這個版面發表文章
無法 在這個版面回覆文章
無法 在這個版面編輯文章
無法 在這個版面刪除文章
無法 在這個版面進行投票
可以 在這個版面附加檔案
可以 在這個版面下載檔案


Powered by phpBB © 2001, 2005 phpBB Group
正體中文語系由 phpbb-tw 維護製作