Jump to content
  • Advertisement
Sign in to follow this  
Endar

Inconvenient OO design in state machine class?

This topic is 3940 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Since I started work, we've been using state machines everywhere to work with the different states of objects (as you would expect :D). Previously, I had been doing it the harder way, by creating an enum that lists the different states, having a member variable describing the current state and just having a large 'if else' in the object's update function. I decided to write one last night for my current demo, which is still in fairly early stages, so there was practically no changes necessary. each state is a single object with 3 functions: onEnter, onExit, onUpdate. Now, even the first thing I needed to do was to have a state for a particular game object and I had to write a base object for that state and then another object for each state.
class StateMachineState
{
public:

	virtual void onEnter() = 0;
	virtual void onUpdate() = 0;
	virtual void onExit() = 0;

};

class ObjectStateMachineState	:	public StateMachineState
{
private:
	Object* ptr;

public:

	ObjectStateMachineState(Object* p)
	:	ptr(p)
	{ }
};

And then I derive the needed classes, like 'move', etc, etc from 'ObjectStateMachineState'. The problem with this is that with simple states, like the one I implemented last night, which is nothing more than moving an object according to the current frame's timestep, still took 20 or so lines, apart from the one line creation and another to change the state. For a complicated class, this is no problem as complex classes are often longer and so 20 lines seems like very little, but with a class whose required functionality is two lines, having to write a 20 line class seems a bit much. Is it too much? Is it worth it leaving my states as individual objects?

Share this post


Link to post
Share on other sites
Advertisement
I'd just use an enum with switch statements. Using inheritance for this seems unnecessary.

Can you give an example of a FSM that you are trying to implement?

Share this post


Link to post
Share on other sites
Quote:
Original post by Poita
I'd just use an enum with switch statements. Using inheritance for this seems unnecessary.

Can you give an example of a FSM that you are trying to implement?


Yes, inheritance for this particular FSM is unnecessary, at least at the moment. I do intend to do some basic AI soon and I thought that a state machine would be useful.

In the state stuff I've done previously, I did use an enum with switch statement, but I found it ... well, iffy in terms of easily finding the enter and exit code, not to mention that the update function was usually a large, messy function.

Share this post


Link to post
Share on other sites
It seems to me that you're not usually going to write states like Move. Instead you'll probably use states like Chase, Evade, Patrol, etc, and those will most likely not take 2 (or 20) lines of code. With these you might see more benefit.

Share this post


Link to post
Share on other sites
Do you think it would be easier to have an enum and an 'if else' in the object update function, for the simpler things like 'move', 'turn' and the simpler states, or should I just leave it as it is and use the state machine and state objects for everything to prevent confusion?

I would still use the state machine for the higher level AI states such as Chase, Evade, etc to make the descisions, regardless of whether I go the enum way for the simpler states.

Share this post


Link to post
Share on other sites
leave your state's as individual objects. You can always use some macros to reduce the code required for 2 line states. It's easy to implement, easy to read and understand, and easy to debug. In the long run, trust me, it's a very good idea.... (speaking from experiance)

Share this post


Link to post
Share on other sites
A really basic macro for declaring a base class state for an object


#define DECLARE_BASE_STATE(X) class X##StateMachineState : public StateMachineState { public: X##StateMachineState(X* obj) : mObject(obj) {} protected: X* mObject; };



then to replace the OP's original example, you'd just need to do :

DECLARE_BASE_STATE(Object)


Then extend with something like:


#define DECLARE_MOVE_FORWARD(X) class X##MoveForwardState : public X##StateMachineState { public: X##MoveForwardState(X* obj) : X##StateMachineState(obj) {} void onUpdate() { mObject->Position += mObject->GetForwardDir()*GetTimeStep(); } };

#define DECLARE_MOVE_BACKWARD(X) class X##MoveBackwardState : public X##StateMachineState { public: X##MoveBackwardState(X* obj) : X##StateMachineState(obj) {} void onUpdate() { mObject->Position -= mObject->GetForwardDir()*GetTimeStep(); } };
#define DECLARE_MOVE_FORWARD_BACKWARD(X) DECLARE_MOVE_FORWARD(X) DECLARE_MOVE_BACKWARD(X)



Yes, you could use a template such as:


template<typename T>
class TStateMachineState
: public StateMachineState {
public:
TStateMachineState(T* obj)
: mObject(obj) {}
protected:
T* mObject;
};
template<typename T>
class TForwardStateMachineState
: public TStateMachineState<T> {
public:
void onUpdate() {
mObject->Position += mObject->GetForwardDir()*GetTimeStep();
}
};
template<typename T>
class TBackwardStateMachineState
: public TStateMachineState<T> {
public:
void onUpdate() {
mObject->Position -= mObject->GetForwardDir()*GetTimeStep();
}
};



personally speaking, I prefer the macro approach. - I'm now expecting someone to list the reasons as to why templates are better than macros. I'm not wanting to get into a religous war over it, so save yourself the effort ;)

Share this post


Link to post
Share on other sites
sorry, the source tags remove the \'s from the macros.... tried duplicated without any formatting, but neither the source, code, pre tags, or untagged text allows you to use \'s.

Share this post


Link to post
Share on other sites
If the little states follow a particular pattern then it might be sufficient to template them. If the little states are almost similar except for Update (for example) then it might be sufficient to make a common 'simple' state that takes a function object strategy for the very little difference.

But frankly, if you 'waste' 18 lines for a few little states but save a few dozen hours of developer time in modularity, readability and maintainability that's huge gain. Don't miss the forest for the trees.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!