最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

基于瓦片(Tilemap)的隨機(jī)地圖生成

2023-02-21 12:57 作者:引力餛飩  | 我要投稿

RougeLike游戲中很常見的元素就是隨機(jī)地圖,最近項(xiàng)目上也需要制作,在此記錄一下制作方法。

以下是通過Unity中的Tilemap便可簡單實(shí)現(xiàn)的隨機(jī)地圖效果。

繪制使用了Unity,但生成方法不局限于Unity,理論上可以搬到任意平臺(tái)。


1.準(zhǔn)備工作

1.1?板塊布局

為了避免所有地圖都過于相似,我們將大地圖細(xì)分為了30x30的板塊,意味著一個(gè)板塊內(nèi)包含了900個(gè)瓦片單位。

通過將任意數(shù)量的板塊排列組合,地圖可以呈現(xiàn)出不同的結(jié)構(gòu)。

調(diào)整板塊數(shù)量,可以控制整張地圖的規(guī)模。在未來地圖過大時(shí),也可以通過分區(qū)塊加載來優(yōu)化性能。

如果你的地圖并不大,或不需要呈現(xiàn)出不同的構(gòu)造,可跳過此步。

5個(gè)板塊布局

以上是擁有5個(gè)板塊的地圖能呈現(xiàn)出的部分形態(tài)。

這部分可以手動(dòng)配置,也可以通過程序生成,以下是一段示例的代碼。

以上代碼中得到的結(jié)果為板塊的相對(duì)位置,我們將其乘30(每個(gè)板塊的邊長),即可得到實(shí)際的位置。


1.2?板塊布局地圖元素分層

根據(jù)策劃需求,我整理出了地圖的結(jié)構(gòu),按照渲染的順序,由底至上分出了以下幾層。

注:由于我們做的是一個(gè)開船的游戲,所以是水面和陸地,如果你是一款主要在陸地上的游戲,可對(duì)應(yīng)為地面和山峰(或其他阻擋區(qū)域)。

這個(gè)結(jié)構(gòu)并不重要,你可以跳過,唯一重要的是【陸地】層,也就是大多數(shù)游戲中的“墻壁”,我在后續(xù)也會(huì)以墻壁稱呼它,這一層決定了地圖整體長成什么樣子。

地圖的結(jié)構(gòu)

以上結(jié)構(gòu)可以根據(jù)你的項(xiàng)目需求任意調(diào)整。

有了以上信息,就可以開始逐層制作了。



2.程序化生成

2.1?基礎(chǔ)地形

先把裝飾性元素放一邊,整個(gè)地圖其實(shí)都可以簡化為“地板”和“墻壁”,也就是可行走區(qū)域和不可行走區(qū)域,這個(gè)數(shù)據(jù)可以通過兩個(gè)數(shù)字來代表(比如0和1)。

而整個(gè)地圖的數(shù)據(jù),可以存儲(chǔ)在一個(gè)2維數(shù)組中,每個(gè)數(shù)組元素表示此處是什么地塊。

這個(gè)數(shù)組的大小,應(yīng)當(dāng)取決于前一步生成出的布局,通過找出x和y軸最小和最大之間的距離即可得出。

同時(shí),可以將壓根無法被看到的區(qū)域,寫入一個(gè)特殊的值(比如-1),在后續(xù)的運(yùn)算中,忽略這些格子,避免花費(fèi)太多性能用于生成這些根本看不見的區(qū)域上。

以下是偽代碼:

經(jīng)過上述步驟,將會(huì)得到一個(gè)“被掏空”的矩形。

基礎(chǔ)地形

其中灰色部分代表不可見區(qū)域,藍(lán)色代表可見區(qū)域。

接下來,需要在每個(gè)區(qū)塊邊緣設(shè)置基礎(chǔ)的墻壁,只需要檢查每個(gè)格子距離區(qū)塊邊緣的距離即可,距離決定了墻壁的“厚度”,厚度太小可能會(huì)穿幫,導(dǎo)致看到外面的沒有生成地形的區(qū)域。這個(gè)值取決于攝像機(jī)的設(shè)置,你可以經(jīng)過計(jì)算得出,不過更簡單的做法是先隨便填一個(gè)隨后慢慢調(diào)整。

同時(shí)還要檢查相應(yīng)方向上,是否有其他相鄰區(qū)塊。避免生成的墻壁隔斷兩個(gè)區(qū)塊。

以下是偽代碼:

經(jīng)過此步驟,地圖上會(huì)在區(qū)塊邊緣生成一定厚度的墻壁,如下所示:

