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

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

用Unity蓋房子(三)——《勇者斗惡龍:建造者2》自動(dòng)建造

2019-07-11 17:06 作者:皮皮關(guān)做游戲  | 我要投稿

作者:沈琰


前言

最后一篇文章,來(lái)把這個(gè)坑填完。

接上期:用Unity蓋房子(二)——《勇者斗惡龍:建造者2》地形生成和人物控制

上期內(nèi)容中搞定了無(wú)限地形的生成和建造功能的實(shí)現(xiàn),現(xiàn)在總算站在了實(shí)現(xiàn)最初設(shè)想功能的起點(diǎn)上,即讓AI按設(shè)計(jì)圖自動(dòng)建造建筑。

先大致思考一下實(shí)現(xiàn)的步驟吧。

首先是設(shè)計(jì)圖的部分。不管是像原版一樣是放到背包里的道具還是說(shuō)在場(chǎng)景中把待處理的方塊都顯示出來(lái),設(shè)計(jì)圖從本質(zhì)上來(lái)說(shuō),都是一個(gè)數(shù)據(jù)的集合。其中存儲(chǔ)的是限定范圍內(nèi)的方塊數(shù)據(jù),而我們要做的事就是以鼠標(biāo)擊中的位置為基點(diǎn),讓這些數(shù)據(jù)以我們預(yù)想的排列方式傳遞到chunk上。

其次是自動(dòng)建造的AI。這里的主要難點(diǎn)就是如何在一個(gè)不斷變化的地形中正確尋路,以及多個(gè)AI協(xié)同工作的問(wèn)題。

下面就以這個(gè)順序分別實(shí)現(xiàn)以上功能。

另外這期就盡量不貼代碼,只說(shuō)思路。由于代碼會(huì)在實(shí)現(xiàn)過(guò)程中反復(fù)修改,直接貼的效果也不好,如果大家對(duì)實(shí)現(xiàn)方式有疑問(wèn),可以下載文章末尾的工程。

建造模式預(yù)覽

上期還留了一個(gè)坑忘了寫,這期就合并在一起說(shuō)了,即建造時(shí)方塊的朝向控制。

之前我們用一個(gè)鏤空的框來(lái)表示當(dāng)前選中的位置,在刪除模式時(shí)看起來(lái)似乎還行,但在建造模式時(shí)是無(wú)法顯示當(dāng)前方塊的朝向的,因此在建造模式時(shí)直接把選中的方塊按類型以mesh的方式顯示出來(lái),新建一個(gè)腳本來(lái)處理這個(gè)問(wèn)題。

這個(gè)腳本的作用與chunk類似,都是根據(jù)數(shù)據(jù)生成mesh信息,所以這里面也需要對(duì)mesh的引用。不同的地方則是它可以旋轉(zhuǎn)朝向,旋轉(zhuǎn)的方式就是用的上一期說(shuō)的自己寫的一個(gè)簡(jiǎn)易四方向矩陣變換。因此方塊不是真的自己轉(zhuǎn)向了,而是方塊的每個(gè)頂點(diǎn)的相對(duì)位置變了。

然后材質(zhì)球就用和chunk一樣的,只不過(guò)稍微改一下shader,使其顯示為半透明。之前找材質(zhì)貼圖的時(shí)候特意找了一個(gè)能表示方向的,剛好能派上用場(chǎng)。

這還不算完,現(xiàn)在有個(gè)問(wèn)題。朝向不同的方塊處于相鄰位置時(shí)對(duì)相鄰邊的隱藏判斷會(huì)出錯(cuò)。

這是因?yàn)樾D(zhuǎn)方塊的朝向是相對(duì)于方塊自己的朝向,而chunk中的相鄰邊檢測(cè)用的是相對(duì)于chunk的方向,因此這里在檢測(cè)是修正一下檢測(cè)方向就能解決問(wèn)題。

設(shè)計(jì)圖模式預(yù)覽

現(xiàn)在把這個(gè)功能擴(kuò)展到顯示一個(gè)指定區(qū)域內(nèi)。設(shè)計(jì)圖模式的功能大致能分成兩部分,一個(gè)是指定一個(gè)區(qū)域copy地形數(shù)據(jù)的復(fù)制功能,一個(gè)是根據(jù)指定區(qū)域位置去修改chunk數(shù)據(jù)的建造功能,即getData與setData的區(qū)別。

