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

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

游戲編程模式(五):狀態(tài)模式

2023-07-30 22:42 作者:寧牁兒  | 我要投稿
狀態(tài)模式在AI、編譯器和游戲開發(fā)領(lǐng)域應(yīng)用廣泛。游戲開發(fā)引擎unity中也有內(nèi)置的動畫控制器,其原理就是狀態(tài)模式。接下來的討論將會一步步將狀態(tài)模式的演化過程展示出來。


一、混亂的控制代碼

首先考慮一個簡單的“按B鍵觸發(fā)玩家跳躍的場景”:

好,它擁有了基本的跳躍功能,但是會有一些問題:當你瘋狂的按跳躍鍵時,主角就會一直浮空。最容易想到的處理辦法就是添加一個狀態(tài)字段,用來判斷主角是否處于跳躍狀態(tài):

現(xiàn)在如果想添加另外一個動作:當玩家按下方向鍵時,如果角色在地上,我們想要她臥倒,而松開按鍵時站起來:

好,現(xiàn)在又出現(xiàn)了另外一個問題:玩家可以先按下鍵臥倒,再按跳躍鍵跳起,在空中放開下鍵,這將導(dǎo)致主角在跳一半時貼圖變成了站立時的貼圖。如果我們要修復(fù),很容易想到:再加一個狀態(tài)字段用來標識:

這看起來目前還算過得去,但是一個游戲主角能做的動作可能多達十多個幾十個,每加入一個動作都會使代碼數(shù)量增加一個級別,使代碼可讀性和可維護性、可拓展性減少一個量級,最重要的是,它會帶來一堆BUG。

二、有限狀態(tài)機

有限狀態(tài)機(FSMs)可以很好地解決這一類問題,它有幾個關(guān)鍵點:

  • 狀態(tài)機擁有所有可能狀態(tài)的集合

  • 狀態(tài)機同時只能處于一個狀態(tài)

  • 一連串的輸入和事件被發(fā)送給狀態(tài)機

  • 每個狀態(tài)都有一系列的轉(zhuǎn)移,每個轉(zhuǎn)移與輸入和另一狀態(tài)相關(guān)

將上面的玩家控制的例子用狀態(tài)機來表示:

將上述的有限狀態(tài)機用代碼來表示,首先想到的會是用enum和switch來實現(xiàn):

四、狀態(tài)模式

用枚舉和分支來實現(xiàn)有限狀態(tài)機明顯會導(dǎo)致可讀性和可維護性差,對于對OOP非常熟悉的人來說,每一個case分支都可能是一個使用面向?qū)ο蟮臋C會,由此產(chǎn)生了狀態(tài)模式。在GoF中這樣描述狀態(tài)模式;

允許一個對象在其內(nèi)部狀態(tài)發(fā)生變化時改變自己的行為,該對象看起來好像修改了它的類型

把之前的枚舉都轉(zhuǎn)化成一個狀態(tài)類,把switch的每個分支轉(zhuǎn)換成一個共用方法(這里給臥倒狀態(tài)新添加了一個chargeTime來實現(xiàn)蓄力釋放技能的功能):

再將HeroineState作為Heroine類的一個字段,并將輸入?yún)?shù)委托給HeroineState的handleInput和update方法來處理:

好,現(xiàn)在我們要改變主角Heroine的狀態(tài),只需要將HeroineState字段指向不同的HeroineState對象。讓主對象通過改變委托的對象,來改變它的行為,這就是狀態(tài)模式的基本思想了。

五、關(guān)于狀態(tài)類的實例化

我們現(xiàn)在需要考慮如何來實例化狀態(tài)類,用于狀態(tài)之間的轉(zhuǎn)換。

靜態(tài)狀態(tài):如果狀態(tài)對象沒有其他數(shù)據(jù)字段,那么每個狀態(tài)類就只需要一個實例,因為每個實例都將完全一樣(享元模式)。當然,當狀態(tài)對象中有其他狀態(tài)相關(guān)的字段時,就不得不為這個狀態(tài)類實例化多個對象。

六、入口行為和出口行為

狀態(tài)模式的目標是將狀態(tài)的行為和數(shù)據(jù)封裝到單一類中。我們現(xiàn)在已經(jīng)將狀態(tài)的行為封裝好,但是在狀態(tài)的數(shù)據(jù)上還有一些問題。比如:

修改貼圖的代碼和狀態(tài)耦合在了一起,在DuckingState類中出現(xiàn)了IMAGE_STAND的貼圖代碼,此時可以給狀態(tài)一個入口行為來解決這個問題(出口行為同理):

七、并發(fā)狀態(tài)機

假設(shè)現(xiàn)在要給主角一個拿槍的能力,并且在拿槍的時候它也同時能做完全一樣的行為:跑動、跳躍、跳斬、臥倒、站立等,現(xiàn)在如何來設(shè)計狀態(tài)類?或許需要翻倍的狀態(tài)類:站立,持槍站立,跳躍,持槍跳躍……,此時不僅增加了大量的狀態(tài),而且增加了大量的冗余,持槍和不持槍的狀態(tài)是完全一樣的,只是多了一點負責(zé)射擊的代碼。

問題在于我們將兩種狀態(tài)綁定在了一個狀態(tài)機上,所以處理方法就很明顯了:使用兩個單獨的狀態(tài)機:

如果在做什么有n個狀態(tài),而攜帶了什么有m個狀態(tài),要塞到一個狀態(tài)機中,則需要n × m個狀態(tài)。使用兩個狀態(tài)機,就只有n + m個

實現(xiàn)很簡單,只是在原有基礎(chǔ)上添加了幾乎完全一樣的少量代碼:

八、分層狀態(tài)機

如果對OOP敏感,很容易發(fā)現(xiàn)可以繼續(xù)進行優(yōu)化,站立、行走、奔跑、滑鏟這些狀態(tài)或許有很多重復(fù)的代碼來處理與地面碰撞和跳躍的行為,此時可以定義一個地面類來處理這些行為,然后將它們繼承自這個類(當然繼承也會在這些類之間建立一些耦合,此時就需要進行平衡取舍):

九、下推自動機

考慮一個場景:給主角添加了一個射擊狀態(tài),不管現(xiàn)在是什么狀態(tài),都能在按下開火按鈕時跳轉(zhuǎn)為射擊狀態(tài),但關(guān)鍵問題是,如何在射擊后轉(zhuǎn)換為之前的狀態(tài)。

解決方法是下推自動機,有限狀態(tài)機有一個指向狀態(tài)的指針,下推自動機有一個棧指針,它也可以實現(xiàn)狀態(tài)之間的轉(zhuǎn)換,并且:

  • 可以將新狀態(tài)壓入棧中

  • 可以彈出最上面的狀態(tài)


游戲編程模式(五):狀態(tài)模式的評論 (共 條)

分享到微博請遵守國家法律
邯郸县| 合阳县| 胶州市| 垦利县| 新泰市| 柞水县| 甘洛县| 茶陵县| 丰原市| 安康市| 开平市| 安宁市| 财经| 城固县| 思南县| 鱼台县| 深水埗区| 罗甸县| 韶山市| 个旧市| 宁乡县| 威宁| 荆州市| 灌阳县| 溆浦县| 临高县| 东安县| 邵东县| 南丰县| 奇台县| 柘荣县| 永胜县| 凌海市| 岳阳县| 新建县| 大悟县| 五大连池市| 星子县| 布拖县| 云浮市| 海城市|