MC1.12.2的AI系統(tǒng)簡(jiǎn)述
MC提供了一套比較靈活的AI系統(tǒng),但目前主要用于動(dòng)物、村民和怪物。如果玩家可以自定義一種生物,以及它的AI,想必是個(gè)不錯(cuò)的補(bǔ)充。
在《理想境》里,“另我離影”召喚出的分身具有三種行為模式:跟隨、攻擊、守護(hù)。不過,這三個(gè)行為模式并不是各對(duì)應(yīng)一個(gè)AI。它們對(duì)應(yīng)了三種不同的AI組合。
在MC 1.12.2里,AI系統(tǒng)分為兩類:行為AI(EntityAIBase)和索敵AI(EntityAITarget extends?EntityAIBase),它們歸屬兩個(gè)不同的AI列表。
每個(gè)AI列表里有若干任務(wù),每一個(gè)都有優(yōu)先級(jí),同一列表里,優(yōu)先級(jí)序號(hào)越小的越優(yōu)先執(zhí)行。不同隊(duì)列之間沒有優(yōu)先級(jí)比較可言。
舉例來說,“尋找附近的玩家作為目標(biāo)”是索敵AI,我把它扔進(jìn)索敵列表,優(yōu)先級(jí)序號(hào)設(shè)為3;“沖鋒并近戰(zhàn)攻擊”是行為AI,我把它扔進(jìn)行為列表,優(yōu)先級(jí)序號(hào)設(shè)為2。這兩者組合在一起,就能制作一個(gè)看到玩家就撲過來的敵人。少了索敵的部分,或者少了攻擊的部分,都會(huì)導(dǎo)致該生物對(duì)玩家無(wú)動(dòng)于衷。雖然“會(huì)攻擊玩家”在認(rèn)知上只是一件事,但是它在mod實(shí)現(xiàn)里實(shí)際上是拆成兩半做的。
看到這里,我群里某個(gè)總喜歡挑戰(zhàn)我極限的群友就該問了:
假如把索敵AI扔進(jìn)行為列表,把行為AI扔進(jìn)索敵列表會(huì)怎樣?
我看到這個(gè)問題會(huì)非常生氣:你聽聽,這是碳基生物能干出來的事嗎?
要回答這個(gè)問題,要從MC AI的本質(zhì)上說起。AI對(duì)象主要包括這么幾個(gè)東西:?jiǎn)?dòng)條件、繼續(xù)條件、互斥鎖狀態(tài)、執(zhí)行時(shí)的update代碼。無(wú)論是索敵AI,還是行為AI,本質(zhì)上都是這些內(nèi)容。所以,光從語(yǔ)法來看,這樣做是允許的。
但是,由于我們一般默認(rèn)沒有人這樣做,所以也就不會(huì)預(yù)料到這樣會(huì)出什么問題。舉例來說,我們的索敵行為列表里1號(hào)位是“尋找附近玩家”的索敵AI,2號(hào)位是“移動(dòng)并近戰(zhàn)攻擊”,那么索敵AI找到了目標(biāo)之后,很可能就不執(zhí)行后面的2號(hào)位AI了,導(dǎo)致找得到敵人,卻還是不去攻擊。即使不去考慮和其他mod的聯(lián)動(dòng),光是整理出一個(gè)不會(huì)有問題的列表就不容易。請(qǐng)不要給自己找麻煩……除非不這樣做更麻煩。
然后又有人要問了,
如果兩個(gè)AI在同一個(gè)列表,且優(yōu)先級(jí)相同會(huì)怎樣?
我只能說,少干這種給自己找麻煩的事。設(shè)計(jì)的時(shí)候就避免這種優(yōu)先級(jí)相同。把誰(shuí)先誰(shuí)后規(guī)定得清清楚楚,不好嗎?你的時(shí)間是浪費(fèi)在給自己找麻煩上的?
我想做一個(gè)能自定義AI的機(jī)器人(或使魔)mod,那么這里涉及到三種選擇:
1,根據(jù)玩家理解設(shè)計(jì)操作,寫一套復(fù)雜的邏輯把它轉(zhuǎn)化為MC AI的雙列表體系;
2,根據(jù)MC AI雙列表體系設(shè)計(jì)操作,讓玩家去理解這東西;
3,完全否定雙列表體系,自己另起爐灶。
方案1做起來非常麻煩,當(dāng)玩家想實(shí)現(xiàn)某個(gè)操作的時(shí)候,你可能需要去按順序組合四五個(gè)AI才能實(shí)現(xiàn)這個(gè)效果。而且,當(dāng)玩家改變生物的行為模式時(shí),你還要精確地去除原本的AI,確保它們不殘留下來干擾你。
方案2玩家理解起來非常麻煩,或者說門檻比較高。實(shí)際上,很多MC玩家對(duì)游戲的理解是遠(yuǎn)不如mod作者的。這個(gè)差距大到什么程度呢?達(dá)到很多人寧可付費(fèi)下載一個(gè)死亡不掉落mod或者防爆mod,也不去自己打mc原版就有的指令——盡管那個(gè)mod實(shí)際上就是在執(zhí)行指令。網(wǎng)易版這種mod的巨大下載量證明了這一點(diǎn)。如果我希望自己的mod有更多人玩的明白,那勢(shì)必就不要這樣干?!白屵@個(gè)怪物攻擊玩家”,在邏輯上只是一件事,那也就不要讓玩家分別正確執(zhí)行兩個(gè)操作才能實(shí)現(xiàn)。
方案3呢,做起來也簡(jiǎn)單,玩家理解起來也簡(jiǎn)單,但兼容性差。如果有哪個(gè)mod基于雙列表體系修改AI,那么它和我的互動(dòng)結(jié)果,只有實(shí)際試試才知道了。
可能有人要問,MC為啥要搞雙列表體系呢?這不是自找麻煩嗎?其實(shí)也不然。我們看一個(gè)比較好的生物作為例子吧:僵尸。實(shí)際上,骷髏更好,但是也更難理解,我們先從僵尸開始入手。