我的想法是,當(dāng)處于getData的模式時(shí),用代碼生成一個(gè)預(yù)覽框顯示獲取數(shù)據(jù)的范圍,而在SetData的模式下除了這個(gè)預(yù)覽框,還要用半透明材質(zhì)生成mesh 顯示當(dāng)前的方塊數(shù)據(jù)。此外,不管是哪種模式,這個(gè)區(qū)域都是基于當(dāng)前鼠標(biāo)位置可旋轉(zhuǎn)的。

建造模式的旋轉(zhuǎn)方式

這個(gè)功能還是屬于PreviewBox這個(gè)腳本的功能范疇。為方便后面功能的實(shí)現(xiàn),我們先假設(shè)這個(gè)區(qū)域是一個(gè)正方體,這樣只需一個(gè)int值就能表示區(qū)域大小。后面的思路就是根據(jù)朝向來(lái)把這塊區(qū)域分成與cube大小相同的空間,找到它的起始點(diǎn)。然后以此為基點(diǎn)獲取所有的方塊中心點(diǎn)并存入數(shù)組中。

那么剩下的思路就清晰了,再新建一個(gè)byte數(shù)組來(lái)存儲(chǔ)方塊的數(shù)據(jù),接下來(lái)我們就需要保證坐標(biāo)數(shù)組和數(shù)據(jù)數(shù)組中的索引總是能正確地一一對(duì)應(yīng),并使用這些數(shù)據(jù)完成getData和setData功能。

復(fù)制功能

復(fù)制功能的預(yù)覽mesh用框不太好去設(shè)計(jì)紋理的樣式,原本想的是用鏤空的正方體框形來(lái)表示,由于在建造時(shí)方塊的數(shù)據(jù)預(yù)覽會(huì)與之疊加,為了不會(huì)遮擋方塊,這里選擇生成一個(gè)貼地的矩形面來(lái)表示區(qū)域的大小。還是根據(jù)坐標(biāo)計(jì)算出頂點(diǎn),并傳遞數(shù)據(jù)到mesh中。

最后在unity商店里找了個(gè)帶邊緣輪廓的材質(zhì)作為其材質(zhì)球。

建造功能

有前面的基礎(chǔ),建造功能此時(shí)就只需加上其包含的方塊數(shù)據(jù)的預(yù)覽mesh,這個(gè)部分與chunk干的活類似,只有一點(diǎn)要注意,即剛才說(shuō)到的保證坐標(biāo)數(shù)組的下標(biāo)與數(shù)據(jù)數(shù)組的下標(biāo)的對(duì)應(yīng)關(guān)系正確。

目前為止看起來(lái)都沒(méi)什么問(wèn)題,接著就是實(shí)現(xiàn)數(shù)據(jù)的get和set功能。

然后試試效果,這個(gè)時(shí)候問(wèn)題就來(lái)了。

朝向問(wèn)題的修正

首先是setData模式時(shí),方塊mesh預(yù)覽的隱藏面問(wèn)題。有了之前的經(jīng)驗(yàn)大概就能猜出問(wèn)題出在哪了。顯然就是在旋轉(zhuǎn)預(yù)覽框時(shí)的相對(duì)朝向和方塊自己的朝向之間的問(wèn)題。咱們先不慌修改,再看看其他問(wèn)題。

可以看到除了預(yù)覽為初始朝向時(shí),setData時(shí)的方塊朝向基本全錯(cuò)了。這其實(shí)也好理解,當(dāng)我們?cè)谛D(zhuǎn)預(yù)覽區(qū)域時(shí),可以看做是直接修改了方塊的絕對(duì)朝向。那么同理,getData時(shí)也要修正獲得的方塊數(shù)據(jù)的朝向。

都像chunk處理方塊相鄰方向那么去寫,代碼就顯得太難看了。因此干脆在朝向枚舉那里加兩個(gè)擴(kuò)展方法去處理朝向修正問(wèn)題。

然后在getData、setData和預(yù)覽mesh相鄰邊檢測(cè)時(shí)修正相對(duì)朝向。

修正之后一切都符合預(yù)期了。

chunk的第二個(gè)mesh組件

現(xiàn)在相當(dāng)于是直接把數(shù)據(jù)更新到chunk里,但我們要的只是起一個(gè)指示和預(yù)覽作用的mesh,最大的區(qū)別是它不該有碰撞。

所以在chunk的預(yù)制體下多加一個(gè)mesh,當(dāng)發(fā)現(xiàn)當(dāng)前的cube數(shù)據(jù)為透明時(shí),就把數(shù)據(jù)傳遞到第二個(gè)mesh里。

AI的自動(dòng)建造

