Как бороться с различными пропорциями в libGDX?
Я реализовал некоторые экраны с помощью libGDX, которые, очевидно, будут использовать класс Screen
, предоставляемый инфраструктурой libGDX. Однако реализация этих экранов работает только с заранее определенными размерами экрана. Например, если спрайт предназначался для экрана размером 640 x 480 (соотношение сторон 4: 3), он не будет работать так, как предполагалось, на других размерах экрана, так как спрайты соответствуют размерам экрана и не масштабируются до размера экрана вообще. Более того, если бы простое масштабирование было предоставлено libGDX, проблема, с которой я столкнулся, все равно была бы там, потому что это изменило бы соотношение сторон экрана игры.
После исследования в Интернете я наткнулся на блог/форум, в котором обсуждалась одна и та же проблема. Я реализовал его, и пока он работает нормально. Но я хочу подтвердить, является ли это наилучшим вариантом для достижения этого или есть ли лучшие альтернативы. Ниже приведен код, показывающий, как я имею дело с этой законной проблемой.
FORUM LINK: http://www.java-gaming.org/index.php?topic=25685.new
public class SplashScreen implements Screen {
// Aspect Ratio maintenance
private static final int VIRTUAL_WIDTH = 640;
private static final int VIRTUAL_HEIGHT = 480;
private static final float ASPECT_RATIO = (float) VIRTUAL_WIDTH / (float) VIRTUAL_HEIGHT;
private Camera camera;
private Rectangle viewport;
// ------end------
MainGame TempMainGame;
public Texture splashScreen;
public TextureRegion splashScreenRegion;
public SpriteBatch splashScreenSprite;
public SplashScreen(MainGame maingame) {
TempMainGame = maingame;
}
@Override
public void dispose() {
splashScreenSprite.dispose();
splashScreen.dispose();
}
@Override
public void render(float arg0) {
//----Aspect Ratio maintenance
// update camera
camera.update();
camera.apply(Gdx.gl10);
// set viewport
Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,
(int) viewport.width, (int) viewport.height);
// clear previous frame
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// DRAW EVERYTHING
//--maintenance end--
splashScreenSprite.begin();
splashScreenSprite.disableBlending();
splashScreenSprite.draw(splashScreenRegion, 0, 0);
splashScreenSprite.end();
}
@Override
public void resize(int width, int height) {
//--Aspect Ratio Maintenance--
// calculate new viewport
float aspectRatio = (float)width/(float)height;
float scale = 1f;
Vector2 crop = new Vector2(0f, 0f);
if(aspectRatio > ASPECT_RATIO) {
scale = (float) height / (float) VIRTUAL_HEIGHT;
crop.x = (width - VIRTUAL_WIDTH * scale) / 2f;
} else if(aspectRatio < ASPECT_RATIO) {
scale = (float) width / (float) VIRTUAL_WIDTH;
crop.y = (height - VIRTUAL_HEIGHT * scale) / 2f;
} else {
scale = (float) width / (float) VIRTUAL_WIDTH;
}
float w = (float) VIRTUAL_WIDTH * scale;
float h = (float) VIRTUAL_HEIGHT * scale;
viewport = new Rectangle(crop.x, crop.y, w, h);
//Maintenance ends here--
}
@Override
public void show() {
camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); //Aspect Ratio Maintenance
splashScreen = new Texture(Gdx.files.internal("images/splashScreen.png"));
splashScreenRegion = new TextureRegion(splashScreen, 0, 0, 640, 480);
splashScreenSprite = new SpriteBatch();
if(Assets.load()) {
this.dispose();
TempMainGame.setScreen(TempMainGame.mainmenu);
}
}
}
ОБНОВЛЕНИЕ: Недавно я узнал, что у libGDX есть свои функции для поддержания пропорций, которые я хотел бы обсудить здесь. Во время поиска вопроса о соотношении сторон в Интернете я столкнулся с несколькими форумами/разработчиками, у которых была эта проблема: "Как сохранить соотношение сторон на разных размерах экрана?" Одно из решений, которые действительно работали для меня, было опубликовано выше.
Позже, когда я продолжил реализацию методов touchDown()
для экрана, я обнаружил, что из-за масштабирования при изменении размера координаты, на которых я реализовал touchDown()
, изменились бы на большую сумму. После работы с некоторым кодом для перевода координат в соответствии с изменением размера экрана я уменьшил эту величину в значительной степени, но мне не удавалось поддерживать их с точными точками. Например, если бы я реализовал touchDown()
на текстуре, изменение размера экрана изменило бы touchListener на области текстуры на несколько пикселей вправо или влево, в зависимости от размера, и это было явно нежелательно.
Позже я узнал, что у сценического класса есть своя собственная функциональность, поддерживающая соотношение сторон (boolean stretch = false
). Теперь, когда я реализовал свой экран, используя класс сцены, соотношение сторон поддерживает его. Однако при изменении размера или разных размерах экрана, черная область, которая генерируется, всегда появляется в правой части экрана; то есть экран не центрирован, что делает его довольно уродливым, если черная область существенно большая.
Может ли кто-нибудь из членов сообщества помочь мне решить эту проблему?
Ответы
Ответ 1
Как это сделать в настоящее время:
Так как это один из самых известных вопросов в libgdx, я дам ему немного update:
LibGDX v1.0 представил Viewport
для решения этой проблемы. Это намного проще в использовании, и стратегия масштабирования подключается, что означает, что одна строка может изменить поведение, и вы можете играть с ней и посмотреть, какая из них подходит вашей игре.
Все, что вам нужно знать об этом, можно найти здесь.
Ответ 2
EDIT: развивается libGDX. Лучший ответ теперь этот пользователем. Обязательно проверьте ссылку на Viewport
документация..
Поскольку SteveBlack опубликовал ссылку на проблему, о которой сообщалось в классе сцены, я отправился туда, чтобы узнать, что проблема (на самом деле это не моя проблема) была решена в последние ночные часы.
После изучения здесь и там в Интернете по проблеме, которую я имел, я не мог найти решения, поэтому решил связаться с человеком, который сообщил об ошибке напрямую. После этого он ответил мне на форумах libgdx, и я обязан ему за то, что он помог мне. Вот ссылка
Это была единственная строка кода, и все, что вам нужно сделать, это:
В параметре resize():
stage.setViewport(640, 480, false);
stage.getCamera().position.set(640/2, 480/2, 0);
Где 640 X 480 - это разрешение вашего TextureRegion, которое описывает предполагаемое соотношение сторон. Если ваш размер TextureRegion был 320 X 240, то оба аргумента должны быть изменены на новое разрешение, чтобы сделать трюк.
Ссылка профиля оригинального человека, который действительно разрешил мою проблему
Ответ 3
Черные полосы слева/справа или сверху/снизу выглядят лучше, чем просто искажать всю сцену в соответствии с экраном. Если вы нацеливаете соотношение сторон, которое в середине возможных диапазонов (возможно, 4: 3, вероятно, с низким уровнем, 16: 9, вероятно, с высоким уровнем), тогда бары должны оставаться малыми для большинства устройств. Это также позволяет использовать большую часть экрана даже на больших экранах, и у вас уже есть код этого парня, так что это довольно легко. Было бы даже лучше, если бы это был просто вариант, встроенный в libgdx.
Но, я думаю, лучший подход - использовать весь экран. Я еще этого не делал, но это будет тот подход, который я приму для своего следующего проекта. Идея состоит в том, что если кто-то имеет более широкий экран, то они должны видеть больше по сторонам. Крис Пруетт рассказывает о том, как это сделать в одном из своих разговоров (ссылка на то, что вы говорите - фактически все это на самом деле довольно хорошо), Идея заключается в масштабировании по высоте, а затем установите свой видовой экран достаточно широко, чтобы соответствовать экрану. OpenGL должен позаботиться о отображении остальных. То, как он это делает, здесь.
Для libgdx, может быть, есть простой способ сделать это с помощью scene2d, перемещая камеру по сцене, но я никогда не работал с scene2d. В любом случае запуск приложения в качестве собственного изменяемого размера окна - это гораздо более простой способ протестировать несколько размеров экрана, чем создавать кучу AVD.
Ответ 4
См. последнюю часть раздела "Вид" в официальных документах:
https://code.google.com/p/libgdx/wiki/scene2d#Viewport
Ответ 5
Класс ResolutionFileResolver позволяет вам разрешать имена файлов с лучшим разрешением. Я считаю, что будет работать и с другими пропорциями, если вы создали спрайты для этих пропорций. Существует пример использования AssetManagerTest.
Ответ 6
Я использую этот метод из http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/
Я сделал эту функцию, которая возвращает точку на экране, касающуюся, уменьшенную до нужной позиции игры.
public Vector2 getScaledPos(float x, float y) {
float yR = viewport.height / (y - viewport.y);
y = CAMERA_HEIGHT / yR;
float xR = viewport.width / (x - viewport.x);
x = CAMERA_WIDTH / xR;
return new Vector2(x, CAMERA_HEIGHT - y);
}
Используйте это при приземлении/вверх/перетаскивании, и вы можете проверить на ощупь в своей игре.
Ответ 7
Этот код работает для меня с последним обновлением:
* OrthographicCamera - это кулачок, это не делает обрезки, просто меняет видовое окно, так что ширина по-прежнему "в много раз больше, чем фактическое окно/устройство
public void resize(int width, int height) {
int newW = width, newH = height;
if (cam.viewportWidth > width) {
float scale = (float) cam.viewportWidth / (float) width;
newW *= scale;
newH *= scale;
}
// true here to flip the Y-axis
cam.setToOrtho(true, newW, newH);
}