Окна просмотра

Когда в libGDX игре вы имеете дело с различными экранами, то часто для определенной стратегии необходимо решить, как будут обрабатываться эти экраны. Camera и Stage поддерживают разные стратегии для окна просмотра, например, когда используется метод Camera.project(vec, viewportX, viewportY, viewportWidth, viewportHeight).

libGDX предоставляет более удобный способ решения этой проблемы, а именно с помощью разных окон просмотров – Viewport.

StretchViewport

StretchViewport поддерживает работу с виртуальным размером экрана. Это означает предположение о том, что размер экрана всегда virtualWidth и virtualHeight. Виртуальное окно просмотра будет всегда растягиваться до размеров экрана. Черных полос не будет, но соотношение сторон может быть не одинаковыми после масштабирования.

FitViewport

FitViewport тоже поддерживает виртуальный размер экрана. В отличие от StretchViewport, будет всегда сохранять соотношение размера виртуального экрана (виртуального окна просмотра), при масштабировании стремится к максимально возможному соответствию экрана. Одним из недостатков такой стратегии является возможное появление черных полос.

FillViewport

FillViewport сохраняет соотношение сторон виртуального размера экрана, но в отличие от FitViewport, будет всегда заполнять весь экран, что в результате может приводить к тому, что некоторые части окна просмотра будет обрезаны.

ScreenViewport

ScreenViewport не имеет постоянного виртуального размера экрана. Окно просмотра всегда будет соответствовать размеру экрана, что означает отсутствие масштабирование и черных полос. Недостатком является возможное изменение игрового процесса, так как игрок с большим экраном может видеть в игре больше, чем игрок с меньшим размером экрана.

ExtendViewport

ExtendViewport сохраняет соотношение сторон игрового мира без черных полос, расширяя мир в одном направлении. Сначала масштабируется мир по размеру окна просмотра, затем короткий размер удлиняется до заполнения окна просмотра.

Максимальное значение размерностей может подаваться в ExtendViewport, в этом случае, черные полосы будут видны, когда соотношение сторон выходит из-за поддерживаемого диапазона.

CustomViewport

Различные стратегии могут быть реализованы с помощью наследования CustomViewport extends Viewport и реализации calculateViewport(width, height) метода. Другой подход заключается в использовании ScalingViewport и применении масштабирования, которого нет в других окнах просмотра. Одним из примеров может быть использование Scaling.none, что приведет к "StaticViewport", которое всегда сохраняет тот же размер. Это может выглядеть следующим образом:

Использование

В libGDX окно просмотра всегда управляет viewportWidth и viewportHeight камеры. Таким образом, камера должна передаваться в конструктор окна просмотра.

private Viewport viewport;
private Camera camera;

public void create() {
    camera = new PerspectiveCamera();
    viewport = new FitViewport(800, 480, camera);
}

Всякий раз, когда в libGDX происходит событие изменения размера, окно просмотра должно быть проинформировано об этом и обновлено. Параметры окна просмотра будут автоматически пересчитаны, а камера обновлена:

public void resize(int width, int height) {
    viewport.update(width, height);
}

Кроме того, изменится окно просмотра OpenGL через glViewport() и будут добавлены черные полосы, если это необходимо, делая невозможным визуализацию в области черных полос. В случае появления черных полос для определенной стратегии, окно просмотра OpenGL может быть установлено в стандартный размер и окно просмотра может запросить размер черных полос с помощью методов Viewport.getLeftGutterWidth() и Viewport.getRightGutterWidth(). Для примера того, как это сделать, смотрите тест. Это может выглядеть следующим образом (с соответствующим приграничным изображением)

Класс Viewport предоставляет удобные project(), unproject() и getPickRay() методы, которые используются текущим окном просмотра для корректного выбора, как вам конвертировать координаты игрового мира и экрана.

Когда используется Stage, его окно просмотра необходимо обновлять при сообщении об изменении размеров.

private Stage stage;

public void create() {
    stage = new Stage(new StretchViewport(width, height));
}

public void resize(int width, int height) {
    // используйте true для центровки камеры
    stage.getViewport().update(width, height, false);
}

Чтобы увидите разные libGDX окна просмотра в действии, посмотрите тесты: ViewportTest1, ViewportTest2 и ViewportTest3.