用户操作
[留言]  [发消息]  [加为好友] 
订阅我的博客
XML聚合    FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
n5的公告
在信息时代,客观障碍已不复存在,所谓障碍都是主观上的。如果你想研发什么新的技术,你不需要几百万美元的资金,你只需要在冰箱里放满比萨和可乐,再有一台便宜的计算机,和与之献身的决心,你即可拥有任何你想拥有的编程境界!- John Carmack
文章分类
同道中人
lyo-非常酷的J2ME模拟器(RSS)
游戏开发&3D
3D Game Study-google邮件列表
EuclideanSpace - building a 3D world
realtimerendering.com
一个不错的3D教程
专业站点
J2ME开发网
Nokia论坛讨论区
python中文社区
sonyericsson开发者站点
存档

原创  在游戏中使用面向对象的FSM 收藏

在游戏中使用面向对象的FSM

以前一直是用switch的状态机,因为J2ME没办法用太多类,现在改做c++了,终于可以试一试面向对象的状态机了,代码果然简洁了好多。参考的是《Programming Game AI by Example》第2章,大约改了下。首先要定义一个状态基类:



这是一个模板类,因为状态要对应不同的所有者,比如游戏状态的所有者是游戏类Game,而主角状态这里的entity_type就是主角类Hero。总之,状态对于状态拥有者实体是依赖关系。因为实体有很多种状态,所以要定义具体的状态子类,比如主菜单状态是游戏状态类的子类:



状态子类采用了单件模式,所以状态子类中不能存放对于拥有者实体来说是自有的数据,比如有很多士兵,那么士兵的状态子类中就不能存放生命值,只能存放在实体中,在状态类中通过实体的指针去访问。我觉得状态采用单件更清晰些,数据就在实体中维护吧,当然也许每个实体有一个对应的状态实例也有合适的使用之处。

然后需要定义状态机类:


状态机类也是模板类,道理一样,每种实体必须有一个对应的状态机类,状态机和实体是聚合关系,状态机保存了实体的指针,从而让状态可以访问实体。状态机和状态既有聚合关系也有依赖关系,状态机维护了当前状态,上一个状态,以及一个全局状态,从而对当前及全局状态进行Update和Render,并且通过 ChangeState管理状态的切换,切换状态时要调用旧状态的OnExit和新状态的OnEnter,设置第一个状态比较特殊,所以我加了 SetFirstState,只有对新状态的处理,原书中是直接设置,这样不会调用OnEnter了。

最后看实体怎么使用状态机,比如有一个Game类,首先他需要拥有一个状态机实例(也是聚合关系):
class Game
{
    StateMachine<Game>*  m_pFSM;
};

这个实例可以在Game构造时构造好:
Game::Game(void)
{
    m_pFSM = new StateMachine<Game>(this); 
}
析构时删除
Game::~Game()
{
   delete m_pFSM;
}
游戏初始化时可设置第一个状态:
m_pFSM->SetFirstState(GSLogo::GetInstance());//这里是显示Logo

在Game Update和Render时分别调用状态机的Update和Render即可
void Game::Update(float dt)
{
    ...
    m_pFSM->Update(dt);
   ...
}

void Game::Render(float dt)
{
  ...
  m_pFSM->Render(dt);
  ...
}

那么状态的切换呢?是在状态子类中进行的,比如游戏从主菜单进入关卡,在主菜单状态的Update逻辑中:
void GSMainMenu::Update(Game* pGame, float dt)
{
   ...
    if(Start按钮按下)
    {
        pGame->GetFSM()->ChangeState(GSLevelLoading::GetInstance());
    }
   ...
}
游戏类有GetFSM方法让状态类得到状态机,切换状态时直接调用相应状态类的GetInstance得到唯一的状态实例

 总结:
1)实体拥有一个状态机,实体通过状态机的Update和Render来实现不同状态下的逻辑和渲染
2)状态机指向他的拥有者实体,并且聚合了状态,状态机通过Update和Render来让当前状态执行逻辑和渲染,并且状态机提供了统一的状态切换流程,即先Exit前一状态,然后设置当前状态,并Enter新状态
3)每个实体对应一个状态基类(通过模板化),以及若干子类(通过继承模板基类),状态子类是实体状态的具体实现者,状态子类进行实际的Update和 Render,并且通过实体指针访问实体数据和方法,状态切换也是通过状态子类进行的,即各个子类是独立的,这样能很方便的增加和删除状态,只要修改前后状态的切换就可以了。

发表于 @ 2009年05月09日 17:27:00 | 评论( loading... ) | 编辑| 举报| 收藏

旧一篇:lyo blog3D文章集锦 | 新一篇:成为优秀的程序员真不简单

  • 发表评论
  • 评论内容:
  •  
Copyright © n5
Powered by CSDN Blog