Как мне сделать экранный HUD в libgdx?

23

Я новичок в libgdx, и я обнаружил, что меня одолевают самые простые вещи. Кажется, я хочу, чтобы я делал что-то определенным образом, но документация не скажет мне, что это такое.

Я хочу сделать очень простую 2d игру, в которой игрок управляет космическим кораблем. Колесо мыши будет увеличиваться и уменьшаться, а информация и элементы управления отображаются на экране.

Но я не могу заставить колесо мыши НЕ увеличивать пользовательский интерфейс. Я попытался futzing с матрицами проекции между

Вот мой (текущий) код:

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 устанавливается с помощью прокрутки (целое число).

Я пробовал около дюжины вариаций на тему смены матрицы проекции камеры после того, как кнопка нарисована, но до того, как корабль появится, но независимо от того, что я делаю, то же самое происходит и с кнопкой, и с кораблем. Так:

Каков обычный способ libgdx для реализации экранного интерфейса, который не трансформируется матрицей проекции / масштабированием камеры?

Девин Карлесс
источник
Вы можете использовать, camera.project(Vector3 screenCoords)чтобы проецировать что-то от мировых координат до экранных шнуров.
JDSweetBeat

Ответы:

17

Вы можете просто использовать другой SpriteBatch без установки матрицы проекции, чтобы нарисовать 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();
lookx2
источник
1
Для того, что я делал, я обнаружил, что это самый простой подход, для базового пользовательского интерфейса, который всегда должен появляться в одном и том же месте на экране (например, оценки, жизни и т. Д.)
Ричард
Когда я попробовал это, spritebatch без матрицы проекции приводил к разному позиционированию на разных разрешениях экрана
codeulike
8

Я думаю, что самый простой способ создать карту HUD - использовать вторую камеру и наложить их. Эта проблема обсуждалась на форумах libgdx некоторое время назад, и я помню, как кто-то там публиковал свой код hud. Вы можете покопаться там и посмотреть, что вы придумали.

Чак Д
источник
2
Да, это правильный ответ. Или используйте отдельную сцену для игры и рисуйте ее после игры.
Мацеманн
3
Спасибо. Я попробую оба. Я не понимал, что было обычной практикой иметь более одной сцены или камеры на экран.
Девин Карлесс
4
Можете ли вы добавить пример кода, или, может быть, @DevinCarless?
ashes999
6

Вот метод, который я использую для работы с одним пакетом:

Сначала нарисуйте все остальное, затем нарисуйте свой последний HUD:

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

Если вы хотите рисовать больше после, убедитесь, что вы сбросили матрицу проекции до того, каким она должна быть.

talloaktrees
источник
Имейте в виду, что в результате вы получите очень много матриц в памяти очень быстро (потому что .cpu()каждый раз создаете новую матрицу). Лучше иметь постоянную буферную матрицу и устанавливать ее значения в каждом кадре.
Денис Княжев
1

Помните, что на первой камере зафиксирован фон. Второй - это то, куда движется земля. Если вам интересно, почему спрайт движется на сцене, потому что секрет - это земля, которая движется. Спрайт просто гуляет, так как вы используете третью камеру. Вы могли бы прокручивать землю второй камеры, но HUD все еще на месте на третьей. Обещай, это правда! Третья камера - это место, где отображается спрайт в центре для направления, идет ли он влево или вправо с помощью небольшого анимационного кода, и HUD (т. Е. Счет, оставшиеся жизни, использованный элемент). Если тебе что-то нужно, спроси меня.

Дэвид Дималанта
источник
Как я могу отсоединить спрайт от второй камеры? То, что я хочу сделать, это нарисовать текст, но он слишком большой ... Так что мне нужна другая камера, но когда я это делаю, текст идет со мной ... с плеером, с моим экраном ... он немного сдвигается как враг на экране, но он все еще остается со мной ... Не могли бы вы посоветовать?
Нимитак,
1

Я сделал это так:

Сначала я создал новый класс под названием Hud. Реализуется Disposableиз-за управления ресурсами. Затем вам нужно определить Stageдля вашего контента и новый, viewportпотому что будет использоваться новая камера. Вам нужно определить новый, Tableкоторый вы можете добавить в Stage. Вы можете добавить свой контент, tableкак обычно. Остальная часть кода, который я приведу, чтобы показать, как он работает, зависит от конкретной игры, поэтому просто проигнорируйте его.

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

}

а затем в Playscreen, как это:

Прежде всего вам нужна переменная для ссылки на ваш HUD, как:

private Hud hud; 

а затем в конструкторе вы создаете новый экземпляр вашего класса:

hud= new Hud(); 

в методе обновления вам нужно поместить эти строки кода, так как я думаю, что вы хотите отобразить некоторую информацию об игре, такую ​​как очки или оставшиеся жизни:

hud.update();

в методе рендеринга сделайте это:

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

и, в конце концов, не забудьте избавиться от лишнего в методе утилизации

Надеюсь, это поможет

Bexx
источник