Advanced State System: Queues and Removal

October 1st, 2008 by John Sedlak Leave a reply »

During the last part of this little article series I mentioned how I used a queue in each state object to allow for continuous transitioning to occur. The reason for this is to allow for complex transitioning to occur. One example for this is a logo screen where it needs to fade in, stay on screen and then fade out again. Rather than relying on managing the states manually, we can add states on to a queue so they occur automatically.

In the StateObject class, let’s add a private queue to the list of private fields.

1
private Queue<State> statesToTransition = new Queue<State>();

Next up, we need to fix the Transition function to take into consideration the queue. Instead of beginning the transition immediately, we need to add it to the queue and then check if we can use it.

1
2
3
4
5
6
public virtual void Transition(State newState)
{
    statesToTransition.Enqueue(newState);
 
    CheckForNewTransition();
}

Note that we have removed the transitioning code and put it inside a new function that we need to create.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected virtual void CheckForNewTransition()
{
    if (CurrentState == States.Transitioning)
        return;
 
    if (statesToTransition.Count > 0)
    {
        CurrentState = States.Transitioning;
        NextState = statesToTransition.Dequeue();
 
        transitionTime = NextState.Time;
        currentTime = 0.0f;
    }
}

This function checks to make sure that the object isn’t already transitioning because if it is, we can’t start a new transition. It then checks the queue for a new state to transition to and if so, starts that transition. Because we do not want it to transition only when we add a new state on the queue, we need to add a call to this function in the Update method.

1
2
3
4
5
6
public virtual void Update(GameTime gameTime)
{
    CheckForNewTransition();
 
    UpdateTransition(gameTime);
}

This, unfortunately, is just not good enough! No, we need to add a function so we can adjust the transition time for each state change. This allows us to avoid creating new states just to change their timing. To do this, we simply add an overload to the Transition function.

1
2
3
4
5
6
public virtual void Transition(State newState, float time)
{
    newState.Time = time;
 
    Transition(newState);
}

Now that we can do some fancy transitioning, we also want to make sure we handle when the state changes. We will modify a method in our StateObject, OnStateChanged, which will handle when this situation occurs. What we want to handle is when a special state comes to pass, the RemoveReady state.

1
2
3
4
5
protected virtual void OnStateChanged()
{
    if(CurrentState == States.RemoveReady)
        StateManager.Remove(this);
}

Now we need to adjust StateManager to make sure each state object is given a reference to the manager so this is possible. To do this, we will modify the Load method as follows.

1
2
3
4
5
6
7
public void Load(params IStateObject[] objectsToLoad)
{
    for (int i = 0; i < objectsToLoad.Length; i++)
        objectsToLoad[i].StateManager = this;
 
    currentObjects.AddRange(objectsToLoad);
}

And there you have it. You can download the updated source code below.

ATS: Part 2 (202) - 115.95 KB

Advertisement

Leave a Reply

You must be logged in to post a comment.