常規遊戲編程指導

下面討論一下讀者所關心,也是遊戲編程常用的技術和基本原理,這有利於簡化遊戲編程的複雜程度。 首先,視頻遊戲是運行於超高性能計算機上的遊戲程序。對於時間或內存要求特別嚴格的代碼部分不能使用高級API來編程,和遊戲代碼內部盾環有關的部分,大都需自已手工編寫,否則遊戲將會碰到嚴重的速度和性能問題。當然,這並不意味着就不能信任DirectX等API編程工具,因爲DirectX以高性能和心可能“瘦”的方式編寫。但在通常情況下,要避免高級的函數調用。 除上述情況應多加註意外,在編程時還應留意下面的編程技巧。

 

技巧:不要怕使用全局變量,許多視頻遊戲不使用大量的帶有形參的、與時間相關的函數,而是使用一個全局變量來代替,例如一個函數的代碼如下:

void Plot(int x,int y,int color)

{ //在屏幕上畫一個點像素

   video_buffer[x + y * MEMORY_PITCH] = color;

}

//結束Plot 函數體運行的時間小於函數調用所需的時間。

這是由於參數壓入和彈出堆棧造成的。在這種情況下,更好的方法可能是創建一個全局變量,然後在調用前進行賦值,像下面一樣:

int gx,gy,gz,gcolor;//定義一些全局變量
void Plot_G(void)

{

//使用全局變量來畫一個點像素

video_buffer(gx + gy * MEMORY_PITCH] = gcolor;

}//結束Plot_G

 

技巧:使用內聯功能。通過使用內聯指令來完全擺脫調用功能甚至能夠改善上面的技巧。內聯指令不調用函數,而指示編譯器將被調用函數代碼放在需要調用該函數的最佳位置,這樣做會使程序變得更大,但卻提高了運行速度。下面是一個實例。

 inline void Plot_I (int x,int y,int color)

{ //在屏幕上畫一個點像素

video_buffer[x + y * MEMORY_PITCH] = color;

}//結束Plot_I

 注意:這裏並沒有使用全局變量,因爲編輯器有效運行了相同類型數據的別名,但是全局變量遲早會派上用場,如果在函數調用時,一個或兩個形參已改變,由於沒有重新加載,所以舊的參數值有可能仍被使用。

技巧:儘量使用32位變量而不用8位變量或16位變量,Pentium和之後的處理器全部都是32位的,這就意味着它們並不喜歡8位或16位的數據字符,實際上,更小的數據可能會由於超高速緩存和其他相關的內存尋址異常而使速度下降,例如,讀者可能創建一個如下所示的結構: struct CPOINT { short x,y; unsigned char c; }//結束CPINT

儘管這個結構看上去很好,但實際並非如此!首先,結構本身目前是一個5字符長的結構——2個short+1個char=5。這實際上是一個很差的設計,這將導致內存地址崩潰。更好的結構形式如下:

 struct CPOINT { int x,y; int c; }//結束CPINT
C++ 提示:除了默認的公共可見性外,C++中的結構更像是“類”。

這種新結構要更好一些。首先,所有的成員都是相同尺寸——也就是說整數的大小爲4字節。因此,單個指針可以通過遞增DWORD(雙字節)的邊界訪問任何單元。當然,這種新結構的大小 就是3個整數長,即12字節,至少是4的倍數,或者在DWORD邊界上。這樣將明顯地提升性能。 實際上,如果讀者真想穩妥地話,應當將所有的結構都變爲32字節的倍數。
由於Pentium家庭處理器芯片上標準緩存線長度是32倍數,因而這是一個最佳長度。可以通過人工虛設單元或者使用編輯指令(最簡單的方法)來滿足這個要求。當然,這可能會浪費大量的內存,但是爲了提高速度這是值得的。

技巧:註釋你的代碼,遊戲程序員不註釋代碼是出了名的,不要犯相同的錯誤。用額外的輸入換取整潔,註釋良好的代碼是值得的。
技巧:程序應以類似RISC(精簡指令系統計算機)的形式來編寫。換句話說,儘量簡化你的代碼,而不是使它更復雜。Pentium和PentiumⅡ處理器特別喜歡簡單指令,而不是複雜的指令,你的程序可以長些,但應儘量使用簡單指令,使程序相對於編輯器來說更加簡單些。例如,不要編寫類似下面的程序:

if((x+=(2*buffer[index++])>10) { //進行工作 }//結束
應這樣做 x+=(2*buffer[index]); index++ if(x>10) { //進行工作 }//結束if

技巧:按照這種方式來編寫代碼有兩個原因,首先,它允許調試程序在代碼各部分之間放置斷點;第二,這將更易於編譯器向Pentium處理器傳送簡單指令,這樣將使處理器使用更多的執行單元並行地處理代碼。複雜的代碼就比較糟糕。

技巧:按照這種方式來編寫代碼有兩個原因,首先,它允許調試程序在代碼各部分之間放置斷點;第二,這將更易於編譯器向Pentium處理器傳送簡單指令,這樣將使處理器使用更多的執行單元並行地處理代碼。複雜的代碼就比較糟糕。
對於簡單的、是2的倍數的整數乘法運算,應使用二進制移位運算。因爲所有的數據在計算機中都以二進制存儲,位組合向左或右移動就等同於乘法和除法運算。例如: int y_pos = 10 //將y_pos乘以64 y_pos = (y_pos << 6);//2^6=64
相似的有
{ //將y_pos除以8 y_pos = (y_pos >> 3);//1/2^3=1/8 當讀者接觸到優化那一章時,將會發現更多的、類似的技巧。哈哈,酷吧!
技巧:編寫高效的算法。世界上所有的彙編語言都不會將n^2算法運行得更快些,更好的方法是使用整齊、高效的算法而不是蠻幹。

技巧:不要在編程過程中優化代碼。這通常會浪費時間。等到完成主要的代碼塊或整個程序後纔開始進行繁重的的優化工作。這樣可以節省你的時間,因爲你必須處理一些模糊的代碼或不必要的優化。當遊戲編程完成時,纔到了剖析代碼、查找問題以優化程序的時間。另一方面,程序要注意錯落有致,不要雜亂無章。

技巧:使用C++應謹慎。如果讀者是位老練的高手,繼續前進去做你喜歡的事,但是不要去瘋狂追求類,或使遊戲程序過於複雜以至於超出一般計算機的承受能力,簡單、直觀的代碼是最好的程序,也最容易調試。我從來都不想看多重的隸屬關係。

技巧:如果感到前路荊棘叢生,那就停下來,回頭然後繞路而行,我見過許多遊戲程序員開始於一條很差的編程路線,然後葬送自己。能夠意識到自己所犯的錯誤,然後重新編寫500行的代碼要比得到一個不是期望的代碼結構要好得多,因此,如果在工作中發現問題,那就要重新評估並確保它是值得花時間補救的。
技巧:經常備份你的工作。在編寫遊戲代碼時,需要相當頻繁地鎖定系統。重新做一個排序算法比較容易,但是要爲一個新角色或碰撞檢測重新編寫AI則是另一回事。

技巧:在開始你的遊戲項目之前,進行一下組織工作,使用合理的文件名和目錄名,提出一種一致的變量命名約定,儘量對圖形和聲音數據使用分開的目錄,而不是將其全部都放置在一個目錄中。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章