Original Post
Hi all! I just started doing some tests implementing states in cpp. I wrote this piece of code in the last hour, and it works pretty well. I'm using function pointers to member functions, which calls a virtual function, so derived classes can easily override a particular state function. The only drawback I see right now is that having arbitrary parameters to state functions would add a lot of complexity to the generated code. I'm looking for feedback, ideas, comments from the community! Thanks! EDIT: Had to remove trailling slashes in macros so source code shows correcly. =[dEkS]=
#define DECLARE_STATE_FUNCCALL(Class, FuncName)
void (Class::*FuncName##FnPtr)();
void FuncName(void)
{
(this->*##FuncName##FnPtr)();
}
#define BEGIN_STATE_DEF
virtual void GotoState(int iStateID)
{
switch(iStateID)
{
#define BEGIN_STATE_DEF_INHERIT(ParentClassName)
virtual void GotoState(int iStateID)
{
ParentClassName::GotoState(iStateID);
switch(iStateID)
{
#define END_STATE_DEF
}
}
#define STATE_DEF_START(StateID)
case(StateID):
#define STATE_DEF_END
break;
#define IMPLEMENT_STATE_FUNC(StateName, FuncName)
FuncName##FnPtr = StateName##FuncName##Call;
#define DEFINE_STATE_FUNC_CALL(StateName, FuncName)
void StateName##FuncName##Call()
{
StateName##FuncName();
}
class kPlayer
{
protected:
virtual void NormalWalk()
{
printf("%s.NormalWalk()\n", m_pPlayerName);
}
virtual void NormalShoot()
{
printf("%s.NormalShoot()\n", m_pPlayerName);
}
virtual void DeadWalk()
{
printf("%s.DeadWalk()\n", m_pPlayerName);
}
virtual void DeadShoot()
{
printf("%s.DeadShoot()\n", m_pPlayerName);
}
public:
kPlayer(char* pPlayerName) : m_pPlayerName(pPlayerName) {}
char* m_pPlayerName;
// States
DECLARE_STATE_FUNCCALL(kPlayer, Walk)
DECLARE_STATE_FUNCCALL(kPlayer, Shoot)
DEFINE_STATE_FUNC_CALL(Normal, Walk)
DEFINE_STATE_FUNC_CALL(Normal, Shoot)
DEFINE_STATE_FUNC_CALL(Dead, Walk)
DEFINE_STATE_FUNC_CALL(Dead, Shoot)
BEGIN_STATE_DEF
STATE_DEF_START(0)
IMPLEMENT_STATE_FUNC(Normal, Walk)
IMPLEMENT_STATE_FUNC(Normal, Shoot)
STATE_DEF_END
STATE_DEF_START(1)
IMPLEMENT_STATE_FUNC(Dead, Walk)
IMPLEMENT_STATE_FUNC(Dead, Shoot)
STATE_DEF_END
END_STATE_DEF
};
class kInvinciblePlayer : public kPlayer
{
protected:
void DeadWalk()
{
printf("%s.NotDeadWalk()\n", m_pPlayerName);
}
void DeadShoot()
{
printf("%s.NotDeadShoot()\n", m_pPlayerName);
}
void NormalCastSpell()
{
printf("%s.NormalCastSpell()\n", m_pPlayerName);
}
void DeadCastSpell()
{
printf("%s.NotDeadCastSpell()\n", m_pPlayerName);
}
public:
kInvinciblePlayer(char* pPlayerName) : kPlayer(pPlayerName) {}
// States
DECLARE_STATE_FUNCCALL(kInvinciblePlayer, CastSpell)
DEFINE_STATE_FUNC_CALL(Normal, CastSpell)
DEFINE_STATE_FUNC_CALL(Dead, CastSpell)
BEGIN_STATE_DEF_INHERIT(kPlayer)
STATE_DEF_START(0)
IMPLEMENT_STATE_FUNC(Normal, CastSpell)
STATE_DEF_END
STATE_DEF_START(1)
IMPLEMENT_STATE_FUNC(Dead, CastSpell)
STATE_DEF_END
END_STATE_DEF
};
int _tmain(int argc, _TCHAR* argv[])
{
kPlayer Player("bob");
Player.GotoState(0);
Player.Walk();
Player.Shoot();
Player.GotoState(1);
Player.Walk();
Player.Shoot();
kInvinciblePlayer InvinciblePlayer("god");
InvinciblePlayer.GotoState(0);
InvinciblePlayer.Walk();
InvinciblePlayer.Shoot();
InvinciblePlayer.CastSpell();
InvinciblePlayer.GotoState(1);
InvinciblePlayer.Walk();
InvinciblePlayer.Shoot();
InvinciblePlayer.CastSpell();
return 0;
}