遊戲中的隨機地圖是如何保存的?

單機遊戲,新建遊戲的時候地圖是根據隨機種子生成的,柏林雜訊處理生成具體地貌,然後在加具體裝飾物(如樹木等),場景載入完畢。請問一下,保存與載入的時候如何處理地圖呢,我的意思是terrain本身?把灰度圖,地貌等保存在文件中,載入存檔的時候在根據原始地圖重新繪製還是怎麼樣呢?


謝邀。通常我們用來程序化生成的地圖都會使用隨機種子。通過隨機種子來跳到一個數列的某個位置(比如Rand()的實現)。如果這個隨機函數滿足平台獨立、可複製性、內存佔用低的話,一般就可以用來生成地形。通過隨機種子的嵌套,我們就可以用一個種子來生成整個地形,地貌用雜訊函數來生成。

但是用隨機函數會有一些潛在的問題。

很多隨機函數會有一個熱身階段。在剛開始生成隨機數的時候會先生成幾個不那麼「隨機」的數字。

數列的長度。比如Rand()的範圍只有0~RAND_MAX(RAND_MAX根據平台不同大小也不同,但最少是32767),可能用不了多久,就會碰到和之前重複的數字。

線程安全。隨機函數一般都會有個內部全局狀態,在多線程情況下是不安全的。

幾乎不支持隨機訪問。假設我們當前處於數列的第10個數字,如果要獲取數列第1000個數字,我們只能調用990次隨機函數,顯然效率太低了;更糟的是,如果此時我們想獲取之前的數字,比如第3個,就跪了。

隨機函數有那麼多缺點,那我們用什麼?答案是雜訊函數。

雜訊函數本質上是個哈希函數。當把隨機種子加入到一個哈希值的生成過程中時,就可以利用隨機種子來生成不同的數列。如果我們用自然數作為輸入,它就像是一個數組。

它生成的數列長度幾乎是無窮的。

一個哈希函數沒有內部全局狀態,因此是線程安全的。

支持隨機訪問。這在生成地圖時非常好用。如果用隨機函數,地圖生成只能在載入時生成,因為地圖生成需要嚴格按照順序來生成。如果想實現走到哪裡生成哪裡是做不到的,因為生成順序是不一致的。而雜訊函數就可以方便的實現。同時又可以支持多線程的載入。


就拿Minecraft來舉例吧。

MC的隨機地圖是根據MC的地圖種子(seed)來生成的,只要生成地圖使用的種子(與各種其他生成參數)一樣,MC根據演算法生成出來的地圖也就一樣。因此當地圖剛被生成出來時,你會發現MC的遊戲地圖存檔也就小百KB,因為此時的所有地形只需要一個種子就能全部算出來。

當玩家進入一個地區(或者區塊 chunk)後,遊戲因為要記錄玩家對這個地區的所有操作和玩家附近的各個更新遊戲地圖的事件(比如樹草作物生長、動物更新等),因此會把這個區域的整個信息全部保存到遊戲文件中。因此你會發現一個玩得久的MC存檔由於玩家探索過的區域非常多,整個遊戲文件能到好幾GB。

所以簡單說,MC的存檔機制就是:

1. 對於沒有探索過的區塊,根據種子自行生成直到被玩家探索

2. 對於玩家探索之後的區塊,保存區塊的整個信息。

當然也有一些遊戲的存檔不會保存區域的所有信息而是選擇只記錄玩家對地圖修改了哪些部分,並用種子載入完剩餘部分,這種做法通常會減小遊戲存檔的大小,不過極大的增加了遊戲載入時間,兩種方法各有利弊。

答畢,希望對題主有幫助。

----------最後解釋一下種子(seed)是什麼吧

給一個很簡單的隨機地圖生成演算法:

給一個變數a,定義地圖在各點高度h(x,y)=ax+ay。這樣一來,我若給定一個隨意數字a,我便能生成一整張地圖來;並且我給定任意一個不同的數字,就能生成一張不同的地圖。根據這兩個特點,我就把a叫做種子。

一個遊戲要生成一張隨機地圖,唯一隨機的部分因此實際上只有給種子的這個部分(看我那個簡單的地圖定義函數就知道沒有隨機了)。真實遊戲中的地圖演算法也就只是步驟多了些複雜性罷了,並沒有本質上區別。所以我們在MC里輸種子的時候,我們只要輸入一個隨機字元串就好了。


近景terrian 至少要考慮collision,run-time隨機生成的話,硬體要求太大了,所以你說的只能是遠景,那就只是rendering,把要被interpolate的vector數據到最多到heap(可能都不用touch硬碟),然後加遠景fog。。。


本人沒有經驗,給出一個演算法上的參考

對於一個類似MC的不需要劇情的開放式遊戲而言

首先把地圖分為幾十碼x幾十碼左右為一個單位的chunk

弄一個二維數組,假設叫ChunkArray,存儲chunk的引用,默認全是null

首先開檔時只需要記錄一下種子(從說明來看答主應該知道柏林雜訊函數)

玩家修改地形之後,再在ChunkArray里初始化一個chunk存儲地形和上面的各種物體

載入玩家周圍的地形時Chunkarray[x,y]==null就根據地圖生成演算法重新生成

否則載入chunk

玩家移動的時候載入其附近的chunk,從內存中卸載較遠的chunk

利用許多語言自帶的序列化,存檔系統應該不會很難寫


保存隨機參數,對於演算法來說輸入輸出都是固定的


推薦閱讀:

數據結構存儲數據內存不夠如何解決?
零基礎自學反彙編相關的計算機知識,該如何入門,有什麼書可以推薦?
請問各位寫代碼都是從零開始嗎?比如做課程設計等。網上的源碼該如何利用?自己寫了其中多少代碼算自己寫的?
哪些編程習慣會導致內存泄漏?
如何成為一個內力深厚的程序員?正確的補充計算機基礎知識?

TAG:遊戲 | 編程 | Unity遊戲引擎 |