基礎(chǔ) | 簡(jiǎn)單的智能體----有限狀態(tài)機(jī)(七)

本系列為筆者初學(xué)c/c++和游戲AI開(kāi)發(fā)的學(xué)習(xí)經(jīng)歷,練習(xí)為主,不涉及到具體的游戲開(kāi)發(fā)軟件學(xué)習(xí)(如unity,虛幻4等),適合剛?cè)腴T(mén)的小伙伴一起學(xué)習(xí)探討,歡迎在評(píng)論區(qū)留下意見(jiàn)。
開(kāi)發(fā)語(yǔ)言:c/c++ (11及以上)?
開(kāi)發(fā)平臺(tái):macOS mojave / Linux?
編譯器:vs Code / g++

三、代碼實(shí)現(xiàn)
3.4?狀態(tài)類(lèi)

3.4.1?抽象狀態(tài)類(lèi)
? 在狀態(tài)模式中(圖5),狀態(tài)被解耦為抽象狀態(tài)類(lèi)與具體狀態(tài)類(lèi),定義和實(shí)現(xiàn)被分離。
? State類(lèi)為抽象類(lèi),是作為接口來(lái)使用的,這個(gè)接口中封裝了每個(gè)具體狀態(tài)類(lèi)會(huì)使用到的一些方法,但并沒(méi)有具體的實(shí)現(xiàn)細(xì)節(jié)。
接口是一個(gè)共享框架,供兩個(gè)系統(tǒng)交互時(shí)使用。在C++中,接口是使用抽象類(lèi)來(lái)實(shí)現(xiàn)的。
----《C++ Primer Plus》
? 使用抽象類(lèi)來(lái)實(shí)現(xiàn)接口有許多好處,比如減少重復(fù)的代碼,提供標(biāo)準(zhǔn)化的管理,定義與具體實(shí)現(xiàn)的解耦等等。
? 在“Bob的一天”中,我們的State類(lèi)就起到了管理具體狀態(tài)類(lèi)的作用,它只是聲明了狀態(tài)類(lèi)必須含有哪些方法,具體這些方法中實(shí)現(xiàn)的細(xì)節(jié)和差異,則根據(jù)不同的狀態(tài)來(lái)做決定。
Enter(Miner *): 進(jìn)入某一個(gè)狀態(tài)
Execute(Miner *): Miner類(lèi)在每個(gè)時(shí)刻具體要執(zhí)行的動(dòng)作
Exit(Miner* ): 退出某一個(gè)狀態(tài)

? 注意我們的抽象類(lèi)是通過(guò)虛函數(shù)和純虛函數(shù)來(lái)實(shí)現(xiàn)的,這意味著每個(gè)純虛函數(shù)必須在派生類(lèi)中被實(shí)現(xiàn)。
3.4.1 具體狀態(tài)類(lèi)
? 具體狀態(tài)類(lèi)繼承了接口的方法,然后根據(jù)每個(gè)狀態(tài)的不同來(lái)做不同的實(shí)現(xiàn)。
? 如“到礦場(chǎng)挖礦”狀態(tài)中,有“走到礦場(chǎng)”、“挖礦”和“離開(kāi)礦場(chǎng)”這三個(gè)動(dòng)作,“挖礦”這個(gè)動(dòng)作中又包含了“是否口渴”、“口袋是否裝滿了金子”等狀態(tài)的更新邏輯判斷。
? 而其他三個(gè)狀態(tài),又各有差異和區(qū)別。但不管有多少差異,都一定包含有Enter、Execute和Exit這三個(gè)方法。也就是每種狀態(tài)都有的共性、標(biāo)準(zhǔn)。
??以EnterMineAndDigForNugget()這個(gè)狀態(tài)為例,我們通過(guò)單例模式來(lái)實(shí)現(xiàn)具體狀態(tài)類(lèi),關(guān)于單例模式我們之前已經(jīng)介紹過(guò)了(詳情請(qǐng)見(jiàn)鏈接)。

??該狀態(tài)類(lèi)首先繼承了Sate類(lèi),之后以單例模式來(lái)規(guī)定該狀態(tài)類(lèi)只允許有一個(gè)實(shí)例化對(duì)象,且在退出該狀態(tài)類(lèi)后,會(huì)銷(xiāo)毀并釋放其占有的內(nèi)存。
? 我們以Instange()函數(shù)來(lái)返回一個(gè)實(shí)例化對(duì)象,并用其他三個(gè)函數(shù)來(lái)更新Miner的狀態(tài)。

? 每個(gè)函數(shù)體我們都傳入一個(gè)Miner對(duì)象,Miner里具體實(shí)現(xiàn)了每個(gè)狀態(tài)中可以執(zhí)行的動(dòng)作。如“計(jì)算口袋的金子”、“判斷是否口渴”、“判斷是否疲勞”等等。
? 可以見(jiàn)到,在整個(gè)項(xiàng)目當(dāng)中,我們具體的更新?tīng)顟B(tài)的邏輯,也就是Bob會(huì)做的動(dòng)作,都是在具體狀態(tài)類(lèi)中去實(shí)現(xiàn)的。
? Miner類(lèi)只是定義了一個(gè)Miner可以會(huì)有那些屬性和動(dòng)作,并寫(xiě)好它們的實(shí)現(xiàn),但是具體的使用邏輯則交給具體狀態(tài)類(lèi)根據(jù)具體的使用場(chǎng)景去決定。
? 這樣做的好處是,如果我們之后想要給Bob增加新的狀態(tài),只需要在Miner類(lèi)中新增一些動(dòng)作相關(guān)函數(shù),然后再新建一個(gè)具體狀態(tài)類(lèi),在里面去調(diào)用、去使用這些函數(shù)就可以。
? 我們不用每次都寫(xiě)這些重復(fù)的代碼,而且可以很方便的增刪管理。
? 比如在“到礦場(chǎng)挖礦”這個(gè)狀態(tài)中,我們要Bob也有“去睡覺(jué)休息”這個(gè)動(dòng)作,只需要加入幾行代碼即可:

3.5?主函數(shù)入口??
? ? 當(dāng)然,C++中我們的程序都必須有一個(gè)入口,作為一切的開(kāi)始。

? 四、結(jié)束語(yǔ)
? 這樣,一個(gè)簡(jiǎn)單的有限狀態(tài)機(jī)實(shí)現(xiàn)的智能體Bob就完成了,在小鎮(zhèn)上的一天中,他挖礦、喝酒和睡覺(jué),知道自己什么時(shí)候會(huì)累,會(huì)渴,也知道自己銀行賬戶的余額。
? Bob有簡(jiǎn)單的外界感知能力,雖然都是我們?nèi)斯べx予他的,但這個(gè)簡(jiǎn)單的項(xiàng)目可以作為我們?nèi)腴T(mén)游戲人工智能這個(gè)有趣的領(lǐng)域。
? 也許很多年以后,游戲中的NPC也有著復(fù)雜的情感,也會(huì)有自己的“生活”。

知識(shí)點(diǎn):
抽象類(lèi)&接口

參考:?
《游戲人工智能編程案例精粹》
《C++ Primer Plus》?
相關(guān)代碼下載:https://github.com/linpeijie/GameToy/tree/master/GameAI/FSM