aigc實現(xiàn)的并發(fā)狀態(tài)機(jī)

參考游戲編程模式
并發(fā)狀態(tài)機(jī)
我們決定給英雄拿槍的能力。 當(dāng)她拿著槍的時候,她還是能做她之前的任何事情:跑動,
跳躍,跳斬,等等。 但是她在做這些的同時也要能開火。
如果我們執(zhí)著于FSM,我們需要翻倍現(xiàn)有狀態(tài)。 對于每個現(xiàn)有狀態(tài),我們需要另一個她持
槍狀態(tài):站立,持槍站立,跳躍,持槍跳躍, 你知道我的意思了吧。
多加幾種武器,狀態(tài)就會指數(shù)爆炸。 不但增加了大量的狀態(tài),這也增加了大量的冗余: 持
槍和不持槍的狀態(tài)是完全一樣的,只是多了一點負(fù)責(zé)射擊的代碼。
問題在于我們將兩種狀態(tài)綁定——她做的和她攜帶的——到了一個狀態(tài)機(jī)上。 為了處理所有
可能的組合,我們需要為每一對組合寫一個狀態(tài)。 修復(fù)方法很明顯:使用兩個單獨的狀態(tài)
機(jī)。
如果她在做什么有n個狀態(tài),而她攜帶了什么有m個狀態(tài),要塞到一個狀態(tài)機(jī)中,
我們需要n × m個狀態(tài)。使用兩個狀態(tài)機(jī),就只有n + m個。
我們保留之前記錄她在做什么的狀態(tài)機(jī),不用管它。 然后定義她攜帶了什么的單獨狀態(tài)機(jī)
。 Heroine將會有兩個“狀態(tài)”引用,每個對應(yīng)一個狀態(tài)機(jī),就像這樣:
···
class Heroine
{
// 其他代碼……
private:
HeroineState* state_;
HeroineState* equipment_;
};
···
為了便于說明,她的裝備也使用了狀態(tài)模式。 在實踐中,由于裝備只有兩個狀態(tài)
,一個布爾標(biāo)識就夠了。
當(dāng)英雄把輸入委托給了狀態(tài),兩個狀態(tài)都需要委托:
···
void Heroine::handleInput(Input input)
{
state_->handleInput(this, input);
equipment_->handleInput(
this, input);
}
···
功能更完備的系統(tǒng)也許能讓狀態(tài)機(jī)銷毀輸入,這樣其他狀態(tài)機(jī)就不會收到了。 這
能阻止兩個狀態(tài)機(jī)響應(yīng)同一輸入。
每個狀態(tài)機(jī)之后都能響應(yīng)輸入,發(fā)生行為,獨立于其它機(jī)器改變狀態(tài)。 當(dāng)兩個狀態(tài)集合幾
乎沒有聯(lián)系的時候,它工作得不錯。
在實踐中,你會發(fā)現(xiàn)狀態(tài)有時需要交互。 舉個例子,也許她在跳躍時不能開火,或者她在
持槍時不能跳斬攻擊。 為了完成這個,你也許會在狀態(tài)的代碼中做一些粗糙的if測試其他
狀態(tài)來協(xié)同, 這不是最優(yōu)雅的解決方案,但這可以搞定工作。