生成墻壁


2.2?隨機(jī)擺放的獨(dú)立墻壁塊

這一步可忽略,你可以跳到2.3。

目前中間的區(qū)域還是太開闊了,出于美觀,我在其中放了一些“島嶼”。

放置的規(guī)則也很簡單,隨機(jī)找到任意大?。ɡ?x5)的空間,然后填入墻壁編號(hào)即可

重復(fù)以上過程N(yùn)次,即可得到一大堆雜亂擺放的墻壁塊。

(因?yàn)橹谱鲌D片比較麻煩,我這里直接用游戲內(nèi)的素材進(jìn)行展示了,將數(shù)據(jù)繪制出來的方法可在后面看到。)

獨(dú)立墻壁塊

需要注意的是:多個(gè)隨機(jī)寫入的墻壁塊可能會(huì)阻斷你的區(qū)域,形成一片孤立區(qū)域。

被隨機(jī)墻壁塊阻斷的情況

一個(gè)簡單的處理辦法是,生成一個(gè)寬高都+2的塊,寫入這些墻壁塊之前,檢查塊中每個(gè)格子上是否已經(jīng)存在墻壁,如果存在則舍棄掉這次,并且在寫入時(shí)將大小-2。


2.3?隨機(jī)擺放的獨(dú)立墻壁塊

現(xiàn)在已經(jīng)有個(gè)一個(gè)基本的地形了,但邊緣太過平整,看起來不像是天然形成的自然景觀(海岸線),需要讓它有些變化。

為此需要定義一個(gè)函數(shù),我稱之為“生長”函數(shù),讓墻壁就像植物一樣從平整的墻面長出來。

這個(gè)函數(shù)需要對(duì)每一個(gè)格子進(jìn)行判斷:

首先,它必須是一個(gè)空的格子;

其次,它的四個(gè)方向上需要有任意一個(gè)方向是墻體;

最后,通過一個(gè)隨機(jī)檢查(比如有30%的概率)將這個(gè)格子變?yōu)閴w。

至于為什么只能有一個(gè)方向是墻壁,后面會(huì)提到。

偽代碼如下:

將上述代碼重復(fù)執(zhí)行數(shù)次,迭代次數(shù)越多,生成的越多。我們的地圖會(huì)變成這樣。

(注意,我用到的隨機(jī)參數(shù)并非上述代碼中的參數(shù),所以結(jié)果可能會(huì)看起來不一樣。)

隨機(jī)擺放的獨(dú)立墻壁塊


2.4?平滑

這一步是可選項(xiàng),你可以跳過。

上面的地圖已經(jīng)有些形狀了,但部分地方向外突出的太“尖銳”,看起來不夠自然。

因此需要做一些平滑處理,我又聲明了一個(gè)“平滑”函數(shù),平滑的過程非常簡單。

在上一步中,我只用到了那些只相鄰一塊墻壁的空塊,而這一步,則是用到相鄰2、3、4塊的,代碼部分幾乎一樣。

我在每種相鄰情況下,都給予了不同的概率,這可以控制地圖的“豐滿程度”。

其實(shí)這一步可以跟上一步“生長”合并,但根據(jù)實(shí)際項(xiàng)目需求,我還是拆分為了2個(gè),便于控制地圖的生成??傊憧梢愿鶕?jù)需要將它們合并或者拆分。

最后,同樣迭代數(shù)次。地圖大概會(huì)變成這個(gè)樣子:

(注意,我用到的隨機(jī)參數(shù)并非上述代碼中的參數(shù),所以結(jié)果可能會(huì)看起來不一樣。)

獨(dú)立墻壁塊平滑結(jié)果


2.5 其他的一些裝飾層

剩下的步驟都大同小異,基本上和之前一樣:

(1)遍歷每個(gè)格子

(2)判斷這個(gè)格子和相鄰格子的情況

(3)寫入數(shù)據(jù)

例如,要為墻壁的外輪廓添加一圈陰影,那就:

(1)遍歷每個(gè)格子

(2)檢查相鄰格子是不是墻壁

(3)寫入“陰影數(shù)字”

最終在游戲中呈現(xiàn)的效果如下:

添加裝飾層后的效果



3.繪制篇

3.1 Rule Tile

這是個(gè)可選的組件,如果不需要,你可以跳過此步。

對(duì)于渲染瓦片地圖,Unity自帶的Tilemap已經(jīng)可以做到。

