¿Cómo hago un HUD en pantalla en libgdx?


23

Soy nuevo en libgdx, y estoy descubriendo que las cosas más simples me dejan perplejo. Parece querer que haga las cosas de una manera específica, pero la documentación no me dice qué es eso.

Quiero hacer un juego 2D muy simple en el que el jugador controle una nave espacial. La rueda del mouse se acercará y alejará, y la información y los controles se mostrarán en la pantalla.

Pero parece que no puedo hacer que la rueda del mouse NO haga zoom en la interfaz de usuario. He intentado futzing con las matrices de proyección en el medio

Aquí está mi código (actual):

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 se establece por desplazamiento (cantidad int).

He intentado con una docena de variaciones sobre el tema de cambiar la matriz de proyección de la cámara después de que se dibuja el botón pero antes de que se active la nave, pero no importa lo que haga, las mismas cosas suceden tanto en el botón como en la nave. Asi que:

¿Cuál es la forma habitual de libgdx de implementar una IU en pantalla que no se transforma mediante la matriz / zoom de proyección de la cámara?


Podrías usar el camera.project(Vector3 screenCoords)para proyectar algo desde las coordenadas mundiales hasta los cables de pantalla.
JDSweetBeat

Respuestas:


17

Puede usar otro SpriteBatch sin configurar la matriz de proyección para dibujar el 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();

1
Por lo que estaba haciendo, encontré que este era el enfoque más simple, para la IU básica que siempre debería aparecer en el mismo lugar en la pantalla (como puntajes, vidas, etc.)
Richard

Tener el spritebatch sin matriz de proyección condujo a diferentes posiciones en diferentes resoluciones de pantalla cuando probé esto
codeulike

8

Creo que la forma más fácil de lograr un mapa hud sería usar una segunda cámara y superponerlas. Este tema ha sido discutido en los foros de libgdx hace un tiempo y recuerdo que alguien allí publicó su código hud. Es posible que desee hurgar por allí y ver qué se le ocurre.


2
Sí, esta es la respuesta correcta. O use un escenario separado para hud y dibuje después de las cosas del juego.
Matsemann

3
Gracias. Probaré los dos. No me di cuenta de que era una práctica común tener más de un escenario o cámara por pantalla.
Devin Carless

44
¿Puedes agregar algún código de muestra o tal vez @DevinCarless?
ashes999

6

Aquí hay un método que uso para trabajar con un solo lote:

Primero dibuja todo lo demás, luego dibuja tu HUD al final:

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

Si desea dibujar más después, asegúrese de restablecer la matriz de proyección a lo que sea necesario.


Tenga en cuenta que terminará con muchas matrices en la memoria muy rápidamente (porque .cpu()crea una nueva matriz cada vez). Mejor tener una matriz de búfer permanente y establecer sus valores en cada cuadro.
Denis Kniazhev

1

Recuerde, la primera cámara es donde se fija el fondo. El segundo es donde se mueve el suelo. Si te preguntas por qué el sprite se mueve en el escenario porque el secreto es el suelo que se mueve. El sprite está caminando en su lugar ya que estás usando una tercera cámara. Puede desplazarse por el suelo de la segunda cámara, pero el HUD todavía está en su lugar en la tercera. ¡Promesa, es verdad! La tercera cámara es donde muestra el sprite en el centro para la dirección, ya sea que vaya hacia la izquierda o hacia la derecha con un pequeño código de animación, y el HUD (es decir, puntuación, vidas restantes, elemento utilizado). Si necesitas algo, pregúntame.


¿Cómo puedo separar el sprite de la segunda cámara? Lo que quiero hacer es dibujar texto, pero es demasiado grande ... Necesito otra cámara, pero cuando hago eso, el texto va conmigo ... con el reproductor, con mi pantalla ... se mueve un poco Al igual que el enemigo en la pantalla, pero todavía está conmigo ... ¿Me puede aconsejar?
Nimitack

1

Lo he hecho así:

Primero, he creado una nueva clase llamada Hud. Se implementa Disposabledebido a la gestión de recursos. Luego debe definir una Stagepara su contenido y una nueva viewportporque se usará una nueva cámara. Debe definir una nueva Tableque pueda agregar a Stage. Puede agregar su contenido a la tableforma habitual. El resto del código que pondré para mostrar cómo funciona es específico del juego, así que simplemente ignórelo.

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;
}

}

y luego en la pantalla de reproducción así:

En primer lugar, necesita una variable para hacer referencia a su hud como:

private Hud hud; 

y luego en el constructor creas una nueva instancia de tu clase:

hud= new Hud(); 

en el método de actualización, debe poner estas líneas de código, ya que creo que desea mostrar información del juego, como puntos o las vidas restantes:

hud.update();

en el método de render haga esto:

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

y al final no olvides deshacerte de tu hud en el método de eliminación

Espero que eso ayude

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.