···
// 定義角色狀態(tài)
enum CharacterState {
Idle,
Moving,
Attacking,
Ducking,
Jumping,
}
// 定義角色裝備狀態(tài)
enum EquipmentState {
None,
Gun,
}
// 定義角色類
class Character extends cc.Component {
private _stateStack: CharacterState[] = [CharacterState.Idle]; // 角色狀態(tài)棧
private _equipmentStack: EquipmentState[] = [EquipmentState.None]; // 角色裝備狀態(tài)棧
private _isFiring: boolean = false; // 是否正在開火
private _moveSpeed: number = 100; // 移動速度
private _fireInterval: number = 0.5; // 開火間隔時間
private _fireTimer: number = 0; // 開火計時器
constructor() {
super();
}
update(dt: number) {
this._fireTimer += dt;
}
// 切換角色狀態(tài)方法
private changeCharacterState(newState: CharacterState) {
if (this._stateStack[this._stateStack.length - 1] === newState) {
return;
}
this._stateStack.push(newState);
switch (newState) {
case CharacterState.Idle:
this.stopMoving();
break;
case CharacterState.Moving:
this.startMoving();
break;
case CharacterState.Attacking:
this.startAttacking();
break;
case CharacterState.Ducking:
this.startDucking();
break;
case CharacterState.Jumping:
this.startJumping();
break;
}
}
// 結(jié)束當(dāng)前角色狀態(tài)方法
private endCurrentCharacterState() {
const currentState = this._stateStack.pop()!;
switch (currentState) {
case CharacterState.Idle:
break;
case CharacterState.Moving:
this.stopMoving();
break;
case CharacterState.Attacking:
this.stopAttacking();
break;
case CharacterState.Ducking:
this.stopDucking();
break;
case CharacterState.Jumping:
this.stopJumping();
break;
}
}
// 切換角色裝備狀態(tài)方法
private changeEquipmentState(newState: EquipmentState) {
if (this._equipmentStack[this._equipmentStack.length - 1] === newState) {
return;
}
this._equipmentStack.push(newState);
switch (newState) {
case EquipmentState.None:
this.stopFiring();
break;
case EquipmentState.Gun:
this.startFiring();
break;
}
}
// 結(jié)束當(dāng)前角色裝備狀態(tài)方法
private endCurrentEquipmentState() {
const currentState = this._equipmentStack.pop()!;
switch (currentState) {
case EquipmentState.None:
break;
case EquipmentState.Gun:
this.stopFiring();
break;
}
}
// 開始移動方法
private startMoving() {
// TODO:播放移動動畫等操作
}
// 停止移動方法
private stopMoving() {
// TODO:播放停止動畫等操作
}
// 開始攻擊方法
private startAttacking() {
if (!this._isFiring && this._fireTimer >= this._fireInterval) {
this._isFiring = true;
this._fireTimer = 0;
// TODO:播放攻擊動畫等操作,并在攻擊結(jié)束后調(diào)用 stopAttacking 方法停止攻擊
}
}
// 停止攻擊方法
private stopAttacking() {
this._isFiring = false;
// TODO:停止播放攻擊動畫等操作
}
// 開始俯臥方法
private startDucking() {
// TODO:播放俯臥動畫等操作,并在俯臥結(jié)束后調(diào)用 stopDucking 方法停止俯臥
}
// 停止俯臥方法
private stopDucking() {
// TODO:停止播放俯臥動畫等操作
}
// 開始跳躍方法
private startJumping() {
// TODO:播放跳躍動畫等操作,并在跳躍結(jié)束后調(diào)用 stopJumping 方法停止跳躍
}
// 停止跳躍方法
private stopJumping() {
// TODO:停止播放跳躍動畫等操作
}
// 開始開火方法
private startFiring() {
if (!this._isFiring && this._fireTimer >= this._fireInterval) {
this._isFiring = true;
this._fireTimer = 0;
// TODO:播放開火動畫等操作,并在開火結(jié)束后調(diào)用 stopFiring 方法停止開火
}
}
// 停止開火方法
private stopFiring() {
this._isFiring = false;
// TODO:停止播放開火動畫等操作
}
// 移動方法
public move(direction: cc.Vec3) {
if (direction.mag() > 0) {
if (this._stateStack[this._stateStack.length - 1] !== CharacterState.Moving) {
this.changeCharacterState(CharacterState.Moving);
}
this.node.position = this.node.position.add(direction.normalize().mul(this._moveSpeed));
} else {
if (this._stateStack[this._stateStack.length - 1] === CharacterState.Moving) {
this.endCurrentCharacterState();
}
}
}
// 切換裝備方法
public switchEquipment(equipment: EquipmentState) {
if (this._equipmentStack[this._equipmentStack.length - 1] !== equipment) {
this.endCurrentEquipmentState();
this.changeEquipmentState(equipment);
}
}
// 開火方法
public fire() {
if (this._equipmentStack[this._equipmentStack.length - 1] === EquipmentState.Gun) {
if (this._stateStack[this._stateStack.length - 1] !== CharacterState.Attacking) {
this.changeCharacterState(CharacterState.Attacking);
}
}
}
// 跳躍方法
public jump() {
if (this._stateStack[this._stateStack.length - 1] !== CharacterState.Jumping) {
this.changeCharacterState(CharacterState.Jumping);
}
}
// 俯臥方法
public duck() {
if (this._stateStack[this._stateStack.length - 1] !== CharacterState.Ducking) {
this.changeCharacterState(CharacterState.Ducking);
}
}
// 站起方法
public standUp() {
if (this._stateStack[this._stateStack.length - 1] === CharacterState.Ducking) {
this.endCurrentCharacterState();
}
}
}
···
在上面的代碼中,我們定義了一個名為 Character 的角色類,實現(xiàn)了并發(fā)狀態(tài)機(jī)。我們使用兩個狀態(tài)棧 _stateStack 和 _equipmentStack 分別表示角色的行為狀態(tài)和裝備狀態(tài)。在 update 方法中,我們更新開火計時器 _fireTimer 的值。在 changeCharacterState 和 endCurrentCharacterState 方法中,我們根據(jù)新狀態(tài)切換角色的行為,并在需要時播放相應(yīng)的動畫。在 changeEquipmentState 和 endCurrentEquipmentState 方法中,我們根據(jù)新裝備切換角色的裝備狀態(tài),并在需要時播放相應(yīng)的動畫。在 move、fire、jump、duck 和 standUp 方法中,我們切換角色的狀態(tài),并在需要時播放相應(yīng)的動畫。需要注意的是,在實際開發(fā)中,我們還需要根據(jù)具體需求進(jìn)行修改和優(yōu)化,并添加相應(yīng)的條件和轉(zhuǎn)換條件。同時,在使用并發(fā)狀態(tài)機(jī)時,我們需要小心處理狀態(tài)之間的交互和沖突問題,并盡可能地保持代碼簡潔和易于維護(hù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,250評論 6 530
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 97,923評論 3 413
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,041評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,475評論 1 308
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,253評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,801評論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,882評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,023評論 0 285
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,530評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,494評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,639評論 1 366
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,177評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,890評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,289評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,552評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,242評論 3 389
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,626評論 2 370