Mis on HUD?¶
HUD (Head-Up Display) - mängu liides, mis kuvab olulist teavet mängu hetkeolukorra kohta, näiteks tervis, punktid, aeg, tase ja muud andmed. HUD on tavaliselt paigutatud ekraani ülemisse või alumisse ossa ning mängija ei pea selle teabe saamiseks sekkuma.
Näide: Minecraft HUD

Kuidas luua HUD?¶
libGDX kasutab HUD-i loomiseks standardseid komponente, nagu Stage, ViewPort, Table, Label ja muud.
Stage: Kõigi visuaalsete elementide (näitlejate) konteiner. Stage haldab kuvamist ja sisendi töötlemist.
Viewport: Koordinaadistik, mis haldab HUD-i kuvamist ekraanil, arvestades ekraani eraldusvõimet ja mõõtkava. Näiteks võib kasutada FitViewport-i, mis kohandab HUD-i erinevatele ekraanisuurustele.
Table: Mugav viis UI komponentide paigutamiseks ridadesse ja veergudesse. Table joondab elemendid automaatselt ja haldab nende paigutust.
Label: Teksti kuvamiseks (nt taimeri, skoori). Teksti stiili, fonti ja värvi saab seadistada Label.LabelStyle abil.
Samuti võivad kasutada teisi UI komponente, nagu:
ImageButton: Piltidega nuppude loomiseks.
TextButton: Tavaliste tekstinuppude loomiseks.
Koodinäitena vaatame HUD-klassi loomist Mario mängust, kuid veidi muudetud kujul.
public class Hud {
public Stage stage;
private Viewport viewport;
private Integer worldTimer;
private float timeCount;
private static Integer score;
private Label countdownLabel;
private static Label scoreLabel;
private Label timeLabel;
private Label levelLabel;
private Label worldLabel;
Label gamerLabel;
private int minutes;
private float totalTime;
private int seconds;
public Hud(SpriteBatch sb){
// initialize variables
worldTimer = 999;
totalTime = 300f;
timeCount = totalTime;
minutes = (int) (totalTime / 60);
seconds = (int) (totalTime % 60);
score = 0;
// setup the HUD viewport using a new camera seperate from our gamecam
// define our stage using that viewport and our games spritebatch
viewport = new FitViewport(game.vWidth, game.vHeight, new OrthographicCamera());
stage = new Stage(viewport, sb);
// define a table used to organize our hud's labels
Table table = new Table();
// Top-Align table
table.top();
// make the table fill the entire stage
table.setFillParent(true);
// define our 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.GREEN));
scoreLabel =new Label(String.format("%04d", score), new Label.LabelStyle(new BitmapFont(), Color.GREEN));
timeLabel = new Label("TIME", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
levelLabel = new Label("1", new Label.LabelStyle(new BitmapFont(), Color.GREEN));
worldLabel = new Label("LEVEL", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
gamerLabel = new Label("SCORE", new Label.LabelStyle(new BitmapFont(), Color.WHITE));
// add our labels to our table, padding the top, and giving them all equal width with expandX
table.add(gamerLabel).expandX().padTop(20);
table.add(worldLabel).expandX().padTop(20);
table.add(timeLabel).expandX().padTop(20);
// add a second row to our table
table.row();
table.add(scoreLabel).expandX();
table.add(levelLabel).expandX();
table.add(countdownLabel).expandX();
// add our table to the stage
stage.addActor(table);
}
/**
* Updates the HUD with the given delta time.
*
* @param dt The time elapsed since the last frame.
*/
public void update(float dt) {
timeCount -= dt/2;
if (timeCount <= 0) {
timeCount = 0;
minutes = 0;
seconds = 0;
} else {
minutes = (int) (timeCount / 60);
seconds = (int) (timeCount % 60);
countdownLabel.setText(String.format("%02d:%02d", minutes, seconds));
}
}
public void increaseScore(int points) {
score += points;
scoreLabel.setText(String.format("%04d", score));
}
}
Kuvamiseks on vaja HUD lisada põhimänguklassi. Näide, kuidas seda teha saab:
public class PlayScreen implements Screen {
private Hud hud;
private Game game;
public PlayScreen(Game game) {
this.game = game;
// create our game HUD for scores/timers/level info
hud = new Hud(game.batch);
}
public void update(float dt) {
hud.update(dt);
}
@Override
public void render(float delta) {
// separate our update logic from render
update(delta);
// clear the game screen with Black
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
game.batch.setProjectionMatrix(hud.stage.getCamera().combined);
hud.stage.draw();
}
}
Tulemus¶

HUD meie näidismängust¶
Sellel pildil on kujutatud meie näidismängu kasutajaliidest, kus on näha kõik mängijale vajalikud andmed: iga mängija tervis, taimer ning sõnum mängu hetkeseisust.
Kuidas seda saavutada?¶
Loome klassi HUD. Konstruktori sees loome ka Stage'i, et renderdada HUD sisu.
public class Hud {
private static final Integer LABEL_SIZE = 20;
private static final Integer TABLE_PADDING_TOP = 20;
public static final Integer GAME_STATUS_LABEL_PADDING_TOP = 150;
public static final String INITIAL_LIVES_COUNT = String.valueOf(PLAYER_LIVES_COUNT);
private final Stage stage;
private final Integer localPLayerId;
// Initialize HUD labels with placeholder values, which can later be updated as the game state changes
private final Label localPlayerNameLabel = createLabelWithBackground("You", Color.GREEN, LABEL_SIZE);
private final Label timeLabel = createLabelWithBackground("0:00", Color.WHITE, LABEL_SIZE);
private final Label remotePlayerNameLabel = createLabelWithBackground("Enemy", Color.WHITE, LABEL_SIZE);
private final Label localPlayerLivesLabel = createLabelWithBackground(INITIAL_LIVES_COUNT, Color.RED, LABEL_SIZE);
private final Label remotePlayerLivesLabel = createLabelWithBackground(INITIAL_LIVES_COUNT, Color.RED, LABEL_SIZE);
private final Label gameStatusLabel = createLabel("Waiting for other player...", Color.BLACK, LABEL_SIZE);
/**
* Info overlay that contains information about: player names, lives, game status, game time.
*
* @param spriteBatch used for rendering all visual elements. Using the same spritebatch as the Arena (players,
* bullets etc.) helps with scaling and resizing
*/
public Hud(SpriteBatch spriteBatch) {
localPLayerId = ServerConnection.getInstance().getClient().getID();
// The viewport with current hardcoded width and height works decently with most screen/window sizes
// There's no need for additional font re-scaling when adjusting the window size
Viewport viewport = new FitViewport(640, 480, new OrthographicCamera());
// Create a stage to render the HUD content
stage = new Stage(viewport, spriteBatch);
// Create a table to display fields such as lives count
Table table = createHudTable();
table.setDebug(false); // true - outline all table cells, labels with a red line (makes table non-transparent)
stage.addActor(table);
}
}
Kõikide vajalike elementide paigutamiseks loome kujuteldava tabeli, kuhu lisame vajalikud komponendid (Label, Button). Lisame neid ridadena.
private Table createHudTable() {
// For simple tables, using an empty placeholder label is usually the easiest solution to adjust alignment
Label emptyLabel = createLabel("", Color.WHITE, LABEL_SIZE);
Table table = new Table();
table.setFillParent(true); // Fill whole screen
table.top(); // Align the table's content to the top
table.padTop(TABLE_PADDING_TOP);
// First row: player names and time
table.add(localPlayerNameLabel);
table.add(timeLabel);
table.add(remotePlayerNameLabel);
table.row().expandX(); // make the row fill the entire width of the screen
// Second row: player lives
table.add(localPlayerLivesLabel);
table.add(emptyLabel); // empty label as a placeholder for alignment
table.add(remotePlayerLivesLabel);
table.row().expandX();
// Third row: game status message
table.add(gameStatusLabel)
.colspan(3) // Make the label span across all 3 table columns
.padTop(GAME_STATUS_LABEL_PADDING_TOP)
.align(Align.center); // Center-align the label within the table cell
table.row();
return table;
}
Samuti lisame sellele klassile meetodi "render", mis joonistab meie HUD-i.
/**
* Stage, which contains all HUD content, must be re-rendered each frame, even if there are no changes.
*/
public void render() {
stage.draw();
}
Lõpuks peame lisama meetodid kasutajaliidese komponentide (nagu taimer, elud, mängu staatus jne) uuendamiseks.
/**
* Update time, lives and game state (waiting for other players / active / game over).
*
* @param gameStateMessage latest game state received from the server
*/
public void update(GameStateMessage gameStateMessage) {
updateLives(gameStateMessage.getPlayerStates());
updateTime(gameStateMessage.getGameTime());
updateGameStatus(gameStateMessage);
}
private void updateLives(List<PlayerState> players) {
for (PlayerState player : players) {
if (player.getId() == localPLayerId) {
localPlayerLivesLabel.setText(player.getLives());
} else {
remotePlayerLivesLabel.setText(player.getLives());
}
}
}
private void updateTime(int gameTime) {
int minutes = Math.floorDiv(gameTime, 60);
int seconds = gameTime % 60;
timeLabel.setText(minutes + ":" + String.format("%02d", seconds));
}
private void updateGameStatus(GameStateMessage gameState) {
if (gameState.isAllPlayersHaveJoined()) {
gameStatusLabel.setText(""); // Remove "Waiting for other players ..."
}
for (PlayerState player : gameState.getPlayerStates()) {
if (player.getId() == localPLayerId && player.getLives() == 0) {
gameStatusLabel.getStyle().fontColor = Color.RED; // Make displayed game status message red
gameStatusLabel.setText("You lost");
} else if (player.getId() != localPLayerId && player.getLives() == 0) {
gameStatusLabel.getStyle().fontColor = Color.GREEN; // Make displayed game status message green
gameStatusLabel.setText("You won");
}
}
}