HTML5 2D平台游戏开发#4状态机
在實(shí)現(xiàn)了《HTML5 2D平臺(tái)游戲開(kāi)發(fā)——角色動(dòng)作篇之沖刺》之后,我發(fā)現(xiàn)隨著角色動(dòng)作的增加,代碼中的邏輯判斷越來(lái)越多,鋪天蓋地的if() else()語(yǔ)句實(shí)在讓我捉襟見(jiàn)肘:
這還僅僅是角色只有數(shù)個(gè)動(dòng)作的情況下,如果后期角色動(dòng)作越來(lái)越多,那么這種編碼方式不僅容易出錯(cuò),而且還難以維護(hù),我意識(shí)到自己正在朝一個(gè)錯(cuò)誤的方向前進(jìn)。在做了一番調(diào)研后,發(fā)現(xiàn)有限狀態(tài)機(jī)(Finite-state machine,簡(jiǎn)稱FSM)是解決這類問(wèn)題的方案之一。不過(guò)在使用狀態(tài)機(jī)之前,首先要明確都有些什么狀態(tài),狀態(tài)之間是如何切換的。在稿紙上畫一張草圖來(lái)整理一下思路:
?
可以發(fā)現(xiàn),雖然現(xiàn)在角色只有四種狀態(tài),但按鍵分支已經(jīng)達(dá)到八種,而且還沒(méi)有考慮到在每個(gè)狀態(tài)中雖然按下按鍵但不改變狀態(tài)的情況,比如跳躍中按下A/D鍵能左右移動(dòng)但還是跳躍狀態(tài)。
下面就到了實(shí)現(xiàn)狀態(tài)機(jī)的階段了。狀態(tài)機(jī)首先要有一個(gè)標(biāo)識(shí)當(dāng)前狀態(tài)的成員,另外還需要一個(gè)設(shè)置這個(gè)成員的方法:
function FSM() {var activeState = null;//@param state {Function} 每一個(gè)狀態(tài)對(duì)應(yīng)一個(gè)執(zhí)行函數(shù)this.setState = function(state) {activeState = state;};this.update = function() {if (activeState != null) {activeState();}}; }var f = new FSM(); var flag = true;f.setState(function() {console.log('現(xiàn)在是站立狀態(tài)'); });//模擬狀態(tài)切換 (function updateState() {if (flag) {f.setState(function() {console.log('現(xiàn)在是移動(dòng)狀態(tài)');});flag = !flag;} else {f.setState(function() {console.log('現(xiàn)在是站立狀態(tài)');});flag = !flag;}f.update();setTimeout(updateState, 1000); })();不過(guò),這個(gè)狀態(tài)機(jī)在游戲中不會(huì)用到?,這里只是用來(lái)表述一種思路。還有一種是基于堆棧的狀態(tài)機(jī),有時(shí)稱之為下推自動(dòng)機(jī)(Pushdown automata)
這種狀態(tài)機(jī)在工作時(shí),只有棧頂?shù)脑靥幱诩せ顮顟B(tài)。
一次只允許一種狀態(tài)激活,這樣就方便了游戲在各種狀態(tài)間進(jìn)行切換,同時(shí)避免了代碼邏輯混亂的問(wèn)題。
在update中使用條件選擇語(yǔ)句來(lái)進(jìn)入各個(gè)分支:
update(dt) {switch (state) {case STATE.IDLE: //空閑this.updateIdle(dt);break;case STATE.WALKING: //移動(dòng)this.updateWalking(dt);break;case STATE.JUMPING: //跳躍this.updateJumping(dt);break;case STATE.DASHING: //沖刺this.updateDashing(dt);break;case STATE.DASHING_JUMPING: //沖刺跳this.updateDashingJumping(dt);break;} }再次回顧一下上面的思路草圖,在空閑狀態(tài),角色能過(guò)渡到的狀態(tài)有跳躍、移動(dòng)、沖刺,代碼實(shí)現(xiàn)如下:
//空閑 updateIdle(dt) {this.speed.x = 0; //處于靜止?fàn)顟B(tài),速度為0if (key[65]) { //向左移動(dòng)this.speed.x -= this.speedX;this.direction = -1;this.state = STATE.WALKING; //進(jìn)入移動(dòng)狀態(tài)this.play(); //播放移動(dòng)狀態(tài)時(shí)的動(dòng)畫 }if (key[68]) { //向右移動(dòng)this.speed.x += this.speedX;this.direction = 1;this.state = STATE.WALKING;//同上this.play();}if (key[75]) { //跳躍if (!this.jumping) { //這里不用判斷onGround,因?yàn)樘幱趇dle狀態(tài)必然是onGroundthis.state = STATE.JUMPING;//進(jìn)入跳躍狀態(tài)this.jumping = true;this.speed.y = this.jumpSpeed;}}if (key[85]) { //沖刺if (!this.dashing) {this.dashLifeTime = CONFIG.MAX_DASH_LIFE_TIME;this.state = STATE.DASHING;//進(jìn)入沖刺狀態(tài)this.dashing = true;this.speed.x += CONFIG.DASH_SPEED * this.direction;}} else {this.dashing = false;}this.speed.y += this.gravity;//更新位置this.moveX(dt);this.moveY(dt);if (this.pos.y >= 9.375) {this.speed.y = 0;this.pos.y = 9.375;if (!key[75]) this.jumping = false;} }在上面的代碼中,如果按下了移動(dòng)鍵,則會(huì)進(jìn)入移動(dòng)狀態(tài),游戲再次循環(huán)時(shí),就會(huì)執(zhí)行updateWalking方法。如法炮制,就能很輕易地實(shí)現(xiàn)剩余的方法。
//移動(dòng) updateWalking(dt) {this.state = STATE.IDLE;this.speed.x = 0;if (key[65]) {this.speed.x -= this.speedX;this.state = STATE.WALKING;this.direction = -1;}else if (key[68]) {this.speed.x += this.speedX;this.state = STATE.WALKING;this.direction = 1;}if (key[75]) {if (!this.jumping) {this.state = STATE.JUMPING;this.jumping = true;this.speed.y = this.jumpSpeed;}} else {this.jumping = false;}if (key[85]) { //沖刺if (!this.dashing) {this.dashLifeTime = CONFIG.MAX_DASH_LIFE_TIME;this.state = STATE.DASHING;this.dashing = true;this.speed.x += CONFIG.DASH_SPEED * this.direction;}} else {this.dashing = false;}this.moveX(dt);this.moveY(dt);if (this.state === STATE.IDLE) this.play(); }本篇結(jié)束,有空再繼續(xù)更新。
P.S.在沒(méi)有使用狀態(tài)機(jī)之前,我考慮的是通過(guò)記錄按鍵的順序與組合來(lái)實(shí)現(xiàn)各種動(dòng)作,既繁瑣又容易出錯(cuò),代碼感覺(jué)都看不下去了,還好懸崖勒馬,才避免了許多無(wú)用功?。
?
轉(zhuǎn)載于:https://www.cnblogs.com/undefined000/p/use-finite-state-machine-in-2D-Platform-Game.html
總結(jié)
以上是生活随笔為你收集整理的HTML5 2D平台游戏开发#4状态机的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [PY3]——IO——文件目录操作
- 下一篇: lintcode-517-丑数