Положение камеры libgdx с использованием области просмотра

Я довольно опытный разработчик libgdx, но некоторое время борюсь с одной проблемой, поэтому решил спросить здесь.

Я использую FillViewport, TiledMap, Scene2d и OrtographicCamera. Я хочу, чтобы камера следовала за моим экземпляром игрока, но есть определенные границы (равные размеру карты). Это означает, что камера никогда не выйдет за пределы карты, поэтому, когда игрок подходит к концу карты, камера перестает следовать за ним, и он уходит к самому краю экрана. Возможно, звучит сложно, но это просто, и я уверен, что вы понимаете, что я имею в виду, это используется в каждой игре.

Я вычислил 4 значения:

minCameraX = camera.viewportWidth / 2;
minCameraY = camera.viewportHeight / 2;
maxCameraX = mapSize.x camera.viewportWidth / 2;
maxCameraY = mapSize.y - camera.viewportHeight / 2;

Я удалил ненужные вещи, такие как преобразование единиц измерения, camera.zoom и т. д. Затем я установил положение камеры следующим образом:

camera.position.set(Math.min(maxCameraX, Math.max(posX, minCameraX)), Math.min(maxCameraY, Math.max(posY, minCameraY)), 0);

(posX, posY — положение игрока), что в основном устанавливает камеру в положение игрока, но если оно слишком высокое или слишком низкое, оно устанавливает его на максимальное или минимальное значение, определенное ранее по правой оси. (Я также пробовал MathUtils.clamp(), и он работает так же.

Все идеально до сих пор. Проблема возникает при изменении соотношения сторон. По умолчанию я использую 1280x768, но на моем телефоне 1280x720. Из-за этого нижний и верхний края экрана обрезаются из-за того, как работает FillViewport. Из-за этого часть моей карты обрезана.

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

Вы можете помочь? Спасибо


person Mateusz Gaweł    schedule 21.11.2016    source источник
comment
в чем именно проблема?: Механизм ограничения камеры больше не работает или проблема в том, что части экрана обрезаются?   -  person noone    schedule 21.11.2016
comment
Второй. Верхний и нижний края обрезаны, поэтому я, например, не вижу конечной рамки карты. Конечно, я знаю, что именно так работает FillViewport, но должна быть возможность изменить границы камеры, чтобы исправить это.   -  person Mateusz Gaweł    schedule 21.11.2016
comment
Я не уверен, что это работает в этом случае, но вы можете попробовать добавить getTopGutterHeight() и getBottomGutterHeight() к своим minCameraY и maxCameraY (или, может быть, наоборот и вычесть вместо добавления?)   -  person noone    schedule 21.11.2016
comment
вечером обязательно попробую. я дам тебе знать   -  person Mateusz Gaweł    schedule 21.11.2016
comment
@noone - разве это не работает только для FitViewport?   -  person m.antkowicz    schedule 21.11.2016
comment
@m.antkowicz: Я думаю, что математически черные полосы (желоба) в FitViewport могут быть такими же, как обрезанные части в Fillviewport. getTopGutterHeight() возвращает Gdx.graphics.getHeight() - (screenY + screenHeight), который представляет собой разницу между высотой области просмотра и фактической высотой устройства = отрезанная часть.   -  person noone    schedule 21.11.2016
comment
Мой совет — никогда не использовать FillViewport. Это создает ситуации, подобные этой, когда вам приходится выполнять утомительные вычисления, чтобы иметь дело с чем-то простым, что вообще сводит на нет всю цель использования диспетчера видового экрана. Используйте ExtendViewport! В 90% случаев это правильный выбор. Это гарантирует, что вам никогда не придется вычислять, может ли что-то, что должно быть видно, быть за кадром.   -  person Tenfour04    schedule 21.11.2016


Ответы (3)


Я попробовал решение noone и Tenfour04 из комментариев выше. Оба не идеальны, но я достаточно удовлетворен, я думаю:

никто:

camera.position.x = MathUtils.clamp(camera.position.x, screenWidth/2 + leftGutter, UnitConverter.toBox2dUnits(mapSize.x) - screenWidth/2 + rightGutter);
camera.position.y = MathUtils.clamp(camera.position.y, screenHeight/2 + bottomGutter, UnitConverter.toBox2dUnits(mapSize.y) - screenHeight/2 - topGutter);

Однако это работало только для небольшого спектра разрешений. Для странных разрешений, где соотношение сторон сильно отличается от стандартного, я видел белые полосы после границы. Это значит, что вся граница была принтером, а какая-то часть мира за границей. я не знаю почему

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

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

Он все еще имеет некоторые ограничения. Поскольку граница является частью мира (плиточные блоки), все в порядке, когда она одного цвета. В случае, если граница имеет разные цвета, рендеринг одного цвета за пределами границ не будет решением.

Спасибо noone и Tenfour04, и я по-прежнему открыт для предложений :)

Вот несколько снимков экрана: https://www.dropbox.com/sh/00h947wkzo73zxa/AAADHehAF4WI8aJ8bu4YzB9Va?dl=0

person Mateusz Gaweł    schedule 21.11.2016
comment
Пока мир по крайней мере такой же большой, как экран, я не уверен, как вы могли бы в конечном итоге видеть за пределами границ, если вы используете зажим камеры, который вы показали в своем вопросе. Что я делаю, так это использую виртуальную ширину и высоту, соответствующие разрешению 4:3, а затем убеждаюсь, что в мире достаточно, чтобы покрыть хотя бы версию 16:9. Например, если ваш виртуальный размер 400x300, то ваш мир должен иметь ширину не менее 534, чтобы вы никогда не видели пустоту. Вы можете добавить дополнительные фрагменты декораций, чтобы обеспечить это на небольших сценах. - person Tenfour04; 21.11.2016
comment
Я добавил несколько скриншотов, чтобы визуализировать проблему - person Mateusz Gaweł; 22.11.2016

Почему бы вам не использовать FitViewport вместо FullViewport? Таким образом, он не отключит ваш экран, верно?

person John    schedule 22.11.2016
comment
и сделать уродливые белые полосы - person Mateusz Gaweł; 22.11.2016

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

Здесь ширина и высота — это размер мира в пикселях. Я использую этот код с FillViewport, и все отлично работает!

float playerX = player.getBody().getPosition().x*PPM;
float playerY = player.getBody().getPosition().y*PPM;

float visibleW =  viewport.getWorldWidth()/2 + (float)viewport.getScreenX()/(float)viewport.getScreenWidth()*viewport.getWorldWidth();//half of world visible
float visibleH = viewport.getWorldHeight()/2 + (float)viewport.getScreenY()/(float)viewport.getScreenHeight()*viewport.getWorldHeight();

float cameraPosx=0;
float cameraPosy=0;

if(playerX<visibleW){
    cameraPosx = visibleW;
}
else if(playerX>width-visibleW){
    cameraPosx = width-visibleW;
}
else{
    cameraPosx = playerX;
}

if(playerY<visibleH){
    cameraPosy = visibleH;
}
else if(playerY>height-visibleH){
    cameraPosy = height-visibleH;
}
else{
    cameraPosy = playerY;
}

camera.position.set(cameraPosx,cameraPosy,0);

camera.update();
person Eugene Mamaenko    schedule 02.05.2017