Read Part One and Part Two first. If you don't already own a copy of "Design Patterns" by the Gang of Four I would recommend checking it out, since it seems to be the definitive reference.

This entry will continue the discussion on the State Design Pattern. It will be broken up into two parts: a) Responses from feedback I've received on the previous two articles and b) Explanation of how we handle input events at the base State class while still providing flexibility for concrete states to implement their own input event handlers.

I asked for some feedback on the previous two articles and received a couple comments which I will try to briefly address here. As a refresher, here is the base State Class:


class State {
protected:
  App* pApp;
  
  virtual void handleMouse(); // get mouse input and act
  virtual void handleKeyboard(); // get keyboard input and act
  virtual void draw(); // draw screen if needed
public:
  State(App* _app) : pApp(_app) {   }
  
  virtual void update(); // updated every tick
  // functions used to transition between states
  virtual bool transitionInto(State* fromState);
  virtual void transitionOutOf(State* toState);
};

The first comment essentially pointed out that the transitionInto() and transitionOutOf() functions are named rather confusingly. If I call MainMenuState.transitionInto(TitleScreenState) am I moving from Title Screen into Main Menu or vice versa? To try and make it more obvious the intent of these functions I will rename the functions onEntry(State* prevState) and onExit(State* nextState) to make clear their intent. If a particular state needs to perform some actions prior to the state machine entering into the main loop of the state (i.e. repeatedely calling the update() function) it places these actions into the onEntry() function. Similarly if a state machine needs to perform some "clean up" it puts its actions into the onExit() function. The arguments to these functions let the states know which states it's coming from (in the onEntry() case) or which state it's going to (in the onExit() case).

The second comment stated that making public functions virtual is not a Good Idea (tm). I thought this rather silly until he pointed out this article from Herb Sutter. Who am I to argue with Herb! Well, while I can agree in principle to the contents of the article, in the interest of keeping this discussion simple I am not going to not making any changes as a result of this recommendation. (The "fix" would be to make hide my public virtual functions and then provide an additional three non-virtual functions that call the virtual functions).

The final comments reflected that the articles themselves are dealing mostly with code aspects rather than explaining why we want to do this and why we want to do that. I hope to improve this by actually getting into some of the previously "transparent" portions of the State base class and showing some pseudocode examples.

One further thing I realized while preparing for this article was that the subclasses of State do not need to know about updateKeyboard() and updateMouse() as we'll soon see. As a result, I am making these functions private and non-virtual.

So without further ado, let's update our State class for the above changes to:


class State {
private:
  void handleMouse(); // handle mouse input
  void handleKeyboard(); // handle keyboard input
protected:
  App* pApp;
  virtual void draw(); // draw screen if needed
public:
  State(App* _app) : pApp(_app) {   }
  virtual void update(); // updated every tick
  virtual bool onEntry(State* fromState);
  virtual void onExit(State* toState);
};

The state machine repeatedly calls the update() function of the state which has the following code:


void State::update()
{
  updateKeyboard();
  updateMouse();
  draw();
}

Now there are two main questions: 1) How do we handle input events in the state machine and 2) How do we handle drawing to the screen? I'm going to address #1 in the rest of this article and save #2 for another rainy day.

So we have two input devices: the Mouse and the Keyboard. We can start with the mouse because it has a fewer number of possible events. Let's list all 7 possible events:

- left mouse button pressed
- left mouse button released
- right mouse button pressed
- right mouse button released
- middle mouse button pressed
- middle mouse button released
- mouse moved

Implicit in all these events is that we may also need to know the location of the mouse pointer when the event occured.

Now what we'd like is a way to handle all the above 7 events at the State level while still allow subclasses of State to specify individual behavior. As usual, there are many different ways to skin a cat. This could be handled with 7 new virtual functions to State called onLeftMouseButtonDown(), onLeftMouseButtonUp(), etc and then require subclasses to override these functions with whatever actions they would like. However, I wanted to find a cleaner approach than this while still providing all the same amount of flexibility.

I found it in the C++ Boost library. Specifically, Boost.Function and Boost.Bind. If you haven't looked at Boost and you code heavily in C++, I highly recommend you start looking at it. There's something in Boost for everybody and it will change the way you program for the better.

Boost.Function provides "function object wrappers for deferred calls or callbacks". In other words, these function objects are mostly like function pointers. However, when you combine Boost.Function with Boost.Bind they allow for much more. Boost.Bind provides "generalized binders for function/object/pointers and member functions". In other words, it provides a mechanism to bind something to a particular function (even a member function of an instantiated object) and bind specific arguments.

Let's put some examples into play so you can see just what the frick I'm talking about. Let's look at one event: "Left Mouse Button Pressed". Now we want the base State class to have a function pointer (or object) for this specific event and allow the subclasses of State (like MainMenuState) to be able to bind any function to this event:


