900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > HTML5 2D平台游戏开发#4状态机

HTML5 2D平台游戏开发#4状态机

时间:2023-10-22 22:51:16

相关推荐

HTML5 2D平台游戏开发#4状态机

在实现了《HTML5 2D平台游戏开发——角色动作篇之冲刺》之后,我发现随着角色动作的增加,代码中的逻辑判断越来越多,铺天盖地的if() else()语句实在让我捉襟见肘:

这还仅仅是角色只有数个动作的情况下,如果后期角色动作越来越多,那么这种编码方式不仅容易出错,而且还难以维护,我意识到自己正在朝一个错误的方向前进。在做了一番调研后,发现有限状态机(Finite-state machine,简称FSM)是解决这类问题的方案之一。不过在使用状态机之前,首先要明确都有些什么状态,状态之间是如何切换的。在稿纸上画一张草图来整理一下思路:

可以发现,虽然现在角色只有四种状态,但按键分支已经达到八种,而且还没有考虑到在每个状态中虽然按下按键但不改变状态的情况,比如跳跃中按下A/D键能左右移动但还是跳跃状态。

下面就到了实现状态机的阶段了。状态机首先要有一个标识当前状态的成员,另外还需要一个设置这个成员的方法:

function FSM() {var activeState = null;//@param state {Function} 每一个状态对应一个执行函数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('现在是站立状态');});//模拟状态切换(function updateState() {if (flag) {f.setState(function() {console.log('现在是移动状态');});flag = !flag;} else {f.setState(function() {console.log('现在是站立状态');});flag = !flag;}f.update();setTimeout(updateState, 1000);})();

不过,这个状态机在游戏中不会用到?,这里只是用来表述一种思路。还有一种是基于堆栈的状态机,有时称之为下推自动机(Pushdown automata)

这种状态机在工作时,只有栈顶的元素处于激活状态。

一次只允许一种状态激活,这样就方便了游戏在各种状态间进行切换,同时避免了代码逻辑混乱的问题。

在update中使用条件选择语句来进入各个分支:

update(dt) {switch (state) {case STATE.IDLE: //空闲this.updateIdle(dt);break;case STATE.WALKING: //移动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;}}

再次回顾一下上面的思路草图,在空闲状态,角色能过渡到的状态有跳跃、移动、冲刺,代码实现如下:

//空闲updateIdle(dt) {this.speed.x = 0; //处于静止状态,速度为0if (key[65]) { //向左移动this.speed.x -= this.speedX;this.direction = -1;this.state = STATE.WALKING; //进入移动状态this.play(); //播放移动状态时的动画 }if (key[68]) { //向右移动this.speed.x += this.speedX;this.direction = 1;this.state = STATE.WALKING;//同上this.play();}if (key[75]) { //跳跃if (!this.jumping) { //这里不用判断onGround,因为处于idle状态必然是onGroundthis.state = STATE.JUMPING;//进入跳跃状态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;//进入冲刺状态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;}}

在上面的代码中,如果按下了移动键,则会进入移动状态,游戏再次循环时,就会执行updateWalking方法。如法炮制,就能很轻易地实现剩余的方法。

//移动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();}

本篇结束,有空再继续更新。

P.S.在没有使用状态机之前,我考虑的是通过记录按键的顺序与组合来实现各种动作,既繁琐又容易出错,代码感觉都看不下去了,还好悬崖勒马,才避免了许多无用功?。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。