Adding a HUD

Basic components of Scene2D

The Scene2D library is mainly used for creating UIs and overlays that provide additional information to the player.  There are 3 main components/classes used: Stage, Group, Actor.  The Stage is at the top of the hierarchy and is basically the container that holds and handles the Actors.  It also acts as an input processor, so any inputs required by the actors are passed through the Stage.

Let’s create a new class and call it Hud, so we don’t overload our screen class with functionality.  If you’re going to take CS in IB, low cohesion, meaning the class is doing a wide variety of stuff, is something you should avoid!  

In order to make a Stage, it needs a Viewport.  In case you forgot what a viewport is, it basically controls how the Stage will be displayed on the screen and therefore to the player. We’ll use the same viewport as the one we used in our screen, which is the FitViewport.

IMPORTANT: Make sure to import the correct classes, since there are multiple Stage classes out there. Always import the LibGDX one.

public class Hud
{
    private Viewport viewport;
    private Stage stage;
    public Hud()
    {
        viewport = new FitViewport(Constants.WIDTH, Constants.HEIGHT, new OrthographicCamera());
        stage = new Stage(viewport);

    }
}

Now moving onto Group, it’s actually also an Actor, but it can hold child actors.  If we were to have individual actors spread across the whole Stage, it would be quite hard to manage, in case you want to resize or reposition some of them, that’s when Groups come in handy.  For UIs, it’s really common to use a Table which fills up the entire screen, and that’s what we’re going to use.  Rather than resizing each actor, Table can also help set constraints on how multiple actors can be resized and positioned at once, and therefore it’s best practice to do any resizing and repositioning on the Table rather than each actor.

We can create the Table like so in the code below. setFillParent(true) makes sure the Table fiills up the whole Stage, and table.debug() is a great method that helps you draw lines so you know where your table rows and columns start and end. Simply put, it’s great with debugging.

public Hud()
{
    //existing code
    Table table = new Table(); 
    table.setFillParent(true);
    table.debug();
}

Lastly, Actors.  They’re basically the UI widget components that you would be using and showing onto the screen, such as buttons, labels, images, etc.  There’s a lot of different widgets available in the library and I can’t really go through all of them, so in this video I’m just going to show 2 basic ones, Label and Button.

Label

A Label displays text, and the constructor requires the text, and a LabelStyleLabelStyle simply defines the style of the label, such as the font and the color.  I’m going to make labels for the level number, the score.

private int score;
private Label levelLabel;
private Label scoreLabel;
private Label levelNumberLabel;
private Label scoreNumberLabel;

public Hud()
{
    //existing code
    Label.LabelStyle labelStyle = new Label.LabelStyle(new BitmapFont(), Color.WHITE);
    levelLabel = new Label("LEVEL", labelStyle);
    scoreLabel = new Label("SCORE", labelStyle);
    levelNumberLabel = new Label("1-1", labelStyle);
    scoreNumberLabel = new Label("" + score, labelStyle);
}

Moving on to Buttons, I’ll simply create a TextButton just to show how it works. Similar to Labels, it also needs a ButtonStyle. We can create a button like so:

TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle();
buttonStyle.font = new BitmapFont();
tempButton = new TextButton("TEMP", buttonStyle);

ADDITIONAL CONTENT: If you wish to create a background image for the button, that can be added to the ButtonStyle. You would have to pack the background image(s) into a texture pack (refer to Sprite tutorial if needed). Up refers to when the button is not clicked, and Down refers to when the button is clicked or highlighted.)

Skin buttonSkin = new Skin();
TextureAtlas buttonAtlas = new TextureAtlas(<put your .atlas filename as a String here>);
buttonSkin.addRegions(buttonAtlas);
buttonStyle.up = buttonSkin.getDrawable(<put String of normal button's area (found in .atlas) here>);
butonStyle.down = buttonSkin.getDrawable(<put String highlighted button's area (found in .atlas) here>);

Since it’s a button, it means you can click on it. And since you can click on it, obviously you would want the button to do something when it’s being clicked. In order to do that, we can use the addListener() method like so:

tempButton.addListener(new InputListener()
        {
            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button)
            {
                //whatever you want the program to do after the button is clicked
                Gdx.app.log("triggered", "tempButton"); 
                return super.touchDown(event, x, y, pointer, button);
            }
        });

Note: There are several methods within InputListener that can cater to different inputs, such as KeyDown(), keyUp(), scrolled(), and many more.

Since our Stage now needs to listen for input, we have to add this line of code to our constructor, preferably right after the stage is made, but the positioning of it doesn’t really matter:

Gdx.input.setInputProcessor(stage);

Adding Actors to Table

To add an Actor to a table, you can simply do:

table.add(<whatever your Actor is called>);

There are many methods built into the Table class that can help you with positioning each actor. For example, expandX() tells the cell to take up the entire Table’s extra space in the X-direction, and row() helps make a new row in your Table, meaning any Actors added to the table after that line will be on the next row.

It’s kind of hard to explain each built-in method one by one here, but if you’re interested you can watch the video lesson which goes through them in a bit more detail. Some of the methods are self explanatory.

The code I used in the video for the table is as follows: (Scroll to the bottom for the image)

public Hud()
{
    //existing code
    table.top();    
    table.add(levelLabel).expandX().padTop(10);
    table.add(scoreLabel).expandX().padTop(10);
    table.row();
    table.add(levelNumberLabel).expandX();
    table.add(scoreNumberLabel).expandX();
    table.row();
    table.add(tempButton).colspan(2).fill();

    stage.addActor(table)
}

The red lines generated are due to the table.debug() method, so once you’re set with the layout of your table, you can simply remove that line of code and the lines will disappear. Tip: All actors have that debug() method and it can come in handy often.

Drawing the HUD

The HUD will be drawn in our screen class, so make sure to make a getStage() method in the Hud class just so our screen class can access it. Then, In our LevelOne class, we can use that method to draw our Hud.  So make a new Hud variable in the constructor of your screen class:

private Hud hud;

public LevelOne()
{
    //existing code
    hud = new Hud();
}

Then we can simply call the stage’s draw() method in the render() method within our screen class.

IMPORTANT: Make sure to call the draw() method OUTSIDE of the batch, otherwise the player’s sprites don’t get drawn.

@Override
public void render(float delta)
{
    //existing code
    hud.getStage().draw();
}

And this is what our Hud looks like:

Video Lesson

https://drive.google.com/file/d/1_JjMy-bLwo8pN7neW2Wl97DjBceVCvmk/view?usp=sharing