Table of ContentsThe Game ScreenThe Primary Actor

Game State

To make Star Assault a professional-quality game, you need to add support for some additional game states. A state is just a mode in which you place the game to handle different game situations. A good example of two states is playing (normal game play) and paused (where the game just treads water while waiting to return to the play state).

States don't stop there, though. Instead of throwing the player blindly into the game, you'll add a "get ready for the action" state to give the player a chance to get in position to play. You'll also add a state to handle when the player dies (so you can spend a few seconds rubbing it in), and of course the dreaded "game over" state.

Adding State to GameScreen

To add state handling to GameScreen, start by adding a current state field and two states PLAYING and PAUSED.

private int state;
private static int t=0;
public static final int PLAYING = t++;       // game in progress
public static final int PAUSED = t++;         // paused

NOTE

Tip

Notice the use of the incrementing integer t for the state types. This is just an easy way to add and remove entries in the list without having to renumber them.

You'll also add a convenience method to change the state of the game.

public final void setState(int newState)
{
    state = newState;
}

To implement the various states, you need to next move the thread construction code and run method from the application class in the GameScreen class.

public class GameScreen extends Canvas implements Runnable, CommandListener
{
    ...

    private boolean running;
    private int state;

    public GameScreen(StarAssault midlet)
    {
        ...

        // create the game thread
Thread t = new Thread(this);
t.start();
}

An example run method now able to handle a new "paused" state is coded below. This method replaces the existing GameScreen cycle method previously called by the application class's cycle method (which is also no longer necessary).

public void run()
{
    try
    {
        while(running)
        {
            // remember the starting time
            cycleStartTime = System.currentTimeMillis();

            if (state != PAUSED)
            {
            world.cycle();
                repaint();
                ...
                // sleep if we've finished our work early
                timeSinceStart = System.currentTimeMillis() - cycleStartTime;

                if (timeSinceStart < MS_PER_FRAME)
                {
                    synchronized (this)
                    {
                        wait(MS_PER_FRAME - timeSinceStart);
                    }
                }
                else
                    Thread.yield();

            } else        // PAUSED
            {
                // just hang around sleeping if we are paused
                try
                {
                    Thread.sleep(500);
                }
            catch (java.lang.InterruptedException e)
            {
            }
        }
    }
...

This modified version of the run method checks to see whether you're in the paused state before doing any rendering or cycling. If the game is paused, you just sleep for short amounts of time, waiting for the state to return to normal.

This is only the start of your state code. Next, add a state that gives the player a small amount of time before you start the game.

public static final int STARTING_UP = t++;

To implement this, you need to change the run method so that when the game is in this state the world and actors are rendered, but nothing is cycled. This way, the player will be able to see what's going on, but nothing will move. After a timeout (say three seconds), you'll switch into the PLAYING state, and off they'll go.

Before you look at the changes to the run method, add support for the timeout of this state. You'll find that knowing how long you've been in a state is a pretty common requirement, so you should add some generic support to the GameScreen class.

private long timeStateChanged;

public final void setState(int newState)
{
    state = newState;
    timeStateChanged = System.currentTimeMillis();
}

Now take a look at the revised run method to support the starting-up state. Notice I've separated the handling of the rendering (repaint) and cycling code. You only cycle if the game is underway, but you always render (unless the game is paused).

public void run()
{
    try
    {
        while (running)
        {
            ...
// run the cycle (only if they're playing)
if (state == PLAYING)
    world.cycle();

if (state == STARTING_UP)
{
    long timeSinceStateChange = System.currentTimeMillis() 
                                  timeStateChanged;
    if (timeSinceStateChange > 3000)
        setState(PLAYING);
}

Note that we don't bother drawing when in the paused state because it takes too much processing power. The screen won't be blank though, the last rendered screen will stay on the screen (unless something else is drawn over the top, such as the menus).

// always draw unless we're paused
if (state != PAUSED)
{
    repaint();

    ...

So how do you use the starting-up state? Well, first you set it to be the initial state when the player starts the game, but it's really more for when the player starts a new game or life and he needs a moment to gather his bearings. You'll see all of this in action a little later in the chapteralong with some additional states such as "game over" and "dying" when you handle the death of the player's ship.

    Table of ContentsThe Game ScreenThe Primary Actor