class State
{
  // ...
  boost::function< void (int x, int y) > onLeftMouseDown;
};

There, we have now essentially added a function called onLeftMouseDown to the State class. The function has a void return type and accepts two integer arguments.

In order to show you a bit of updateMouse(), I'm going to pretend we have a way to fetch mouse events called getMouseEvent() and that all mouse events are put into the form of the following structure:


enum EventType { LEFTDOWN, LEFTUP, RIGHTDOWN, RIGHTUP, MIDDLEDOWN, MIDDLEUP, MOVE};
  
struct MouseEvent {
  EventType type;
  int x; // x-coordinate of mouse pointer
  int y; // y-coordinate of mouse pointer
};

Now we can show you a bit of what State::updateMouse() does :


void State::updateMouse()
{
  Event ev = getMouseEvent();
  if (ev.type == LEFTDOWN && onLeftMouseDown) { onLeftMouseDown(ev.x, ev.y); }
}

When boost::function objects are first created, they point at nothing (much like a NULL function pointer). You can check whether a function points at something just as you would a function pointer before making the function call.

What we need to do now is point this function object at something. Let's say we have a MainMenu state (derived publicly from State) and that when the left mouse button is pressed, we want to print out the coordinates of the mouse pointer.


class MainMenu : public State
{
private:
  void printMouseCoordinates(int x, int y) {cout << x << ',' << y << endl;}
};

There's our function that will do the dirty work, now how do we bind State::onLeftMouseDown to MainMenu::printMouseCoordinates()? You got it: Boost.Bind. Let's put it inside the constructor of MainMenu:


MainMenu::MainMenu(App* pApp) : State(pApp)
{
  onLeftMouseDown = boost::bind( &MainMenu::printMouseCoordinates, this, _1, _2);
}

The bind statement wraps up a call to printMouseCoordinates into a little object which we then assign to onLeftMouseButtonDown. The special expressions _1 and _2 are ways to indicate that the function should pass along its two arguments to the bound function. This feature has more implications than this simple usage and it's one of the things that makes Boost.Bind so special.

We fill out the State class with 6 more boost::function objects to handle each mouse event and then we process the functions within State::updateMouse() in a similar fashion. What we end up with is a state machine where each state can assign specific behavior to each mouse event as they see fit (and can change the behavior whenever they'd like).

One thing which became obvious to me was that I would need a generic function that would transition states. I put this at the State level like so:


class State
{
protected:
  void goToState(State* pNewState, int x, int y) { pApp->queueStateTransition(pNewState); }
};

Note that the x and y arguments are not used in the above function. They are put there so it is possible to bind the above function to a mouse event (which will always have two arguments, x and y).

Now let's say that in the MainMenu button I also want to transition to the TitleScreen state whenever the right mouse button is released. Let's update our constructor to do this:


MainMenu::MainMenu(App* pApp) : State(pApp)
{
  onLeftMouseDown = boost::bind( &MainMenu::printMouseCoordinates, this, _1, _2);
  onRightMouseUp = boost::bind( &State::goToState, this, pApp->getState(State_TitleScreen), _1, _2);
}

As I mentioned above, a powerful feature of Boost.Bind is the ability to bind function arguments. In this case, we are binding a 3-argument function (State::goToState()) to a 2-argument function (State::onRightMouseUp(x,y)) by specifying that the first argument will always be a pointer to the State object that we want to go to.

The keyboard handling takes a slightly modified approach since we're dealing with over 200 unique events here. In this case I put a std::map into the State class so that we only track those keyboard events we are interested in. I will show a full implementation of this event handling in my next entry in this series.

§32 · February 3, 2005 · C++, Software, Technology · · [Print]

Leave a Comment to “Matters of State – Part Three”

  1. […] Anyway, I totally reworked the component hierarchy so graphical components of the user interface includes base Components with subclasses of Containers, Labels, Images. All of these components can be bound to event handlers at run-time for the following mouse events: “onMouseEnter”, “onMouseExit”, “onMouseMove”, “onMousePressed”, “onMouseReleased” and “onMouseClicked”. Each game state has a “desktop” container that contains the screen elements and components are added, initialized, positioned and sized and bound to events at run-time. Events are forwarded to the desktop container which handles routing the events down the hierarchy. […]

  2. Chris says:

    I just finished reading this article in the series, it was great. I really need to implement something like this, at the moment I just have for example a bool to say whether I am in the quake like console or not and in the rendering loop I draw either my world or console text and in the update loop I do another check, very ugly code. I’ve only got two states at the moment, but it gets worse and worse the more variety you have in your states (changing physics, sound, ai, etc.) and the more states you have, this is *not* the way to do it. I’ll implement something like this tonight.

    Aww man, I have to know math to comment on this blog.