Adding a Menu

In order to create a menu, it would be good to go through the HUD video first, since I’ll also be using the Scene2D library for our menu, and I won’t do as much explaining in this one as the HUD one because I’ll assume you know the differences between a Stage, Actor, Viewports, etc.  

Similar to our HUD, lets create another class for the Menu, and similar to our HUD, make a Viewport and a Stage variable like so:

private Stage menuStage;
private Viewport menuViewport;

public Menu()
{
    menuViewport = new FitViewport(Constants.WIDTH, Constants.HEIGHT, new OrthographicCamera());
    menuStage = new Stage(menuViewport);
}

And then, we make the Table in our constructor so we can add buttons to our Stage.

menuTable = new Table();
menuTable.setFillParent(true);

This time, instead of having a transparent background, I want the table to have a semi-transparent black background just so it’s more obvious that there’s a menu in the front.

For the Format (3rd argument in Pixmap() constructor), I can choose between RGBA4444 and RGBA8888, the 4 and 8 simply mean whether each channel, r, g, b, or a, is made up of 8 bits or 4 bits.  I’ll just use 8 bits for this one.

Pixmap bgPixmap = new Pixmap(1,1, Pixmap.Format.RGBA8888);
bgPixmap.setColor(0,0,0,0.5f);
bgPixmap.fill();

TextureRegionDrawable textureRegionDrawableBg = new TextureRegionDrawable(new TextureRegion(new Texture(bgPixmap)));
menuTable.setBackground(textureRegionDrawableBg);

Then, we’ll make some buttons, lets just make a restart button and a quit button.

TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle();
buttonStyle.font = new BitmapFont();
TextButton restartButton = new TextButton("RESTART", buttonStyle);
TextButton quitButton = new TextButton("QUIT", buttonStyle);

Afterwards, since they’re buttons, it means they can take input.  For the quit button, we want it to simply quit the game when the button is pressed, and that can be done pretty straightforwardly with the built-in Gdx.app.exit() method.

quitButton.addListener(new InputListener()
{
    @Override
    public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
    {
        Gdx.app.exit();
        return false;
    }
});

For the restart button, we obviously want to restart our game when that button is pressed.  If you recall our GameOver screen, there’s a play again button.  We can use that exact mechanic here, by simply setting the game.setState() to GameState.LEVELONE.

restartButton.addListener(new InputListener()
{
    @Override
    public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
    {
        game.setState(GameState.LEVELONE);
        return false;
    }
});

And because our setState() method needs a game object, we need to remember to pass the DemoGame object through the constructor when instantiating our Menu object:

private DemoGame game;

public Menu(final DemoGame game)
{
    this.game = game;
}

IMPORTANT: The game parameter requires the final keyword because it is accessed from an inner class, the InputListener class.  If you don’t include the final keyword, you’ll see an error.

At the end, don’t forget to add the Buttons to our Table, and then add the Table to our Stage.

menuTable.add(restartButton);
menuTable.row();
menuTable.add(quitButton);
menuStage.addActor(menuTable);

Now, in our LevelOne class, we can make a new Menu object variable in the constructor, and then remember to pass the DemoGame object through like so:

private Menu menu;

public LevelOne(DemoGame game)
{
    //existing code
    this.menu = new Menu(myGame);
}

If you recall the Updating Input Processors lesson, since our Menu class has buttons that need to take in input, we also need to add our Menu class’s Stage to the InputMultiplexer object.  Similar to the Hud class, we can write a getStage() method in our Menu class, and use that to add the InputProcessor:

inputMultiplexer.addProcessor(menu.getStage());
Gdx.input.setInputProcessor(inputMultiplexer);

Now, we have to find a way to show our menu.  And obviously we only want the menu to be shown after we press a certain button.  We also want to pause our game when the menu is shown, and we can do that by adding another conditional in our InputListener’s keyDown() method like so:

if(keycode == Input.Keys.ESCAPE)
{
    game.setState(GameState.PAUSE);
}

However, after pausing the game, we also need to find a way to resume the game.  We can add another GameState to our GameState enum class, called RESUME

public enum GameState
{
    LEVELONE, LEVELTWO, ENDGAME, PAUSE, RESUME;
}

We also need to add a getState() method in our DemoGame class:

public GameState getState()
{
    return currentState;
}

After that, we can then edit our if statement from above (in the keyDown() method in InputListener), and resume our game after the player presses escape again:

if(keycode == Input.Keys.ESCAPE)
{
    if(game.getState() == GameState.PAUSE)
            {
                game.setState(GameState.RESUME);
             }
        else
            {
                game.setState(GameState.PAUSE);
            }
}

Similar to our Menu class, we also need to pass the DemoGame object through to our InputListener class because setting game states requires the DemoGame object.  You can do that simply by adding it as a parameter in the constructor, and making another variable to store the argument in that variable.

private DemoGame game;
public InputListener(Player player, DemoGame game)
{
    this.player = player;
    this.game = game;
}

Don’t forget to update your instantiation of your InputListener object in your LevelOne class to include the new argument:

InputProcessor processor = new InputListener(player, game);

And now, moving on to drawing our actual menu when our game is paused.  In our render() method in our LevelOne class, we only want our game to update when the game is not paused.  We can do that by wrapping our update() call within an if statement to check if the game is paused or not, like so:

if(myGame.getState() != GameState.PAUSE)
{
    update(delta);
}

And to draw our menu when the game is paused, we can simply call the Stage’s draw() method if getState() equals to PAUSE.

if(myGame.getState() == GameState.PAUSE)
{
    menu.getStage().draw();
}

Video Lesson