標籤:

從零開始手敲次世代遊戲引擎(七)

那麼首先讓我們從最熟悉的Windows開始我們的圖形編程支線任務。

想像一下在現實生活當中,如果我們想要畫畫,需要準備一些什麼東西。在計算機領域,這個過程也是很相似的。因為當計算機從CUI(就是文字界面)轉向GUI的時候,拓荒GUI的那些先驅們,也是參考著生活進行設計和編程的。

顯然,我們首先需要有一塊畫布。在Windows系統當中,就是需要創建一個窗體。相信看這篇文章的很多人都寫過Windows應用,而且是GUI應用。用Visual Studio生成一個windows應用,會自動生成創建這個窗體的代碼。甚至,如果使用UWP,那麼窗口對我們來說更像一張網頁。然而這不是我想要介紹的方法。

我想要介紹的是使用windows系統API,也就是俗稱win32 API(64位windows的API仍然稱為win32 API)的方式創建窗口。之所以這麼做,是為了最小限度的依賴Visual Studio以及相關的庫,也是為了便於與其它系統的類似API作個比較。

好了,讓我們開始。首先依然是做個記錄點:

[tim@iZ625ivhudwZ GameEngineFromScratch]$ git checkout -b article_7nSwitched to a new branch article_7n

然後新建一個Platform目錄,用於存放和平台相關的代碼。

[tim@iZ625ivhudwZ GameEngineFromScratch]$ mkdir Platformn[tim@iZ625ivhudwZ GameEngineFromScratch]$ cd Platformn

在Platform下面新建Windows目錄,用於存放Windows平台相關代碼:

[tim@iZ625ivhudwZ Platform]$ mkdir Windows n[tim@iZ625ivhudwZ Platform]$ cd Windowsn

新建helloworld_win.c,敲入如下代碼:

// include the basic windows header filen#include <windows.h>n#include <windowsx.h>n#include <tchar.h>nn// the WindowProc function prototypenLRESULT CALLBACK WindowProc(HWND hWnd,n UINT message,n WPARAM wParam,n LPARAM lParam);nn// the entry point for any Windows programnint WINAPI WinMain(HINSTANCE hInstance,n HINSTANCE hPrevInstance,n LPTSTR lpCmdLine,n int nCmdShow)n{n // the handle for the window, filled by a functionn HWND hWnd;n // this struct holds information for the window classn WNDCLASSEX wc;nn // clear out the window class for usen ZeroMemory(&wc, sizeof(WNDCLASSEX));nn // fill in the struct with the needed informationn wc.cbSize = sizeof(WNDCLASSEX);n wc.style = CS_HREDRAW | CS_VREDRAW;n wc.lpfnWndProc = WindowProc;n wc.hInstance = hInstance;n wc.hCursor = LoadCursor(NULL, IDC_ARROW);n wc.hbrBackground = (HBRUSH)COLOR_WINDOW;n wc.lpszClassName = _T("WindowClass1");nn // register the window classn RegisterClassEx(&wc);nn // create the window and use the result as the handlen hWnd = CreateWindowEx(0,n _T("WindowClass1"), // name of the window classn _T("Hello, Engine!"), // title of the windown WS_OVERLAPPEDWINDOW, // window stylen 300, // x-position of the windown 300, // y-position of the windown 500, // width of the windown 400, // height of the windown NULL, // we have no parent window, NULLn NULL, // we arent using menus, NULLn hInstance, // application handlen NULL); // used with multiple windows, NULLnn // display the window on the screenn ShowWindow(hWnd, nCmdShow);nn // enter the main loop:nn // this struct holds Windows event messagesn MSG msg;nn // wait for the next message in the queue, store the result in msgn while(GetMessage(&msg, NULL, 0, 0))n {n // translate keystroke messages into the right formatn TranslateMessage(&msg);nn // send the message to the WindowProc functionn DispatchMessage(&msg);n }nn // return this part of the WM_QUIT message to Windowsn return msg.wParam;n}nn// this is the main message handler for the programnLRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)n{n // sort through and find what code to run for the message givenn switch(message)n {n // this message is read when the window is closedn case WM_DESTROY:n {n // close the application entirelyn PostQuitMessage(0);n return 0;n } break;n }nn // Handle any messages the switch statement didntn return DefWindowProc (hWnd, message, wParam, lParam);n}n

