日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人工智能 > ChatGpt >内容正文

ChatGpt

趣说游戏AI开发:对状态机的褒扬和批判

發(fā)布時(shí)間:2025/3/8 ChatGpt 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 趣说游戏AI开发:对状态机的褒扬和批判 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

0x00 前言

因?yàn)榕R近年關(guān)工作繁忙,已經(jīng)有一段時(shí)間沒(méi)有更新博客了。到了元旦終于有時(shí)間來(lái)寫(xiě)點(diǎn)東西,既是積累也是分享。如題目所示,本文要來(lái)聊一聊在游戲開(kāi)發(fā)中經(jīng)常會(huì)涉及到的話題——游戲AI。設(shè)計(jì)游戲AI的目標(biāo)之一是要找到一種便于使用并容易拓展的的方案,常見(jiàn)的一些游戲AI方案包括了有限狀態(tài)機(jī)(FSM)、分層有限狀態(tài)機(jī)(HFSM)、面向目標(biāo)的動(dòng)作規(guī)劃(GOAP)以及分層任務(wù)網(wǎng)絡(luò)(HTN)和行為樹(shù)(BT)等等。下面我們就來(lái)聊一聊比較有代表性的游戲AI方案——狀態(tài)機(jī)。

0x01 有限狀態(tài)機(jī)(FSM)