接下來(lái)就是重點(diǎn)功能的實(shí)現(xiàn)了,這部分的核心就是尋路。

2D平面的尋路功能相信大家已經(jīng)不陌生了,如果有這部分不太熟悉的同學(xué),推薦去看專欄里的另一篇文章。傳送門:給貓看的游戲AI實(shí)戰(zhàn)(四)眼見為實(shí)——讓AI的思考過(guò)程可視化

但我們這里的尋路稍微有點(diǎn)不一樣,它不是平面的而是立體的。這里我們簡(jiǎn)化一下思路,把方塊與方塊之間的連線作為路徑,那么地圖仍然可以看做是無(wú)向圖。估算一下規(guī)模,目前的默認(rèn)地圖為4x4個(gè)chunk,算上立體結(jié)構(gòu)節(jié)點(diǎn)也應(yīng)該不會(huì)超過(guò)1萬(wàn)個(gè),所以就用最簡(jiǎn)單的廣度優(yōu)先搜索(BFS)就行。

新建一個(gè)腳本來(lái)編寫AI,定義一下尋路的規(guī)則。一圖流表示路徑規(guī)則:

把這個(gè)邏輯轉(zhuǎn)換為代碼:

然后根據(jù)判斷條件寫一個(gè)簡(jiǎn)易的BFS,由于路徑不一定都有,所以還要處理當(dāng)尋不到路徑時(shí)的情況,這里的邏輯就是維護(hù)一個(gè)最近的節(jié)點(diǎn),當(dāng)尋不到路時(shí)就返回這個(gè)最近點(diǎn)。

現(xiàn)在把這個(gè)腳本掛在主角身上,把路徑畫出來(lái)測(cè)試一下效果:

可以看到路徑?jīng)]問(wèn)題,那接下來(lái)就是根據(jù)這個(gè)路徑走過(guò)去,把方塊擺到預(yù)覽的位置,然后切換到下一個(gè),中間還要加上角色的動(dòng)畫和移動(dòng)過(guò)程。這部分沒(méi)什么難度,就跳過(guò)了,直接看效果。

多目標(biāo)協(xié)作

現(xiàn)在單個(gè)AI的功能沒(méi)問(wèn)題了,來(lái)考慮多目標(biāo)協(xié)作的問(wèn)題。最顯著的問(wèn)題是NPC的建造會(huì)影響其它NPC的路徑。比如A在B的路徑上放了一個(gè)方塊,那么B的路徑就需要更新。

最簡(jiǎn)單的辦法就是在每個(gè)AI放置方塊時(shí),通知其它所有的AI路徑需要更新。

然后其它AI在運(yùn)行時(shí)根據(jù)這個(gè)bool值去刷新自己的路徑:

最終得到的效果:

現(xiàn)在基本達(dá)到預(yù)期效果了,但還留下了兩個(gè)問(wèn)題:

1.現(xiàn)在用了一個(gè)自定義的類型來(lái)管理路徑節(jié)點(diǎn),當(dāng)AI較多時(shí),同時(shí)更新路徑是生成節(jié)點(diǎn)過(guò)多,會(huì)產(chǎn)生較大的GC壓力。

2.當(dāng)AI處于移動(dòng)中時(shí)無(wú)法更新路徑,導(dǎo)致有些時(shí)候AI看起來(lái)像是從方塊里走出來(lái)一樣。

這兩個(gè)問(wèn)題就先留給大家思考一下,后續(xù)更新的我再來(lái)修改。

那么這個(gè)坑到這里就算是填完了,感謝大家觀看至此。

本期工程地址:https://github.com/tank1018702/CubeBuilder


有意向參與線下游戲開發(fā)學(xué)習(xí)的童鞋,歡迎訪問(wèn)levelpp.com/。

用Unity蓋房子(三)——《勇者斗惡龍:建造者2》自動(dòng)建造的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
望奎县| 汝州市| 巨野县| 霍山县| 平原县| 石门县| 克拉玛依市| 泌阳县| 若羌县| 岳普湖县| 邛崃市| 从江县| 呈贡县| 康定县| 陆川县| 滨州市| 囊谦县| 邯郸市| 醴陵市| 烟台市| 泊头市| 尚志市| 台中县| 汤阴县| 鸡西市| 绥德县| 阳信县| 深州市| 普宁市| 长子县| 望都县| 虎林市| 社旗县| 乌兰察布市| 布尔津县| 工布江达县| 十堰市| 盐边县| 宜城市| 富蕴县| 静宁县|