好了,讓我們來用Clang對它進行編譯。注意這是一個Windows程序,所以你需要在Windows裡面編譯它。並且,因為我們用到了一些Windows平台的介面,需要鏈接相關的庫:

C:UsersTim.AzureADSourceReposGameEngineFromScratchPlatformWindows>clang -l user32.lib -o helloengine_win.exe helloengine_win.cn

編譯成功的話,會出現一個helloengine_win.exe

C:UsersTim.AzureADSourceReposGameEngineFromScratchPlatformWindows>dirn 驅動器 C 中的卷是 OSn 卷的序列號是 38A2-CBDDnn C:UsersTim.AzureADSourceReposGameEngineFromScratchPlatformWindows 的目錄nn2017/08/21 08:20 <DIR> .n2017/08/21 08:20 <DIR> ..n2017/08/21 08:10 3,163 helloengine_win.cn2017/08/21 08:21 73,216 helloengine_win.exen 2 個文件 76,379 位元組n 2 個目錄 885,621,440,512 可用位元組n

執行它,我們就可以看到我們的窗體啦!

接下來再玩些別的酷酷的東西。在Linux上面交叉編譯它(把代碼Commit/Push到Github上面,然後在Linux上面把代碼再Pull下來。不會的網上搜一下Github/Git教程。)

[tim@iZ625ivhudwZ GameEngineFromScratch]$ git pullnremote: Counting objects: 5, done.nremote: Compressing objects: 100% (2/2), done.nremote: Total 5 (delta 1), reused 5 (delta 1), pack-reused 0nUnpacking objects: 100% (5/5), done.nFrom github.com:netwarm007/GameEngineFromScratchn 264a4aa..5587a7d article_7 -> origin/article_7nUpdating 264a4aa..5587a7dnFast-forwardn Platform/Windows/{helloworld_win.c => helloengine_win.c} | 2 +-n 1 file changed, 1 insertion(+), 1 deletion(-)n rename Platform/Windows/{helloworld_win.c => helloengine_win.c} (97%)n[tim@iZ625ivhudwZ GameEngineFromScratch]$ cd Platform/Windows/n[tim@iZ625ivhudwZ Windows]$ lsnhelloengine_win.cn[tim@iZ625ivhudwZ Windows]$ docker run -it --rm -v $(pwd):/usr/src tim03/mingw64ndocker@691b5f941825:/$ cd /usr/srcndocker@691b5f941825:/usr/src$ lsnhelloengine_win.cndocker@691b5f941825:/usr/src$ x86_64-w64-mingw32-gcc -o helloengine_win.exe helloengine_win.cndocker@691b5f941825:/usr/src$ lsnhelloengine_win.c helloengine_win.exendocker@691b5f941825:/usr/src$ exitnexitn

這個程序,當然,這樣直接是沒有辦法在Linux上執行的,因為它是一個Windows程序。但是,我們可以使用wine來執行它。wine是一個在Linux上面模擬Windows系統介面的執行環境,可以用了執行Windows程序。當時開發wine的主要目的,就是在Linux上面跑只有Windows版本的遊戲。

不過需要注意的是,要執行圖形界面程序,我們必須在Linux的桌面環境下(也就是不能在TTY環境下)。切換到桌面環境(不會的請自己在網上搜索Linux基本教程),打開終端模擬窗口,執行下面的命令(如果沒有安裝wine,請用yum或者apt命令安裝):

tim@iZuf6iup3mphicesefdwajZ:~/src/GameEngineFromScratch/Platform/Windows$ wine helloengine_win.exen

(-- EOF --)

參考引用:

  1. infernodevelopment.com/
  2. Windows API - Wikipedia
  3. Windows API Index

本作品採用知識共享署名 4.0 國際許可協議進行許可。


推薦閱讀:

在奇葩的 Json 世界裡冒險! - 《沒有勇者的世界》開發日誌 (2)
從零開始手敲次世代遊戲引擎(三十六)
從零開始手敲次世代遊戲引擎(二十六)
陳灼:我在2K的八年(序)

TAG:游戏开发 |