有限狀態(tài)自動(dòng)機(jī) (Finite State Machine,FSM)是表示有限多個(gè)狀態(tài)以及在這些狀態(tài)(State)之間轉(zhuǎn)移(Transition)和動(dòng)作(Action)的數(shù)學(xué)模型。有限狀態(tài)機(jī)的模型體現(xiàn)了兩點(diǎn):

  • 狀態(tài)首先是離散的:某一時(shí)刻只能處于某種狀態(tài)之下,且需要滿足某種條件才能從一種狀態(tài)轉(zhuǎn)移到另一種狀態(tài)。
  • 然后狀態(tài)總數(shù)是有限的。
  • 從它的定義,我們可以看到有限狀態(tài)機(jī)的幾個(gè)重要概念:

    • 狀態(tài)(State):表示對(duì)象的某種形態(tài),在當(dāng)前形態(tài)下可能會(huì)擁有不同的行為和屬性。
    • 轉(zhuǎn)移(Transition):表示狀態(tài)變更,并且必須滿足確使轉(zhuǎn)移發(fā)生的條件來(lái)執(zhí)行。
    • 動(dòng)作(Action):表示在給定時(shí)刻要進(jìn)行的活動(dòng)。
    • 事件(Event):事件通常會(huì)引起狀態(tài)的變遷,促使?fàn)顟B(tài)機(jī)從一種狀態(tài)切換到另一種狀態(tài)。

    而狀態(tài)機(jī)便是用來(lái)控制對(duì)象狀態(tài)的管理器。在滿足了某種條件或者說(shuō)在某個(gè)特定的事件被觸發(fā)之后,對(duì)象的狀態(tài)便會(huì)通過(guò)轉(zhuǎn)換來(lái)變成另外一種狀態(tài),而對(duì)象在不同的狀態(tài)之下也有可能會(huì)有不同的行為和屬性。
    當(dāng)然,有限狀態(tài)機(jī)的應(yīng)用范圍很廣,但是顯然游戲開(kāi)發(fā)是有限狀態(tài)機(jī)最為成功的應(yīng)用領(lǐng)域之一。除了游戲AI的實(shí)現(xiàn)可以依靠有限狀態(tài)機(jī)之外,游戲邏輯以及動(dòng)作切換都可以借助有限狀態(tài)機(jī)來(lái)實(shí)現(xiàn)。因此游戲中的每個(gè)角色或者器件或者邏輯都有可能內(nèi)嵌一個(gè)狀態(tài)機(jī)。

    0x02 HFSM分層有限狀態(tài)機(jī)

    如果我們仔細(xì)觀察一個(gè)有限狀態(tài)機(jī)的話,可以發(fā)現(xiàn)它在邏輯結(jié)構(gòu)上是沒(méi)有層次的,如果和行為樹(shù)來(lái)做對(duì)比的話可以發(fā)現(xiàn)這一點(diǎn)十分明顯。在行為樹(shù)中,節(jié)點(diǎn)是有層次(Hierarchical)的,子節(jié)點(diǎn)由其父節(jié)點(diǎn)來(lái)控制。例如行為樹(shù)中有一種節(jié)點(diǎn)叫做“序列(Sequence)節(jié)點(diǎn)”,它的作用是順序執(zhí)行所有子節(jié)點(diǎn)(如果某個(gè)子節(jié)點(diǎn)失敗返回失敗,否則返回成功)。而將行為樹(shù)的這個(gè)優(yōu)勢(shì)應(yīng)用到有限狀態(tài)機(jī)上,分層有限狀態(tài)機(jī)HFSM便誕生了。

    分層的好處

    那么引入了分層之后的HFSM到底帶來(lái)了什么好處呢?
    最大的好處便是在一定程度上規(guī)范了狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)換,從而有效地減少了狀態(tài)之間的轉(zhuǎn)換。
    舉一個(gè)簡(jiǎn)單的小例子:例如RTS游戲中的士兵。如果邏輯沒(méi)有層次上的劃分,那么我們對(duì)士兵所定義的若干狀態(tài),例如前進(jìn)、尋敵、攻擊、防御、逃跑等等,就需要在這些狀態(tài)之間定義轉(zhuǎn)移,因?yàn)樗鼈兪瞧郊?jí)的,因此我們需要考慮每一組狀態(tài)的關(guān)系,并維護(hù)一大堆沒(méi)有側(cè)重點(diǎn)的轉(zhuǎn)移。
    如果在邏輯上是分層的,我們就可以將士兵的這些狀態(tài)進(jìn)行一個(gè)分類(lèi),把幾個(gè)低級(jí)的狀態(tài)歸并到一個(gè)高級(jí)的狀態(tài)中,并且狀態(tài)的轉(zhuǎn)移只發(fā)生在同級(jí)的狀態(tài)中。
    例如高級(jí)狀態(tài)包括戰(zhàn)斗、撤退,而戰(zhàn)斗狀態(tài)中又包括了尋敵、攻擊等幾個(gè)小狀態(tài);撤退狀態(tài)中又包括了防御、逃跑這幾個(gè)小狀態(tài)。

    總而言之,分層狀態(tài)機(jī)HFSM從某種程度上規(guī)范了狀態(tài)機(jī)的狀態(tài)轉(zhuǎn)移,而且狀態(tài)內(nèi)的子狀態(tài)不需要關(guān)心外部狀態(tài)的跳轉(zhuǎn),這樣也做到了無(wú)關(guān)狀態(tài)間的隔離。

    0x03 有限狀態(tài)機(jī)的實(shí)現(xiàn)

    那么到底如何實(shí)現(xiàn)一個(gè)有限狀態(tài)機(jī)呢?主要有兩種方式來(lái)實(shí)現(xiàn),即集中管理控制以及模塊化管理。具體來(lái)說(shuō),這兩種方式的實(shí)現(xiàn)如下:

  • 使用switch語(yǔ)句:所有的狀態(tài)之間的轉(zhuǎn)移邏輯全都寫(xiě)在一個(gè)部分,需要根據(jù)不同的分支來(lái)判斷轉(zhuǎn)移條件是否符合。
  • 使用狀態(tài)模式(State Pattern):一種常見(jiàn)的設(shè)計(jì)模式。在狀態(tài)模式中,我們?yōu)槊總€(gè)狀態(tài)創(chuàng)建與之對(duì)應(yīng)的類(lèi),這樣就將狀態(tài)轉(zhuǎn)移的邏輯從臃腫的switch語(yǔ)句中分散到了各個(gè)類(lèi)中。
  • 了解了有限狀態(tài)機(jī)大體上可以分為這兩種實(shí)現(xiàn)方式,那么接下來(lái)我們就具體來(lái)看一看這兩種方式是如何實(shí)現(xiàn)的。

    switch語(yǔ)句

    在實(shí)現(xiàn)有限狀態(tài)機(jī)時(shí),使用switch語(yǔ)句是最簡(jiǎn)單同時(shí)也是最直接的一種方式。這種方式的基本思路是為狀態(tài)機(jī)中的每一種狀態(tài)都設(shè)置一個(gè)case分支,專門(mén)用來(lái)對(duì)該狀態(tài)進(jìn)行控制。

    上圖是一個(gè)具體的使用有限狀態(tài)機(jī)實(shí)現(xiàn)游戲AI的場(chǎng)景,描述的是一個(gè)游戲單位的AI,下面我們就使用switch語(yǔ)句來(lái)實(shí)現(xiàn)圖中的狀態(tài)機(jī)。

    switch (state) {// 處理狀態(tài)Waiting的分支case State.Waiting: // 執(zhí)行等待wait();// 檢查是否有可以攻擊if (canAttack()){// 當(dāng)前狀態(tài)轉(zhuǎn)換為AttackingchangeState(State.Attacking);}// 若不可攻擊,則檢查是否有可以移動(dòng)else if (canMove()) { // 當(dāng)前狀態(tài)轉(zhuǎn)換為MovingchangeState(State.Moving)}break;// 處理狀態(tài)Moving的分支case State.Moving: // 執(zhí)行動(dòng)作movemove();// 檢查是否可以攻擊敵人if (canAttack()) {// 當(dāng)前狀態(tài)轉(zhuǎn)換為AttackingchangeState(State.Attacking);}// 若不可攻擊,則檢查是否可以等待else if (canWait()) {// 當(dāng)前狀態(tài)轉(zhuǎn)換為WaitingchangeState(State.Waiting);}break;// 處理狀態(tài)Attacking的分支case State.Attacking: // 執(zhí)行攻擊attackattack();// 檢查是否可以等待if (canWait()) {// 當(dāng)前狀態(tài)轉(zhuǎn)換為WaitingchangeState(State.Waiting);}break; }

    通過(guò)這個(gè)小例子,我們可以看到使用switch語(yǔ)句實(shí)現(xiàn)的有限狀態(tài)機(jī)的確可以很好的運(yùn)行。不過(guò)我們還可以發(fā)現(xiàn)這種方式在實(shí)現(xiàn)狀態(tài)之間的轉(zhuǎn)換時(shí),1.檢查轉(zhuǎn)換條件以及2.進(jìn)行狀態(tài)轉(zhuǎn)換的代碼都是混雜在當(dāng)前的狀態(tài)分支中來(lái)完成的,這樣就會(huì)導(dǎo)致代碼的可讀性降低甚至?xí)黾尤蘸蟮木S護(hù)成本。
    這是因?yàn)樵诿總€(gè)具體的狀態(tài)下,都需要檢查多個(gè)具體的轉(zhuǎn)換條件,對(duì)符合條件的還需要轉(zhuǎn)移到新的具體的狀態(tài),這樣的代碼是難以維護(hù)的,因?yàn)樗鼈冃枰诰唧w的情況下處理具體的事物。即便我們將檢查轉(zhuǎn)換條件和進(jìn)行狀態(tài)轉(zhuǎn)換的代碼分別封裝成兩個(gè)專門(mén)的函數(shù)FuncA(檢查轉(zhuǎn)換條件)和FuncB(進(jìn)行狀態(tài)轉(zhuǎn)換),switch語(yǔ)句中各個(gè)具體狀態(tài)的代碼可能會(huì)更加清晰。但是隨著邏輯復(fù)雜度的增加,FuncA和FuncB這兩個(gè)函數(shù)本身的復(fù)雜度可能也會(huì)增加,甚至最后變得臃腫不堪。

    狀態(tài)模式

    當(dāng)控制一個(gè)對(duì)象狀態(tài)轉(zhuǎn)換的條件表達(dá)式過(guò)于復(fù)雜時(shí),把狀態(tài)的判斷邏輯轉(zhuǎn)移到一系列類(lèi)當(dāng)中,可以把復(fù)雜的邏輯判斷簡(jiǎn)單化。因此,使用狀態(tài)模式來(lái)實(shí)現(xiàn)狀態(tài)機(jī)雖然不如直接使用switch語(yǔ)句來(lái)的直接,但是對(duì)于狀態(tài)更易維護(hù)也更易拓展。下面我們就來(lái)看一看狀態(tài)模式中的角色:

      1. 上下文環(huán)境(Context):它定義了客戶程序需要的接口并維護(hù)一個(gè)具體狀態(tài)的實(shí)例,將與狀態(tài)相關(guān)的操作(1.檢查轉(zhuǎn)換條件;2.進(jìn)行狀態(tài)轉(zhuǎn)換)交給當(dāng)前的具體狀態(tài)對(duì)象來(lái)處理。
      2. 抽象狀態(tài)(State):定義一個(gè)接口以封裝使用上下文環(huán)境的的一個(gè)特定狀態(tài)相關(guān)的行為。
      3. 具體狀態(tài)(Concrete State):實(shí)現(xiàn)抽象狀態(tài)定義的接口。
    下面,我們就按照這三個(gè)角色來(lái)實(shí)現(xiàn)上一小節(jié)圖中的狀態(tài)機(jī)吧。
    context類(lèi)

    public class Context {private State state;public Context(State state){this.state = state;}public void Do(){state.CheckAndTran(this);} }

    抽象狀態(tài)類(lèi):

    public abstract class State {public abstract void CheckAndTran(Context context); }

    具體狀態(tài)類(lèi)

    public class WaitingState : State {public override void CheckAndTran(Context context){//執(zhí)行等待動(dòng)作Wait();//檢查是否可以攻擊敵人if (canAttack()){// 當(dāng)前狀態(tài)轉(zhuǎn)換為Attackingcontext.State = new AttackingState();}// 若不可攻擊,則檢查是否有可以移動(dòng)else if (canMove()) { // 當(dāng)前狀態(tài)轉(zhuǎn)換為Movingcontext.State = new MovingState();}} } ...

    雖然看似狀態(tài)模式緩解了使用switch語(yǔ)句那種代碼臃腫、可讀性維護(hù)性差的問(wèn)題,但是狀態(tài)模式并非沒(méi)有自己的缺點(diǎn)。可以看出狀態(tài)模式的使用必然會(huì)增加類(lèi)和對(duì)象的個(gè)數(shù),如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。

    0x04 褒揚(yáng)和批判

    在游戲開(kāi)發(fā)中使用狀態(tài)機(jī)顯然不失為一種不錯(cuò)的選擇,首先它的概念并不復(fù)雜,其次它的實(shí)現(xiàn)也十分簡(jiǎn)單而直接。但它的缺點(diǎn)卻也十分明顯,例如難以復(fù)用,因?yàn)樗枰鶕?jù)具體的情況來(lái)做出反應(yīng),當(dāng)然當(dāng)狀態(tài)機(jī)的模型復(fù)雜到一定的程度之后,也會(huì)帶來(lái)實(shí)現(xiàn)和維護(hù)上的困難。如何選擇,可能就是一個(gè)仁者見(jiàn)仁智者見(jiàn)智的問(wèn)題了。

    總結(jié)

    以上是生活随笔為你收集整理的趣说游戏AI开发:对状态机的褒扬和批判的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。