新闻  |   论坛  |   博客  |   在线研讨会
有限状态机自动机
lionwq | 2008-01-07 20:02:57    阅读:6033   发布文章

/********************有限状态机自动机***********************/
状态图--一个图的数据结构!
1.while + switch;
2.状态机:就是指定系统的所有可能的状态及状态间跳转的条件,然后设一个初始状态输入给这台机器,机器就会自动运转,或最后处于终止状态,或在某一个状态不断循环。
游戏中状态切换是很频繁的。 可能以前要切换状态就是if~else,或者设标志,但这些都不太结构化, 如果把它严格的设为一种标准的状态机,会清楚的多。

比如控制一扇门的运动, 初始时门是关的, 当有力作用在门上时, 门开始慢慢打开,力的作用完后,门渐渐停止不动, 当有反向的力时,门又渐渐关上, 知道回到初始关的状态。 这个你会怎么来编程实现呢。 似乎很麻烦, 的确,没有状态机的思想时会很烦,设很多标志,一堆if条件。
用状态机的话,不只是代码更清晰, 关键是更符合逻辑和自然规律, 不同状态不同处理, 满足条件则跳转到相关状态。

伪码如下:
enum
{
 CLOSED, // 关上状态
 CLOSING, // 正在关状态
 OPENED, // 打开状态
 OPENING, // 正在开的状态
}doorState = CLOSED; // 初始为关

Update()
{
     switch(doorState)
     case CLOSED:
          if (有人推门)
               doorState = OPENING; // 跳转到正在开状态
     break;
     case OPENING:
          door.Rotation += DeltaAngle; // 门的旋转量递增
          if (门的速度为零) / / 力的作用已去
               doorState = OPENED; // 跳转到开状态
    break;
    case OPENED:
         if (有人关门)
              doorState = CLOSING;
   break;
   case CLOSING:
         door.Rotation -= DeltaAngle; // 门的旋转量递减
         if (门的旋转角度减为零)
              doorState = CLOSED; // 门已关上
    break;
}

// 而绘制代码几乎不用怎么变, 门就是会严格按照状态机的指示去运动, 该停就会停
Render()
{
     RotateView(door.Rotation);
     DrawDoor(door.Position);
}

这是一个简单但很典型的例子, 状态机的应用太多了。
就说一个基本游戏的运转: (用到了一个状态然后还有子状态)
UpdateGame()
BEGIN;
   switch(gameState)
   case 等待选择菜单: //它有三个子状态。
   if (选择菜单项 == 开始)
   {
       游戏初始;
      gameState = 开始游戏
   }
   if (选择菜单项 == 选项)
      gameState = 设置
   if (选择菜单项 == 退出)
       gameState = 退出

 case 开始:
 
 游戏运行;
 if (用户按退出键)
 gameState = 等待选择菜单 ;
 ...其他的状态跳转处理;
 case 退出:
 释放资源;
 退出;
 case 设置:
 分别处理不同的选项, 跳转不同的子状态;
 case .... // 其他状态的处理
 
END;

某一个状态可以包含更多的子状态, 这样最好是同一层次的状态设为一个枚举, 并分到另一个switch处理
如 enum STATES{state1, state2, state3}; state2又包含若干状态
则再定义enum SUB_STATE2{sub_state2_1, sub_state2_2, sub_state2_3,};

想很多基本的渲染效果, 如淡入淡出, 闪烁等等, 用状态的思想会事半功倍, 思路也更清晰。

其实像Opengl, Direct3D这样的渲染引擎本身就是状态机, 当你设置渲染的状态, 这台机器就保持这个状态进行渲染工作,如保持光照位置,保持片元颜色, 直到你再次改变它的状态。

状态机的应用实在太广, 相关理论也很多, 最近上课学的随机过程里也讲到一些, 数字电路里的时序逻辑器件也是用状态机来描述。 这些不必多说了。

总之, 用状态机的角度去看待问题, 往往能把比较复杂的系统分解为能单独处理的众多子状态, 处理也会得心应手。希望大家多用它, 很好的东西。


二、
推荐这个:[程序员杂志2004.8月刊_state模式和composite模式实现的状态机引擎]
http://www.contextfree.net/wangyw/source/oofsm.html

个人感觉状态机的几个不同实现阶段:
1、switch/case 最原始的实现方式,是很多的c程序员习惯采用的方式。

2、查找表[状态、事件、动作],稍微做了一点改进。有点类似MFC的雏形。

3、在以上基础上做的一些改进或者变体。
[比如用一个栈结构,激活的状态位于栈顶,自动的映射事件和动作的对应,再或者通过一些巧妙的宏等手段进行包装。但是线性结构在实际中使用比较受限、过于技巧性的宏比较难于理解...]

4、面向对象的设计下、灵活运用模式。如上面给出的链接。重用性和灵活性方面都有不错的表现。沿袭类似的设计思路、根据实际开发内容进行改造后利用。

参与讨论
登录后参与讨论
淡泊以明志 宁静以致远
推荐文章
最近访客