Я реализовал несколько экранов с использованием libGDX, которые, очевидно, будут использовать Screen
класс, предоставляемый фреймворком libGDX. Однако реализация для этих экранов работает только с предварительно определенными размерами экрана. Например, если спрайт был предназначен для экрана размером 640 x 480 (соотношение сторон 4: 3), он не будет работать должным образом на других размерах экрана, потому что спрайты выходят за границы экрана и не масштабируются до размера экрана. вообще. Более того, если бы libGDX обеспечивал простое масштабирование, проблема, с которой я столкнулся, все еще существовала бы, потому что это привело бы к изменению соотношения сторон экрана игры.
После исследования в Интернете я наткнулся на блог / форум, в котором обсуждалась та же проблема. Я реализовал его, и пока он работает нормально. Но я хочу подтвердить, является ли это лучшим вариантом для достижения этой цели или есть альтернативы получше. Ниже приведен код, показывающий, как я справляюсь с этой законной проблемой.
ССЫЛКА НА ФОРУМ: 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 в области текстуры на несколько пикселей вправо или влево, в зависимости от изменения размера, а это, очевидно, было нежелательно.
Позже я узнал, что у класса stage есть собственная встроенная функция для поддержания соотношения сторон ( boolean stretch = false
). Теперь, когда я реализовал свой экран с помощью класса stage, он хорошо поддерживает соотношение сторон. Однако при изменении размера или других размерах экрана создаваемая черная область всегда появляется в правой части экрана; то есть экран не отцентрован, что делает его довольно уродливым, если черная область существенно большая.
Может ли кто-нибудь из членов сообщества помочь мне решить эту проблему?
Ответы:
Как это сделать сейчас:
Поскольку это один из самых известных вопросов по libgdx, я дам ему небольшое обновление :
LibGDX v1.0 представлен
Viewport
для решения этой проблемы. Его намного проще использовать, а стратегию масштабирования можно подключить, что означает, что одна строка может изменить поведение, и вы можете поиграть с ней и посмотреть, какая из них лучше всего подходит для вашей игры.Все, что вам нужно знать об этом, можно найти здесь .
источник
TextureRegion
растяжки. Если оставитьreszie(int width, int height)
функцию пустой. НЕTextureRegion
растягивается.РЕДАКТИРОВАТЬ: libGDX эволюционировала. Лучший ответ сейчас - это никто из пользователей. Обязательно проверьте ссылку на
Viewport
документацию. .Когда SteveBlack разместил ссылку на проблему, о которой сообщалось в классе stage, я пошел туда, чтобы обнаружить, что проблема (которая на самом деле не была моей проблемой) была решена в последних выпусках.
Изучив кое-где в Интернете возникшую у меня проблему, я не смог найти никаких решений, поэтому решил связаться с человеком, который напрямую сообщил об ошибке. После этого он ответил мне на форумах libgdx, и я в долгу перед ним за то, что он мне помог. Ссылка здесь
Это была одна строка кода, и все, что вам нужно было сделать, это:
В методе resize ():
stage.setViewport(640, 480, false); stage.getCamera().position.set(640/2, 480/2, 0);
Где 640 X 480 - это разрешение вашего TextureRegion, которое описывает предполагаемое соотношение сторон. Если ваш размер TextureRegion был 320 X 240, тогда оба аргумента должны быть изменены на новое разрешение, чтобы добиться цели.
Ссылка на профиль исходного человека, который действительно решил мою проблему
источник
setViewport
с 3 параметрами сейчас недоступны!Черные полосы слева / справа или сверху / снизу выглядят лучше, чем просто искажение всей сцены под размер экрана. Если вы нацеливаетесь на соотношение сторон, которое находится в середине возможных диапазонов (4: 3, вероятно, нижний предел, 16: 9, вероятно, высокий предел), тогда полосы должны оставаться небольшими для большинства устройств. Это также позволяет вам использовать большую часть экрана даже на больших экранах, и у вас уже есть код этого парня, так что это довольно просто. Было бы еще лучше, если бы это была просто опция, встроенная в libgdx.
Но я считаю, что лучше всего использовать весь экран. Я еще этого не делал, но это будет подход, который я выберу в своем следующем проекте. Идея в том, что если у кого-то экран шире, он должен видеть больше по бокам. Крис Пруэтт рассказывает о том, как это сделать, в одном из своих выступлений ( ссылка на место в разговоре - на самом деле, все это на самом деле довольно хорошо). Идея состоит в том, чтобы масштабировать по высоте, а затем установить достаточно широкое окно просмотра, чтобы соответствовать экрану. OpenGL должен позаботиться об отображении всего остального. То , как он делает это здесь .
Для libgdx, возможно, есть простой способ сделать это с помощью scene2d, перемещая камеру по сцене, но я никогда не работал с scene2d. В любом случае запуск приложения как собственного окна с изменяемым размером - гораздо более простой способ протестировать несколько размеров экрана, чем создание группы AVD.
источник
См. Последнюю часть раздела Viewport в официальных документах: https://code.google.com/p/libgdx/wiki/scene2d#Viewport
источник
Класс ResolutionFileResolver позволяет разрешать имена файлов с наилучшим разрешением. Я считаю, что это также будет работать с разными пропорциями, если вы создали спрайты для этих соотношений сторон. В AssetManagerTest есть пример использования .
источник
Я использую этот метод из 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); }
Используйте это при касании / подъеме / перетаскивании, и вы можете проверить касание в своей игре.
источник
Этот код работает для меня с последним обновлением: * 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); }
источник