Hello! I am currently working on a FSM for a project at my university. But I have problem with figuring out if I meet the criteria for this program.
I need to have a state that have sub-states (Hierarchical states). This code is about an AI I know, but the topic itself I feel is more related to general programming.
For example Combat leads to Shooting OR TakingCover. And no other state except for Combat should be able to reach these two states directly they need to go through Combat. This is how I have interpreted Hierarchical Finite State Machine anyway, so I would really like to have some feedback on this. It is not the most pretty piece of code out there so I apologize in advance. I also made a bitbucket repository if someone feel they need to dig deeper to help me, I do not wanna bloat this post with all the code. This is the code I think is the most important one and I only included the rest for people that feel they wanna study the code more.
TLDR; Is the code below hierarchical or have I misinterpreted something?
Here is my PonyStates.h file
#include "State.h"
class Pony;
class AgentIsHungry : public State
{
public:
static AgentIsHungry* Instance ();
virtual void EnterState (Pony* p);
virtual void ExitState (Pony* p);
virtual void ExecuteState (Pony* p);
private:
// Copy construtor and assignment.
AgentIsHungry() {}
AgentIsHungry (const AgentIsHungry&);
AgentIsHungry& operator= (const AgentIsHungry&);
};
class AgentIsWorking : public State
{
public:
static AgentIsWorking* Instance();
virtual void EnterState(Pony* p);
virtual void ExitState(Pony* p);
virtual void ExecuteState(Pony* p);
private:
AgentIsWorking() { }
// Copy construtor and assignment.
AgentIsWorking(const AgentIsWorking&);
AgentIsWorking& operator= (const AgentIsWorking&);
};
class AgentIsTierd : public State
{
public:
static AgentIsTierd* Instance ();
virtual void EnterState (Pony* p);
virtual void ExitState (Pony* p);
virtual void ExecuteState(Pony* p);
AgentIsTierd() { }
private:
// Copy construtor and assignment.
AgentIsTierd(const AgentIsTierd&);
AgentIsTierd& operator= (const AgentIsTierd&);
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
class AgentIsHavingANightmare : public AgentIsTierd
{
public:
static AgentIsHavingANightmare* Instance();
virtual void EnterState(Pony* p);
virtual void ExitState(Pony* p);
virtual void ExecuteState(Pony* p);
private:
// Copy construtor and assignment.
AgentIsHavingANightmare() {}
AgentIsHavingANightmare(const AgentIsHavingANightmare&);
AgentIsHavingANightmare& operator= (const AgentIsHavingANightmare&);
};
class AgentIsHavingADream : public AgentIsTierd
{
public:
static AgentIsHavingADream* Instance();
virtual void EnterState(Pony* p);
virtual void ExitState(Pony* p);
virtual void ExecuteState(Pony* p);
private:
// Copy construtor and assignment.
AgentIsHavingADream() {}
AgentIsHavingADream(const AgentIsHavingADream&);
AgentIsHavingADream& operator= (const AgentIsHavingADream&);
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
Here is my PonyStates.cpp file
////////////////////////////////
///////// AgentIsTierd /////////
////////////////////////////////
AgentIsTierd* AgentIsTierd::Instance()
{
static AgentIsTierd instance;
return &instance;
}
void AgentIsTierd::EnterState(Pony* p)
{
if (p->WhereAmI() != Bedroom)
{
std::cout << GetName(p->GetID()) << " is walking to the bedroom; it is time to sleep.\n";
p->ChangeRoom(Bedroom);
}
}
void AgentIsTierd::ExitState(Pony* p)
{
std::cout << GetName(p->GetID()) << " is now leaving the bedroom.\n";
}
void AgentIsTierd::ExecuteState(Pony *p)
{
if (p->IsTierd())
{
std::cout << GetName(p->GetID()) << " wishes to sleep. " << GetName(p->GetID()) << " lay down in bed to sleep! Zzz...\n";
if ((rand() % 100) % 2)
p->ChangeState(AgentIsHavingADream::Instance());
else
p->ChangeState(AgentIsHavingANightmare::Instance());
}
else
{
std::cout << GetName(p->GetID()) << " wakes up refreshed! Time to go to work!\n";
p->ChangeState(AgentIsWorking::Instance());
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Good dream
AgentIsHavingADream* AgentIsHavingADream::Instance()
{
static AgentIsHavingADream instance;
return &instance;
}
void AgentIsHavingADream::EnterState(Pony* p)
{
// Already in bedrom.
}
void AgentIsHavingADream::ExitState(Pony* p)
{
std::cout << "\t" << GetName(p->GetID()) << " had a nice dream and is feeling refreshed.\n";
//p->ChangeState(AgentIsHungry::Instance());
}
void AgentIsHavingADream::ExecuteState(Pony* p)
{
p->Sleep();
p->ChangeState(AgentIsHungry::Instance());
}
// Nightmare
AgentIsHavingANightmare* AgentIsHavingANightmare::Instance()
{
static AgentIsHavingANightmare instance;
return &instance;
}
void AgentIsHavingANightmare::EnterState(Pony* p)
{
// Already in bedrom.
}
void AgentIsHavingANightmare::ExitState(Pony* p)
{
std::cout << "\t" << GetName(p->GetID()) << " had a nightmare and didn't sleep very well.\n";
}
void AgentIsHavingANightmare::ExecuteState(Pony* p)
{
p->BadSleep();
p->ChangeState(AgentIsHungry::Instance());
}