开启辅助访问
 找回密码
 注册帐号

扫一扫,访问微社区

开发者专栏

关注:1963

当前位置:游戏蛮牛 技术专区 开发者专栏

__________________________________________________________________________________
开发者干货区版块规则:

  1、文章必须是图文形式。(至少2幅图)
      2、文章字数必须保持在1500字节以上。(编辑器右下角有字数检查)
      3、本版块只支持在游戏蛮牛原创首发,不支持转载。
      4、本版块回复不得无意义,如:顶、呵呵、不错......【真的会扣分的哦】
      5、......
__________________________________________________________________________________
查看: 2531|回复: 6

[寒江独钓9527] 游戏中有限状态机FSM的三种实现方法

[复制链接]  [移动端链接]
排名
2841
昨日变化
1

6

主题

27

帖子

838

积分

Rank: 9Rank: 9Rank: 9

UID
103529
好友
10
蛮牛币
1374
威望
0
注册时间
2015-6-18
在线时间
285 小时
最后登录
2017-7-3

专栏作家

QQ
发表于 2016-5-24 10:44:17 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册帐号

x
         有限状态机,英文Finite state machine,简称FSM。至今在游戏中应用广泛,今天总结性地说说其三种实现方法(注意其中的代码系伪代码,主要为说明思想,并不一定能运行。)
(一)基本概念
         首先看看比较严格的定义:有限状态机(Finite State Machine)是具有离散输入和输出系统的一种数学模型。表示有限个状态以及在条件输入下状态之间的转移行为。具有有限个内部状态,随着信号(条件)的输入,内部状态不断地转移。
通常我们用状态迁移图或状态迁移表来表示:(请看以下示例)
图片1.png

图b就是与图a等价的状态迁移表。
系统中可取得的状态=S1,S2,S3,事件=t1,t2,t3,t4。事件t1将引起系统状态S1向状态S3迁移,事件t2将引起系统状
       态S3向状态S2迁移,等等
另外,状态迁移图指明了作为特定事件的结果(状态)。在状态中包含可能执行的行为。


(二)实现方法


下面看看其三种实现方法:
1)switch case/if else设计方法
2)基于表结构的状态机设计方法
3)状态设计模式
下面分别说说其思想(主要基于C/C++伪码):
1)switch case/if else设计方法
enum StateType{state_RunAway,state_Patrol,state_attack};
void Agent::UpdateState(StateType CurrentState){
switch(CurrentState) {
  case state_RunAway:
           EvadeEnemy();
           if (Safe())    {  ChangeState(state_ Patrol);   }
           break;
  case state_Patrol:
           FollowPatrolPath();
           if (Threatened())
           if (StrongerThanEnemy()) { ChangeState(state_Attack); }
           else  {   ChangeState(state_ RunAway); }
           break;
  case state_Attack:
           if  (WeakerThanEnemy())  {  ChangeState(state RunAway); }
           else  {  BashEnemyOverHead(); }
           break;
  }//end switch
}
这个比较简单,不说鸟
2)基于表结构的状态机设计方法
图片2.png

/*状态1的动作表*/
ACT_TABLE_T state1ActTable[] = {
    {EVENT1,state1Event1Fun},
    {EVENT3,state1Event3Fun},
};
/*状态2的动作表*/
ACT_TABLE_T state2ActTable[] = {
    {EVENT2,state2Event2Fun},
};
/*状态表*/
STATE_TABLE_T FsmTable[] = {
    {STATE1,state1ActTable},
    {STATE2,state2ActTable},
};
/*客户端提供的状态处理函数*/
void state1Event1Fun(void* pFsm)
{
   FSM_MoveState((FSM_T*)pFsm,STATE2);
   return;
}
void state1Event3Fun(void* pFsm)
{
   FSM_MoveState((FSM_T*)pFsm,STATE3);
   return;
}
void state2Event2Fun(void* pFsm)
{
   FSM_MoveState((FSM_T*)pFsm,STATE3);
   return;
}

FSM_Regist(&fsm,FsmTable);
    ...

可以看出此种方式,可以实现状态机的热更新,因为这些表格是存在数组里面的。用c#的代理是可以较容易实现的,用cc++的话需要用函数指针即可。
3)状态设计模式
UML图如下所示
图片3.png

用一下图示为示例:
QQ截图20160524103926.png

