Game Development Stack Exchange is a question and answer site for professional and independent game developers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm new to libgdx, and I am finding I am getting stumped by the simplest of things. It seems to want me to do things a specific way, but the documentation won't tell me what that is.

I want to make a very simple 2d game in which the player controls a spaceship. The mouse wheel will zoom in and out, and information and controls are displayed on the screen.

But I can't seem to make the mouse wheel NOT zoom the UI. I've tried futzing with the projection matrices in between

Here's my (current) code:

public class PlayStage extends Stage {
...
    public void draw() {
    // tell the camera to update its matrices.
    camera.update();

    // tell the SpriteBatch to render in the
    // coordinate system specified by the camera.
    spriteBatch.setProjectionMatrix(camera.combined);

    spriteBatch.begin();

    aButton.draw(spriteBatch, 1F);

    playerShip.draw(spriteBatch, 1F);

    spriteBatch.end();
}
}

camera.zoom is set by scrolled(int amount).

I've tried about a dozen variations on the theme of changing the camera's projection matrix after the button is drawn but before the ship is, but no matter what I do, the same things happen to both the button and the ship. So:

What is the usual libgdx way of implementing an on-screen UI that isn't transformed by the camera's projection matrix/zoom?

share|improve this question
    
You could use the camera.project(Vector3 screenCoords) to project something from world coordinates to screen cords. – DJMethaneMan Sep 8 '15 at 20:15

You can just use another SpriteBatch without setting projection matrix to draw the HUD,

camera.update();
spriteBatch.setProjectionMatrix(camera.combined);
spriteBatch.begin();
aButton.draw(spriteBatch, 1F);
playerShip.draw(spriteBatch, 1F);
spriteBatch.end();

hudBatch.begin();
//Draw using hudBatch
hudBatch.end();
share|improve this answer
1  
For what I was doing, I found this to be the simplest approach, for basic UI which should always appear at the same spot on the screen (like scores, lives, etc) – Richard Aug 26 '13 at 20:37
    
Having the spritebatch without projection matrix led to different positioning on different screen resolutions when I tried this – codeulike Mar 11 '14 at 0:36

I think the easiest way to accomplish a hud map would be to use a second camera and overlay them. This issue has been discussed on the libgdx forums a while back and I remember someone over there posting their hud code. You may want to poke around over there and see what you come up with.

share|improve this answer
2  
Yes, this is the right answer. Or use a separate Stage for hud and draw it after game stuff. – Matsemann Jun 30 '12 at 4:40
3  
Thank you. I'll try both. I didn't realize it was common practice to have more than one Stage or Camera per Screen. – Devin Carless Jun 30 '12 at 17:34
3  
Can you please add some sample code, or maybe @DevinCarless? – ashes999 Jan 3 '14 at 22:28

Here is a method I use for working with a single batch:

First draw everything else, then draw your HUD last:

Matrix4 uiMatrix = cam.combined.cpy();
uiMatrix.setToOrtho2D(0, 0, WIDTH, HEIGHT);
batch.setProjectionMatrix(uiMatrix);
batch.begin();

If you want to draw more after, make sure you reset the projection matrix to whatever it needs to be.

share|improve this answer
    
This worked for me thanks – Shersha Fn Jan 8 at 18:18

Remember, the first camera is where the background is fixed. The second one is where the ground moves. If you're wondering why the sprite moves in the stage because the secret it the ground that moves. The sprite is just walking in place since you're using a third camera. You might scrolled the second camera's ground but the HUD is still in place on third. Promise, it's true! The third camera is where the it displays the sprite in center for direction, whether he goes left or right by a little animation code, and the HUD (i.e. score, remaining lives, item used). If you need something, ask me.

share|improve this answer

I have done it like this:

First i have created a new Class called Hud. It implements Disposable because of the resource management. Then you need to define a Stage for your content and a new viewport because a new camera will be used. You need to define a new Tablethat you can add to the Stage. You can add your content to the table like usual. The rest of the code i will put to show how it works is game specific so just ignore it.

public class Hud implements Disposable{

public Stage stage;
private Viewport viewport;

//score && time tracking variables
private Integer worldTimer;
private float timeCount;
private static Integer score;
private boolean timeUp;

//Scene2D Widgets
private Label countdownLabel, timeLabel, linkLabel;
private static Label scoreLabel;

public Hud (SpriteBatch sb){
    //define tracking variables
    worldTimer = 250;
    timeCount = 0;
    score = 0;

    //setup the HUD viewport using a new camera seperate from gamecam
    //define stage using that viewport and games spritebatch
    viewport = new FitViewport(GetTheTriforce.V_WIDTH, GetTheTriforce.V_HEIGHT, new OrthographicCamera());
    stage = new Stage(viewport, sb);

    //define labels using the String, and a Label style consisting of a font and color
    countdownLabel = new Label(String.format("%03d", worldTimer), new Label.LabelStyle(new BitmapFont(), Color.WHITE));
    scoreLabel =new Label(String.format("%06d", score), new Label.LabelStyle(new BitmapFont(), Color.WHITE));
    timeLabel = new Label("LEFTOVER TIME", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
    linkLabel = new Label("POINTS", new Label.LabelStyle(new BitmapFont(), Color.WHITE));

    //define a table used to organize hud's labels
    Table table = new Table();
    table.top();
    table.setFillParent(true);

    //add labels to table, padding the top, and giving them all equal width with expandX
    table.add(linkLabel).expandX().padTop(10);
    table.add(timeLabel).expandX().padTop(10);
    table.row();
    table.add(scoreLabel).expandX();
    table.add(countdownLabel).expandX();

    //add table to the stage
    stage.addActor(table);

}

public void update(float dt){
    timeCount += dt;
    if(timeCount >= 1){
        if (worldTimer > 0) {
            worldTimer--;
        } else {
            timeUp = true;
        }
        countdownLabel.setText(String.format("%03d", worldTimer));
        timeCount = 0;
    }
}

public static void addScore(int value){
    score += value;
    scoreLabel.setText(String.format("%06d", score));
}

@Override
public void dispose() { stage.dispose(); }

public boolean isTimeUp() { return timeUp; }


public static Label getScoreLabel() {
    return scoreLabel;
}

public static Integer getScore() {
    return score;
}

}

and then in the Playscreen like this:

first of all you need a variable to reference your hud like:

private Hud hud; 

and then in the constructor you create an new instance of your class:

hud= new Hud(); 

in the update- method you need to put these lines of code since i think you want to display some game information like points or the lives left:

hud.update();

in the render- method do this:

//Set batch to now draw what the Hud camera sees.
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();

and at the end don't forget to dispose your hud in the dispose- method

i hope that helps

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.