但我們可以安裝一個(gè)Unity的額外擴(kuò)展包來更方便的完成。在Unity菜單中選擇:Window -> Package Manager,并安裝“2D Tilemap Extras”這個(gè)包。

這個(gè)包內(nèi)提供了“Rule Tile”組件,可以根據(jù)規(guī)則自動(dòng)調(diào)整Sprite,簡單形容就是,當(dāng)這個(gè)塊是“轉(zhuǎn)角”的情況下,自動(dòng)調(diào)整為“轉(zhuǎn)角磚塊”。

界面如下:

Rule Tile組件

綠色箭頭表示此方向上有其他瓦片,紅色叉表示沒有。

其余部分可以參考此處官方教程。https://learn.unity.com/tutorial/using-rule-tiles


3.2?通過數(shù)據(jù)進(jìn)行繪制

在上述步驟中,我們已經(jīng)得到了一個(gè)巨大的數(shù)組,包含了地圖上每一個(gè)格子的數(shù)據(jù)。

這一步需要將其繪制出來。

對(duì)于每一層,我們都需要?jiǎng)?chuàng)建一層獨(dú)立的Tilemap,并將他們按照順序進(jìn)行顯示??梢酝ㄟ^調(diào)整面向攝像機(jī)的軸(2d游戲中一般是Z)調(diào)整渲染順序。

剩下的工作十分簡單,讀取數(shù)組中每一個(gè)元素,根據(jù)元素的編號(hào),在對(duì)應(yīng)的層上填入格子。

偽代碼如下:

你還可以添加額外的繪制規(guī)則,例如,當(dāng)此處的值> 30并且< 50的話,設(shè)置為草地瓦片。


3.3?裝飾性元素

因?yàn)檫@部分根據(jù)項(xiàng)目的不同會(huì)有很大變化,因此你需要自己選擇合適的方式。

例如:

裝飾石頭

你可以將這塊石頭,按照瓦片的尺寸切割成數(shù)個(gè)瓦片,然后通過某種規(guī)則找到合適的位置進(jìn)行擺放,比如和之前一樣遍歷每個(gè)格子和相鄰格子的辦法。

例如,你想在墻壁的右側(cè)添加一些1格瓦片大小的裝飾,那就遍歷每個(gè)格子,檢查:

(1)它是否是墻壁

(2)它的右側(cè)是否是空地

也可以將其作為獨(dú)立的貼圖,通過SpriteRenderer直接放置在世界空間下的合適位置。


4.附錄

性能問題:

本篇文章僅介紹了方法,并未從性能方面去考慮,在不同的項(xiàng)目上,性能的問題可大可小,很難一概而論。

如果你的地圖非常大,那么構(gòu)建一個(gè)大數(shù)組并逐項(xiàng)遍歷速度可能會(huì)十分感人,你可能需要將其拆分成許多份。你還可以將數(shù)組轉(zhuǎn)化為一張貼圖,通過顏色值記錄格子的信息,并將運(yùn)算過程放入GPU中,理論上或許會(huì)快很多,但我沒有測試過。


參考資料:

這套生成的規(guī)則主要參考了元胞自動(dòng)機(jī)。

關(guān)于元胞自動(dòng)機(jī)的地圖生成,可以參考這篇文章。https://blog.jrheard.com/procedural-dungeon-generation-cellular-automata


除此之外,還有許多程序化生成地圖的方式:

波函數(shù)坍塌:https://www.procjam.com/tutorials/wfc/

通過噪波圖生成:https://www.redblobgames.com/maps/terrain-from-noise/

通過維諾圖生成:http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/

不同的方式都有各自的優(yōu)勢(shì),可以根據(jù)實(shí)際情況進(jìn)行選擇。

最后,感謝閱讀!

基于以上方法生成的《深海傳奇》四種地貌的隨機(jī)地圖


基于瓦片(Tilemap)的隨機(jī)地圖生成的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
昂仁县| 贵德县| 贡觉县| 如皋市| 萨迦县| 额济纳旗| 株洲市| 临清市| 年辖:市辖区| 巍山| 芷江| 东明县| 丰宁| 桐庐县| 华亭县| 南昌市| 阜康市| 新民市| 芦山县| 澄城县| 故城县| 屯留县| 上杭县| 许昌市| 全南县| 蛟河市| 黄山市| 秦安县| 水城县| 内黄县| 渭源县| 中卫市| 泾源县| 铁岭县| 新巴尔虎右旗| 辽阳市| 台中县| 庆元县| 四平市| 海城市| 桓仁|