習(xí)路徑)
簡(jiǎn)介這是《Windows游戲編程大師技巧第二版》原書配套光盤中提取的完整源碼與素材集合面向具備基本C語法與Win32窗口編程經(jīng)驗(yàn)的讀者也適合高校游戲編程課程或自學(xué)DirectX經(jīng)典技術(shù)的人員。本書雖然基于舊版DirectX但核心思想仍是現(xiàn)代游戲開發(fā)的重要基礎(chǔ)。壓縮包共1035個(gè)文件大小38.49MB核心包含159個(gè)C源文件和25個(gè)頭文件并配有518個(gè)BMP位圖、99個(gè)WAV音效、27個(gè)PAL調(diào)色板、19個(gè)SCN場(chǎng)景文件等美術(shù)與音頻資源另有140個(gè)EXE可執(zhí)行程序可直接查看運(yùn)行效果。目錄按章節(jié)組織便于對(duì)照教材逐步追蹤游戲循環(huán)、輸入處理、動(dòng)畫渲染等實(shí)現(xiàn)。已有489人學(xué)習(xí)/下載適合按章節(jié)對(duì)照代碼分析游戲循環(huán)、輸入處理與渲染流程或直接復(fù)用其中的圖片、音效與場(chǎng)景進(jìn)行練習(xí)。整份源碼包結(jié)構(gòu)完整是研習(xí)Windows游戲編程難得的配套資料。1. 源碼包速覽這不只是“古董代碼”而是一套完整的游戲編程入門課先說結(jié)論這份《Windows游戲編程大師技巧第二版》源碼包是著名游戲開發(fā)者André Lamothe在2001年左右為配合同名書籍發(fā)布的配套代碼集合。如果你是在2000年代初開始接觸游戲開發(fā)大概率對(duì)這本書有印象——那會(huì)兒DirectX 7是主流Windows 2000/XP剛開始普及顯卡還叫“3D加速卡”。這個(gè)源碼包的價(jià)值不在于代碼本身有多“現(xiàn)代”而在于它完整記錄了PC單機(jī)游戲開發(fā)黃金時(shí)代的技術(shù)思路。我把它完整解壓了一份目錄結(jié)構(gòu)大概是按照書的章節(jié)組織的每個(gè)章節(jié)對(duì)應(yīng)一個(gè)子目錄里面是該章的示例工程。整體下來有幾十個(gè)項(xiàng)目從最簡(jiǎn)單的Win32窗口創(chuàng)建到完整的Direct3D程序都有覆蓋。我把目錄結(jié)構(gòu)大致梳理了一下Chapter01 - Windows基礎(chǔ)與消息機(jī)制 Chapter02 - DirectX基礎(chǔ) Chapter03 - GDI與DirectDraw入門 Chapter04 - DirectDraw高級(jí)技巧 Chapter05 - DirectInput Chapter06 - DirectSound Chapter07 - 3D數(shù)學(xué)基礎(chǔ) Chapter08 - 軟件渲染引擎 Chapter09 - Direct3D入門 及其之后章節(jié)這個(gè)結(jié)構(gòu)本身就是一個(gè)很好的游戲編程學(xué)習(xí)路徑先搞定操作系統(tǒng)層面的窗口和消息循環(huán)再接觸圖形APIDirectDraw然后處理輸入和音頻最后進(jìn)入3D渲染。說實(shí)話我自己當(dāng)年學(xué)游戲編程時(shí)就是靠著本書的章節(jié)順序一點(diǎn)點(diǎn)往過啃的。如果你是個(gè)剛接觸Windows原生開發(fā)的新手這份源碼是少見的“全鏈路”案例包。需要明確的是這個(gè)源碼包里大量項(xiàng)目使用的是DirectX 7/8 SDK部分Demo還用到了較老的DirectDraw接口在現(xiàn)代Windows系統(tǒng)上直接跑會(huì)有些問題后面我會(huì)給出解決方案。但這也恰好是它的學(xué)習(xí)價(jià)值所在源碼能讓你看到游戲引擎最底層的運(yùn)作邏輯——那些現(xiàn)在被Unity和虛幻引擎封裝得嚴(yán)嚴(yán)實(shí)實(shí)的東西在這里是赤裸裸的C代碼一幀一幀地繪制、一遍一遍地鎖表面特別能培養(yǎng)人對(duì)游戲運(yùn)行機(jī)制的本能直覺。老規(guī)矩我先給你一個(gè)全局性的觀感表格再逐塊深入拆解模塊核心技術(shù)點(diǎn)難度現(xiàn)代對(duì)應(yīng)物Win32窗口與消息循環(huán)窗口類、消息泵、定時(shí)器★★WinUI、Qt事件循環(huán)DirectDraw/GDI雙緩沖、調(diào)色板、表面翻轉(zhuǎn)★★★Direct3D 11、SDLDirectInput鍵盤、鼠標(biāo)、力反饋★★★XInput、WM_INPUTDirectSound音頻流、混音與3D音效★★★XAudio2、WASAPI3D數(shù)學(xué)向量、矩陣、四元數(shù)★★★★DirectXMath軟件渲染光柵化、深度緩沖、紋理映射★★★★★GPU管線你手上這個(gè)zip打包得還算完整。解壓后有的工程需要配置一下包含路徑和庫目錄才能編譯但代碼文件基本都在沒有哪個(gè)章節(jié)的示例莫名缺失。這很重要——因?yàn)楹芏嗬蠒涞脑创a包往往到網(wǎng)上下載下來一堆亂碼能在本地順利組織起目錄的并不多見。2. 核心技術(shù)點(diǎn)拆解從Win32到3D渲染的完整技術(shù)鏈路2.1 Win32編程基礎(chǔ)游戲主循環(huán)的“骨架”這個(gè)源碼包前幾章的示例核心就圍繞一件事在Win32下創(chuàng)建窗口并處理消息循環(huán)。很多人會(huì)覺得這有什么好學(xué)的但實(shí)際游戲開發(fā)和普通GUI程序的消息處理方式有著根本區(qū)別。普通應(yīng)用程序比如對(duì)話框程序是事件驅(qū)動(dòng)的——用戶點(diǎn)了哪個(gè)按鈕鼠標(biāo)不動(dòng)了系統(tǒng)消息過來就處理一下。但游戲程序恰恰相反它是“時(shí)間驅(qū)動(dòng)的”——不管有沒有事發(fā)生每一幀都必須被連續(xù)不斷地更新和渲染。這個(gè)源碼包里的Win32示例展示了幾個(gè)關(guān)鍵機(jī)制消息循環(huán)的寫法?;A(chǔ)版的寫法是一個(gè)while循環(huán)不斷從消息隊(duì)列里取消息翻譯并分發(fā)while (TRUE) { if (PeekMessage(msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message WM_QUIT) break; TranslateMessage(msg); DispatchMessage(msg); } else { // 執(zhí)行游戲邏輯與渲染 Game_Run(); } }這里有個(gè)與普通程序截然不同的點(diǎn)用的是PeekMessage而不是GetMessage。GetMessage會(huì)阻塞如果沒消息就卡在那兒了游戲畫面就會(huì)完全停住而PeekMessage非阻塞沒消息就直接走else分支去跑游戲邏輯保證游戲的更新不會(huì)停滯。WM_TIMER與高分辨率定時(shí)器。早期游戲常用SetTimer控制速度但這種定時(shí)器最低精度只有55毫秒搞游戲明顯不夠。源碼時(shí)的進(jìn)階示例會(huì)用timeGetTime()或QueryPerformanceCounter做高精度計(jì)時(shí)再加上幀間隔的差值計(jì)算來保證游戲速度不隨幀率變化。這個(gè)思路在后面章節(jié)的完整游戲Demo中體現(xiàn)得很明顯——每幀更新時(shí)先算幀間隔dt再把所有移動(dòng)量乘以dt這樣即使幀率從100跳到60移動(dòng)速度也不會(huì)忽快忽慢。我記得有個(gè)示例的注釋還特意寫了“如果你使用GetMessage做消息循環(huán)你的游戲就會(huì)和在泥里走路一樣慢”雖然夸張但很有畫面感。這就是經(jīng)典的“游戲幀循環(huán)”思想消息隊(duì)列負(fù)責(zé)響應(yīng)系統(tǒng)事件游戲邏輯負(fù)責(zé)連續(xù)更新世界狀態(tài)。2.2 GDI與DirectDraw2D游戲畫面生成的兩種路線這本書初版部分的內(nèi)容用的還是GDIWindows圖形設(shè)備接口做2D繪圖后來才轉(zhuǎn)向DirectDraw。源碼包很貼心地同時(shí)提供了兩種路線的示例方便對(duì)比。GDI路子最簡(jiǎn)單拿HDC句柄用BitBlt把內(nèi)存位圖“甩”到窗口客戶區(qū)。它的局限性很明顯——沒硬件加速要做半透明還得自己寫Alpha混合做動(dòng)畫一張一張BitBlt雖然能用但一旦畫面元素多起來就明顯卡頓。但作為學(xué)習(xí)圖形管線的起點(diǎn)GDI代碼簡(jiǎn)單、邏輯清晰拿來理解“幀緩沖”這個(gè)概念特別合適。DirectDraw則是當(dāng)時(shí)Windows游戲的主流選擇它的核心思想是“直接操作顯存里的表面Surface”。源碼包里最典型的示例流程是創(chuàng)建一個(gè)主表面Primary Surface通常還帶一個(gè)后備表面Back Buffer組成翻頁鏈Page Flipping Chain。在窗口模式下主表面對(duì)應(yīng)窗口客戶區(qū)全屏模式下則直接對(duì)應(yīng)整個(gè)屏幕。程序每幀鎖定后備表面往里面寫入像素然后解鎖并翻轉(zhuǎn)頁面Flip將后備表面顯示到屏幕上。// 鎖表面 DDSURFACEDESC2 ddsd; ZeroMemory(ddsd, sizeof(ddsd)); ddsd.dwSize sizeof(ddsd); lpddsBack-Lock(NULL, ddsd, DDLOCK_WAIT, NULL); // 直接寫顯存ddsd.lpSurface指向像素?cái)?shù)組 // ... 繪制像素 ... // 解鎖 lpddsBack-Unlock(NULL); // 翻頁 lpddsPrimary-Flip(NULL, DDFLIP_WAIT);注意這個(gè)lpSurface直接就是顯存區(qū)也就是說你能把每個(gè)像素的顏色值直接寫進(jìn)去。我在學(xué)習(xí)的時(shí)候最享受的就是這個(gè)環(huán)節(jié)——你能直觀地看到內(nèi)存中的字節(jié)變化如何變成屏幕上亮起來的像素?,F(xiàn)在的引擎把這些細(xì)節(jié)都封裝了你要想理解“像素到底怎么到屏幕上的”回頭翻翻這段代碼感受特別直觀。還有一個(gè)細(xì)節(jié)DirectDraw的調(diào)色板模式在源碼包里有專門示例。那個(gè)年代很多游戲用8位色256色必須用調(diào)色板索引來模擬顏色。調(diào)色板示例展示了如何創(chuàng)建一個(gè)IDirectDrawPalette裝入256個(gè)PALETTEENTRY然后設(shè)置到表面。這在當(dāng)時(shí)特別實(shí)用也是市面上“256色游戲畫面是怎么做出來的”這一問題的標(biāo)準(zhǔn)答案。2.3 DirectInput鍵盤、鼠標(biāo)與搖桿的統(tǒng)一輸入方案DirectInput那部分源碼包的示例基本涵蓋了三類常見設(shè)備鍵盤、鼠標(biāo)、游戲控制器。對(duì)于做PC游戲的人來說這套API可比老式的GetAsyncKeyState好太多——它直接輪詢?cè)O(shè)備狀態(tài)不經(jīng)過系統(tǒng)消息隊(duì)列延遲低得多。鍵盤示例就是一個(gè)枚舉設(shè)備、設(shè)置數(shù)據(jù)格式、獲取設(shè)備狀態(tài)的過程。核心結(jié)構(gòu)長(zhǎng)這樣// 創(chuàng)建設(shè)備 DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)g_pDI, NULL); g_pDI-CreateDevice(GUID_SysKeyboard, g_pKeyboard, NULL); g_pKeyboard-SetDataFormat(c_dfDIKeyboard); g_pKeyboard-SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); // 每幀讀取狀態(tài) BYTE keystate[256]; g_pKeyboard-Acquire(); HRESULT hr g_pKeyboard-GetDeviceState(256, keystate); if (FAILED(hr)) { /* 重新獲取 */ } if (keystate[DIK_LEFT] 0x80) { /* 左移 */ }鍵盤的部分好理解重點(diǎn)說說鼠標(biāo)。DirectInput中的鼠標(biāo)是相對(duì)位移模式每幀讀取的DIMOUSESTATE里lX、lY是相對(duì)上一幀的移動(dòng)量不做加速處理。這個(gè)設(shè)計(jì)在FPS游戲中特別關(guān)鍵——如果用了Windows系統(tǒng)鼠標(biāo)的“提高指針精確度”鼠標(biāo)加速會(huì)干擾視角轉(zhuǎn)動(dòng)玩家會(huì)覺得“視角在漂”。所以源碼示例在啟動(dòng)時(shí)會(huì)設(shè)置DISCL_EXCLUSIVE獨(dú)占模式從而繞開系統(tǒng)鼠標(biāo)加速讓游戲拿到的是最原始的物理移動(dòng)量。搖桿Joystick部分也值得提一句。它需要先EnumDevices枚舉可用設(shè)備再用Poll輪詢狀態(tài)很多老玩家玩飛行模擬時(shí)體驗(yàn)到的“桿子沒回中導(dǎo)致視角飄”就是因?yàn)镻oll讀取的軸偏移量沒做死區(qū)處理。這本書的源碼里其實(shí)專門有一章游戲桿校準(zhǔn)的示例處理死區(qū)和軸縮放非常實(shí)用。2.4 3D數(shù)學(xué)與軟件渲染引擎老代碼里的“硬核”部分進(jìn)入第七章之后這本書開始聊3D數(shù)學(xué)對(duì)應(yīng)的源碼里全是向量、矩陣運(yùn)算的實(shí)現(xiàn)。那個(gè)年代沒有DirectXMath庫所有數(shù)學(xué)函數(shù)都要自己寫。源碼包里有一套小型數(shù)學(xué)庫支持四元數(shù)、歐拉角、矩陣乘法等基礎(chǔ)操作代碼可讀性很高。我記得里面有個(gè)用軟件渲染實(shí)現(xiàn)的3D立方體示例沒有調(diào)用任何圖形API而是自己把頂點(diǎn)投影到屏幕上然后掃描線填充三角形。這個(gè)示例把3D渲染的核心流程展現(xiàn)得明明白白定義頂點(diǎn)坐標(biāo)模型空間用矩陣變換到世界空間再乘以攝像機(jī)矩陣變成觀察空間做透視投影得到屏幕坐標(biāo)掃描線光柵化計(jì)算顏色填充這個(gè)流程是后面所有3D引擎共通的底層邏輯但現(xiàn)在幾乎沒有教程從零開始教了。我當(dāng)時(shí)從這段代碼里學(xué)到的一個(gè)重要概念是“透視除法”——頂點(diǎn)坐標(biāo)經(jīng)過矩陣變換后是齊次坐標(biāo)要除以w分量才能得到屏幕坐標(biāo)。書上那段代碼不是特別復(fù)雜但每一步都有注釋很適合手動(dòng)調(diào)試觀察每個(gè)頂點(diǎn)的坐標(biāo)變化。讓人眼前一亮的是第十二章左右的軟件渲染引擎示例有一個(gè)簡(jiǎn)單的Z緩沖實(shí)現(xiàn)。代碼里維護(hù)了一個(gè)浮點(diǎn)數(shù)組存儲(chǔ)每個(gè)像素的深度值繪制三角形時(shí)逐像素比較深度決定要不要寫入顏色。這個(gè)實(shí)現(xiàn)雖然速度遠(yuǎn)不如當(dāng)時(shí)GPU硬件但邏輯不復(fù)雜把“深度測(cè)試”這個(gè)概念講得很清楚。我建議所有學(xué)習(xí)圖形學(xué)的人都手動(dòng)寫一遍這個(gè)環(huán)節(jié)至今我面試做圖形的人都愛問“Z緩沖算法怎么實(shí)現(xiàn)”如果只能說出概念、寫不出代碼多半是對(duì)底層流程理解不夠深刻。3. 實(shí)戰(zhàn)如何把這個(gè)源碼包“跑起來”3.1 環(huán)境準(zhǔn)備工具鏈的選擇在現(xiàn)代Windows環(huán)境跑這份源碼最直接的辦法就是安裝一個(gè)老版本的Visual C。這本書推出那年主流的編譯器是VC6和VC7Visual Studio 2002所以源碼是基于這些工具鏈寫的。很多人會(huì)覺得VC6太老、在新系統(tǒng)上安裝麻煩其實(shí)用現(xiàn)代Visual Studio比如VS2010、VS2015、VS2019打開這些工程也完全可以主要是做幾個(gè)配置調(diào)整。我自己的做法是使用Visual Studio 2015或2017選擇“空項(xiàng)目”手動(dòng)添加源碼然后配置包含目錄和庫目錄指向DX7 SDK。如果你想快速跑通也可以找一個(gè)老機(jī)器或虛擬機(jī)裝Windows XP/2000加VC6這樣最省心源碼包的編譯錯(cuò)誤也會(huì)最少因?yàn)楫?dāng)時(shí)編寫和測(cè)試的環(huán)境就是它工程文件.dsw/.dsp在老版本VS里可以無縫打開。DX7 SDK在微軟官網(wǎng)已經(jīng)下載不到了但網(wǎng)上有歷史SDK的備份。安裝好之后在VS的“工具→選項(xiàng)→項(xiàng)目和解決方案→VC目錄”里把include和lib路徑指向DX7 SDK對(duì)應(yīng)目錄。有個(gè)常見坑如果用的是VS2005以后的編譯器很多DX7頭文件里的“舊式”語法會(huì)導(dǎo)致編譯報(bào)錯(cuò)比如LPDIRECTDRAW7的定義方式。這種情況下可以直接include新版的DX頭文件比如DirectX 9 SDK是向下兼容DirectDraw 7的所以可以用DX9 SDK替代。如果你手里有DirectX 9 SDK哪怕是2008年發(fā)布的最后版本你可以用它的調(diào)試版本兼容DirectDraw效果也基本沒問題。3.2 典型的編譯步驟與直接跑通的項(xiàng)目如果你不想折騰編譯源碼包里部分示例是自帶編譯好的可執(zhí)行文件.exe的不過這些exe是2000年代初編譯的最新系統(tǒng)上運(yùn)行時(shí)可能會(huì)因?yàn)闄?quán)限、兼容性問題彈錯(cuò)。最穩(wěn)妥的方式還是自己編譯我給你一個(gè)最小化步驟清單安裝好Visual Studio我用的是VS2017實(shí)測(cè)過。下載并安裝DX7或DX9 SDK記下安裝路徑。打開源碼包中某個(gè)章節(jié)的VC工作區(qū)文件.dswVisual Studio會(huì)提示轉(zhuǎn)換為新格式點(diǎn)“完成”。右鍵項(xiàng)目→屬性配置“包含目錄”和“庫目錄”為SDK安裝路徑下的Include和Lib。編譯運(yùn)行。比較值得優(yōu)先跑的兩個(gè)項(xiàng)目一是第二章或第三章的“窗口程序模板”它不需要圖形API只做窗口創(chuàng)建和消息循環(huán)最容易跑通二是第七章的“3D數(shù)學(xué)演示”純控制臺(tái)程序不依賴任何圖形設(shè)備好調(diào)試也能直觀看到向量和矩陣的計(jì)算結(jié)果。我記得編譯時(shí)有幾處舊代碼會(huì)報(bào)錯(cuò)比如老版本的TRUE/FALSE在新SDK中與WinDef.h沖突、memset/memcpy需要包含memory.h等。見到這些報(bào)錯(cuò)不要慌按新編譯器報(bào)錯(cuò)提示改一下頭文件引用就行多數(shù)不是邏輯問題。3.3 現(xiàn)代環(huán)境下跑DirectDraw的兼容性“一攬子方案”很多讀者關(guān)心的核心問題來了在現(xiàn)代Windows上DirectDraw還能用嗎答案是可以但前提是需要進(jìn)行一些設(shè)置。Windows 8/10/11仍然保留了對(duì)DirectDraw的兼容層很多老游戲還能跑就是靠它。但窗口模式Windowed Mode下有時(shí)會(huì)出現(xiàn)畫面閃爍或無法翻頁的情況全屏模式反而更穩(wěn)定一些。具體做法找到編譯好的exe文件右鍵→屬性。切換到“兼容性”標(biāo)簽。勾選“以兼容模式運(yùn)行這個(gè)程序”選擇Windows XP SP2或SP3。在“設(shè)置”里勾選“簡(jiǎn)化的顏色模式”選擇16位或8位根據(jù)示例代碼要求來。點(diǎn)“應(yīng)用”后再試著運(yùn)行。如果運(yùn)行時(shí)遇到的報(bào)錯(cuò)是“顯卡驅(qū)動(dòng)無法支持”可以在測(cè)試代碼里將窗口模式改為“全屏獨(dú)占模式”DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN并調(diào)用SetDisplayMode設(shè)置顯示分辨率。就像程序在啟動(dòng)時(shí)會(huì)檢查DD_OK返回值一樣你也可以根據(jù)返回的錯(cuò)誤碼去搜索對(duì)應(yīng)的“DirectDraw錯(cuò)誤碼表”很多問題都能在這個(gè)表里找到官方解釋。這里還要提醒大家一點(diǎn)DirectDraw在現(xiàn)代系統(tǒng)上的兼容層不會(huì)無限制優(yōu)化性能它的像素拷貝是純CPU操作也就是說在現(xiàn)代高分辨率屏幕上玩老示例實(shí)際體驗(yàn)可能還不如在當(dāng)年的低分辨率CRT上流暢。別把它當(dāng)游戲引擎用它是學(xué)習(xí)工具通了原理就去學(xué)3D管線吧。4. 常見問題與排查技巧實(shí)錄我實(shí)際操作這套源碼時(shí)踩過不少坑這里挑幾個(gè)最典型的說一下方便你繞道。報(bào)錯(cuò)C2065:IDirectDraw未聲明。這個(gè)純屬頭文件沒包含確認(rèn)工程里include了ddraw.h并且聲明的接口是LPDIRECTDRAW7不要用舊的LPDIRECTDRAW后者在現(xiàn)代設(shè)置中大概率找不到。鏈接時(shí)找不到dxguid.lib。這是老代碼常見毛病直接在項(xiàng)目屬性→鏈接器→輸入→附加依賴項(xiàng)里加上dxguid.lib。如果不加很多guid變量比如CLSID_DirectDraw會(huì)無法解析。運(yùn)行DirectDraw程序黑屏或閃退。先試試剛才說的兼容模式不行就把代碼里的SetCooperativeLevel(hwnd, DDSCL_NORMAL)換成DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN這兩個(gè)都試過之后多數(shù)情況能解決。不過需要注意程序必須在前臺(tái)運(yùn)行才能獲取設(shè)備控制權(quán)啟動(dòng)后別切到別的窗口。編譯時(shí)期報(bào)struct DDSURFACEDESC2沒有成員dwSize。這多半是在初始化前忘了ZeroMemory結(jié)構(gòu)體。老SDK要求先清零再設(shè)大小如果沒清零會(huì)檢查出錯(cuò)。源碼包里其實(shí)都帶了但你自己找代碼改的時(shí)候容易漏。編譯成功但在運(yùn)行時(shí)提示“DirectX版本太低”。這代碼要求的是DX7但你的系統(tǒng)裝了新版DX9一般能向下兼容。如果確實(shí)不行那就換個(gè)思路下載一個(gè)DirectX修復(fù)工具在系統(tǒng)組件里讓它補(bǔ)裝一下DSound/DInput舊版DLL問題基本能解決。Qt/其他GUI環(huán)境中想用這本書的源碼做學(xué)習(xí)。那我建議你別在原生的Win32窗口上折騰了把源碼里的核心算法抽出來替換成SDL或者跨平臺(tái)框架的窗口管理。直接閱讀源碼的算法奧義比糾結(jié)在老舊的窗口通知機(jī)制里更能高效利用這本書的寶貴內(nèi)容。我還想補(bǔ)充一個(gè)排查技巧如果你在某個(gè)示例代碼里遇到莫名崩潰那大概率是“空指針”問題。源碼老加上部分示例依賴實(shí)際硬件環(huán)境比如DirectInput枚舉時(shí)沒有設(shè)備就返回空指針這時(shí)程序沒有判空就直接調(diào)用了。直接看源碼里if (!device) return這種錯(cuò)誤處理的邏輯把安全判斷補(bǔ)充完整即可。5. 經(jīng)驗(yàn)心得如何最大化利用這份源碼包嚴(yán)格來說這本書源碼配套的知識(shí)體系已經(jīng)“過時(shí)”了但作為游戲編程入門者它仍然是極好的學(xué)習(xí)素材。我個(gè)人的建議是如果你的目的是做游戲不要從源碼包里找現(xiàn)成代碼抄而是要把它當(dāng)“解剖標(biāo)本”來研究。自己動(dòng)手寫一個(gè)簡(jiǎn)化版本遇到卡住的地方翻源碼查看是怎么處理的這樣學(xué)得最快。有幾點(diǎn)個(gè)人經(jīng)驗(yàn)供你參考第一優(yōu)先閱讀注釋再看代碼。作者André Lamothe本身就是個(gè)寫作風(fēng)格非常奔放的人代碼里的注釋極其詳盡甚至有些“啰嗦”但恰恰是這些注釋提供了一個(gè)老工程師的思考過程——為什么要這樣寫是在哪里踩過坑。這種思維鏈價(jià)值遠(yuǎn)超代碼本身。第二可以拿源碼的示例和現(xiàn)代引擎實(shí)現(xiàn)做對(duì)比。比如同樣的雙緩沖機(jī)制在DirectDraw里要手動(dòng)處理鎖表面、翻頁在SDL里可能一個(gè)函數(shù)就搞定在Unity里完全不可見。這種“不同抽象層次解決同一問題”的對(duì)比能讓你對(duì)引擎設(shè)計(jì)理念有更深刻的理解。第三這個(gè)源碼包里某些代碼是可以直接遷移到現(xiàn)代項(xiàng)目里的比如3D數(shù)學(xué)庫、部分工具函數(shù)、以及獨(dú)立于API的算法。我至今還會(huì)在自己的小項(xiàng)目里把它的向量運(yùn)算拿過來改改用底子非常扎實(shí)。只是遷移時(shí)要注意內(nèi)存管理方式老代碼喜歡用裸指針和手動(dòng)new、delete現(xiàn)代代碼建議統(tǒng)一換成智能指針或容器。最后給大家一個(gè)官方能下載的“DX7 SDK補(bǔ)丁包”途徑吧微軟在github上有Microsoft/DirectX-SDK-Samples倉庫里面還有一些歷史示例。如果你手里的zip里的源碼和這個(gè)倉庫的內(nèi)容有出入也可以用倉庫的代碼做交叉閱讀。這套源碼包適合周末的時(shí)候泡杯茶靜下心來慢慢看??匆欢未a跑一個(gè)demo再對(duì)照書上的章節(jié)把原理搞明白收獲絕對(duì)不小。如果你也想重溫一下“游戲是怎么從零開始被造出來的”這份源碼包會(huì)是個(gè)非常有意思的技術(shù)考古之旅。本文還有配套的精品資源點(diǎn)擊獲取