1.环境(Context): Gun.java
public  class  Gun{
       State  state;
       public  void  Gun(){
          state = new BulletStateThree(this); }
       public void setState(State  state){  
          this.state=state; }
       public State getState( ){
          return state;}
       public void fire(){
          state.fire();}
       public void  LoadBullet(){
          state.LoadBullet();}
}
2.抽象状态(State): State.java
public  interface  State{
      public void fire();
        public void LoadBullet();
        public String showStateMess();  
}
3.具体状态(Concrete State)_1:BulletStateThree.java
public class BulletStateThree implements State{
        Gun gun;
        BulletStateThree(Gun gun){this.gun=gun;}
        public void fire(){
        System.out.print(“打出一个子弹”);//do a reflect act
        gun.setState(new BulletStateTwo(this));//transfer to another sate
        }
        public void loadBullet(){System.out.println(“无法装弹”);}
        public String showStateMess(){return “2个子弹状态”;}
}
   具体状态(Concrete State)_2:BulletStateTwo.java
public class BulletStateTwo implements State{
        Gun gun;
        BulletStateTwo(Gun gun){this.gun=gun;}
        public void fire(){
        System.out.print(“打出1个子弹”);
        gun.setState(new BulletStateOne(this));
        }
        public void loadBullet(){System.out.println(“无法装弹”);}
        public String showStateMess(){return “1个子弹状态”;}
}
   具体状态(Concrete State)_1:BulletStateOne.java
public class BulletStateOne implements State{
        Gun gun;
        BulletStateOne(Gun gun){this.gun=gun;}
        public void fire(){
        System.out.print(“打出1个子弹”);
        gun.setState(new BulletStateNull(this));
        }
        public void loadBullet(){System.out.println(“无法装弹”);}
        public String showStateMess(){return “无子弹状态”;}
}
   具体状态(Concrete State)_1:BulletStateNull.java
public class BulletStateNull implements State{
        Gun gun;
        BulletStateNull(Gun gun){this.gun=gun;}
        public void fire(){
        System.out.print(“不能打出子弹”);
        }
        public void loadBullet(){
        System.out.println(“装弹”);
        gun.setState(new BulletStateThree(this));}
        public String showStateMess(){ return “无子弹状态”;}
}
4.Application: Application.java
            public class Application {
        public static void main(String args[]){
        Gun gun=new Gun();
        gun.fire(); gun.fire(); gun.fire(); gun.fire();
        gun.LoadBullet();
        }
}
That's all,3KS







回复

使用道具 举报

6蛮牛粉丝
1193/1500
排名
2513
昨日变化
1

20

主题

393

帖子

1193

积分

Rank: 6Rank: 6Rank: 6

UID
99528
好友
1
蛮牛币
18196
威望
0
注册时间
2015-5-11
在线时间
438 小时
最后登录
2017-10-30
QQ
发表于 2016-5-25 09:42:08 | 显示全部楼层
That's all,3KS
[发帖际遇]: qq718112196 捡了钱没交公 蛮牛币 降了 1 . 幸运榜 / 衰神榜

回复

使用道具 举报

4四处流浪
318/500
排名
9813
昨日变化
4

0

主题

67

帖子

318

积分

Rank: 4

UID
70129
好友
0
蛮牛币
374
威望
0
注册时间
2015-1-21
在线时间
170 小时
最后登录
2017-11-10
发表于 2016-5-25 16:50:25 | 显示全部楼层
感觉我好像是用的第3种。你们呢?不过见识了第二种,很不错。。

回复 支持 反对

使用道具 举报

4四处流浪
330/500
排名
5368
昨日变化
3

0

主题

40

帖子

330

积分

Rank: 4

UID
127501
好友
0
蛮牛币
671
威望
0
注册时间
2015-11-1
在线时间
87 小时
最后登录
2017-7-20
发表于 2016-5-25 17:37:58 | 显示全部楼层
第一种用的习惯了- -。第三种看起来不错,第二种看不懂

回复 支持 反对

使用道具 举报

7日久生情
1838/5000
排名
438
昨日变化
1

0

主题

163

帖子

1838

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
299
好友
2
蛮牛币
4941
威望
0
注册时间
2013-6-11
在线时间
365 小时
最后登录
2017-10-29
发表于 2016-5-25 21:43:58 | 显示全部楼层
不错,谢谢分享。

回复

使用道具 举报

排名
32921
昨日变化
10

1

主题

12

帖子

45

积分

Rank: 1

UID
138597
好友
0
蛮牛币
598
威望
0
注册时间
2016-3-7
在线时间
26 小时
最后登录
2017-11-1
发表于 2016-5-26 08:55:22 | 显示全部楼层
很好很强大

回复

使用道具 举报

7日久生情
2003/5000
排名
17661
昨日变化
6

2

主题

1675

帖子

2003

积分

Rank: 7Rank: 7Rank: 7Rank: 7

UID
185807
好友
0
蛮牛币
2610
威望
0
注册时间
2016-11-22
在线时间
302 小时
最后登录
2017-11-15
发表于 2017-1-18 11:28:36 | 显示全部楼层
不错,谢谢分享

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册帐号

本版积分规则

快速回复 返回顶部 返回列表