有人可能會(huì)說了,這mojang是不是有病,為什么把行為列表的3和4空出來了,是為了讓不同生物類型的同種任務(wù)序號(hào)對(duì)齊嗎?并不是。如果你去看骷髏的,你會(huì)發(fā)現(xiàn)骷髏里EntityAIWanderAvoidWater是5,但是在僵尸里是7。再比如,游泳在骷髏里是1,但是在僵尸里是0。那么,是為了給EntityZombie的子類留空間嗎?也不是。子類一共有仨,Husk、PigZombie和ZombieVillager,都沒有指定3和4。我只能假設(shè)這是以前有3和4,后來隨著版本更新給刪掉了,又懶得整理后面的編號(hào)而造成的歷史殘留。
雖然多數(shù)索敵列表里內(nèi)容的工作都是去指定實(shí)體的attackTarget(攻擊目標(biāo)),但這不意味著它們不能干別的, 也不意味著其他地方不能去修改目標(biāo)。索敵AI可以影響尋路的目的地,做什么都行,代碼里寫什么就是什么。其他地方也可以手動(dòng)指定attackTarget,這使得我們可以制作一個(gè)具有嘲諷效果的道具,而不必直接和AI列表打交道。
這就是AI的本質(zhì):兩套列表里的若干項(xiàng)目,控制實(shí)體的若干內(nèi)容。這里我們沒有深入討論尋路的部分,那個(gè)比較麻煩,且多數(shù)情況下不需要修改——除非你想做的東西不是在地上走來走去,而是蹦來蹦去,或者飛來飛去。一旦改了,還會(huì)和某些AI類不兼容,所以我們先pass。
如果我們?cè)趯?shí)體運(yùn)行的好好的時(shí)候,突然把其中一條AI從列表里去掉, 或者把一條AI加入列表,會(huì)怎么樣?
這個(gè)問題很合理,事實(shí)上MC自己就經(jīng)常這么干。最典型的例子就是骷髏。

點(diǎn)此查看骷髏失去弓的效果。
骷髏會(huì)經(jīng)常調(diào)用(主要是每次在主手物品修改時(shí))setCombatTask。
這個(gè)接口的效果是,首先把近戰(zhàn)和遠(yuǎn)程攻擊都從行為列表里去掉(但不銷毀),然后判斷主手物品。如果主手是弓,那就把遠(yuǎn)程攻擊行為給掛回列表;如果不是,那就把近戰(zhàn)攻擊行為給掛回去。顯然,即使是手里從鉆石換成鐵錠,這個(gè)接口也要調(diào)用一次,然后把AI拆了又掛回去。只有兩種模式的時(shí)候,已經(jīng)這么墨跡,如果你要在多個(gè)模式間來回切換,不事先規(guī)劃好肯定是不行的。
最后再提兩點(diǎn)關(guān)鍵的東西:
玩家、船、盔甲架等不具有AI系統(tǒng)。這些東西是給EntityLiving用的。
AI不會(huì)持久化并存盤。如果你退出游戲后再進(jìn)入游戲,那么實(shí)體并不會(huì)記得退出前它獲得了什么AI,只會(huì)正常調(diào)用構(gòu)造函數(shù)。你需要手動(dòng)恢復(fù)它的各項(xiàng)AI狀態(tài)。或者說,對(duì)于可變AI的生物,自己寫一套AI狀態(tài)存檔系統(tǒng)。