找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2144|回复: 0
打印 上一主题 下一主题
收起左侧

浅谈状态机FSM设计方法

[复制链接]
跳转到指定楼层
楼主
ID:107189 发表于 2016-3-6 02:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

状态机,在游戏里面是非常重要的,最简单的状态机,莫过于

switch()
case 1:
    if(not 反复执行状态1)
       进入1状态前要做的准备

    进入1状态的过程

    if(not 反复执行状态1)
       离开状态1的过程

  case2:
...

但这种方式不能很有效预定义所有的状态,也不能把这些状态之间的切换过程合理的定义出来,“状态”本身没有一个合理的定义,几乎是一种面向过程的方式,只过这种方式足够简单,也最容易让人接受,缺点就没有“状态”的定义和指派功能,导致状态的混乱,出现状态处理重复代码,甚至处理不一致的问题,按照OO的观念,状态描述本来就应该是一种实体

比如“吃饭”这种状态,进入要做什么,进行时要做什么,退出时要做什么,需要进行一个描述,以下是我写的状态机管理策略:

//状态的定义
class State
{
public:
State();
State(const char * name);
//状态的名字
std::string statename;
//比较两个状态是否相同
inline bool operator ==(const State& other);
};


//状态机基类
class BaseFsm
{
public:
//状态机的状态描述
State state;
//进入状态
virtual void Enter(FsmEntity *entity);
//执行状态
virtual void Execute(FsmEntity *entity);
//离开状态
virtual void Exit(FsmEntity *entity);
//比较两个状态机是否相同
inline bool operator ==(const BaseFsm& other);
};

//状态机实体
class FsmEntity
{
protected:
  //当前所使用的状态机
  BaseFsm *mCurrentFsm;
public:
  //构造函数
  FsmEntity();
  //析构函数
  virtual ~FsmEntity();
  //设置开始状态
  void InitState(BaseFsm *fsm);
  //状态是否初始化了
  bool IsStateInited();
  //保持状态的方法
  void KeepState();
  //返回当前的状态机
  BaseFsm * GetCurrentFsm();
  //改变状态
  void ChangeState(BaseFsm *newFsm);
};

//状态机容器
class FsmManager
{
private:
//状态机容器的名称
std::string name;
//所有的状态集合
std::map<std::string, BaseFsm *> mStatusCollection;
public:
//命令一些实体去达到某个状态
void Transaction(std::vector<FsmEntity *> & entities, const char * stateName);
//令某个实体达到某个状态
void Transaction(FsmEntity * entity, const char * stateName);
//添加状态机
void AddFsm( BaseFsm * fsm);
//删除状态机
void RemoveFsm(const char * stateName);
//获取状态机
BaseFsm * FindFsm(const char * stateName);
    //构造
FsmManager(const char *fsname);
//析构
virtual ~FsmManager();
};




State::State()
{
}
State::State(const char * name)
{
statename = name;
}

//构造函数
FsmEntity::FsmEntity()
{
  mCurrentFsm = 0;
}
//析构函数
FsmEntity::~FsmEntity()
{
  
}
//返回当前的状态机
BaseFsm * FsmEntity::GetCurrentFsm()
{
return mCurrentFsm;
}
//状态是否初始化了
bool FsmEntity::IsStateInited()
{
if(mCurrentFsm)
   return true;
else
   return false;
}
//设置当前状态
void FsmEntity::InitState(BaseFsm *fsm)
{
if(mCurrentFsm == 0)
{
   mCurrentFsm = fsm;
}
else
{
  LOG(0, WARN_LV, "初始状态已经设定");
}
}
//保持状态的方法
void FsmEntity::KeepState()
{
mCurrentFsm->Execute(this);
}
//改变状态
void FsmEntity::ChangeState(BaseFsm *newFsm)
{
if(mCurrentFsm)
    //离开原来的状态
    mCurrentFsm->Exit(this);
//设定现有状态
mCurrentFsm = newFsm;
//进入现有状态
mCurrentFsm->Enter(this);
//执行现有的状态
    mCurrentFsm->Execute(this);
}

//比较两个状态是否相同
bool State::operator ==(const State& other)
{
return statename == other.statename;
}

//进入状态
void BaseFsm::Enter(FsmEntity *entity)
{
  LOG(0, DEBUG_LV, "进入%s状态", state.statename.c_str());
}
//执行状态
void BaseFsm::Execute(FsmEntity *entity)
{
  LOG(0, DEBUG_LV, "执行%s状态", state.statename.c_str());
}
//离开状态
void BaseFsm::Exit(FsmEntity *entity)
{
  LOG(0, DEBUG_LV, "离开%s状态", state.statename.c_str());
}

bool BaseFsm::operator ==(const BaseFsm& other)
{
    return state == other.state;
}
//命令一些实体去达到某个状态
void FsmManager::Transaction(std::vector<FsmEntity *> & entities, const char * stateName)
{
for(size_t i = 0; i < entities.size(); i ++)
{
  FsmEntity *entity = entities[i];
  Transaction(entity, stateName);
}
}
//令某个实体达到某个状态
void FsmManager::Transaction(FsmEntity * entity, const char * stateName)
{
if(entity->GetCurrentFsm() && entity->GetCurrentFsm()->state.statename == stateName)
{
  entity->KeepState(); //保持之前的状态
}
else
{
  BaseFsm * fsm = mStatusCollection[stateName];
  if(fsm)
  {
   //执行状态
   entity->ChangeState(fsm);
  }
  else
  {
            LOG(0, ERROR_LV, "找不到%s状态", stateName);
  }
}
}

//添加状态机
void FsmManager::AddFsm( BaseFsm * fsm)
{
  if(mStatusCollection.find(fsm->state.statename.c_str()) != mStatusCollection.end())
   return; //已经添加过了
  //添加
  mStatusCollection[fsm->state.statename] = fsm;
}
//删除状态机
void FsmManager::RemoveFsm(const char * stateName)
{
  std::map<std::string, BaseFsm *>::iterator it = 0;
  if((it = mStatusCollection.find(stateName)) != mStatusCollection.end())
  {
     mStatusCollection.erase(it);
  }
}
//获取状态机
BaseFsm * FsmManager::FindFsm(const char * stateName)
{
std::map<std::string, BaseFsm *>::iterator it = 0;
if((it = mStatusCollection.find(stateName)) != mStatusCollection.end())
{
   BaseFsm * fsm = it->second;
   return fsm;
}
return 0;
}

//构造
FsmManager::FsmManager(const char *fsname)
{
   name = fsname;
   LOG(0, DEBUG_LV, "构造状态机容器 %s", fsname);
}
//析构
FsmManager::~FsmManager()
{
//移出所有的状态机
for(std::map<std::string, BaseFsm *>::iterator it = mStatusCollection.begin(); it!= mStatusCollection.end(); it++)
{
       BaseFsm * fsm = it->second;
    if(fsm)
   delete fsm;
}
}



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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