Как работать с различными соотношениями сторон в libGDX? - PullRequest
79 голосов
/ 08 февраля 2012

Я реализовал некоторые экраны с использованием 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() для текстуры, изменение размера экрана сместит сенсорный список на области текстуры на несколько пикселей вправо или влево, в зависимости от изменения размера, и это, очевидно, нежелательно.

Позже я узнал, что у сценического класса есть собственная встроенная функция для поддержания соотношения сторон (boolean stretch = false). Теперь, когда я реализовал свой экран с помощью сценического класса, соотношение сторон хорошо поддерживается им. Однако при изменении размера или при разных размерах экрана генерируемая черная область всегда появляется в правой части экрана; то есть экран не отцентрирован, что делает его довольно уродливым, если черная область существенно велика.

Может ли какой-нибудь участник сообщества помочь мне решить эту проблему?

Ответы [ 7 ]

50 голосов
/ 18 апреля 2014

Как это сделать сейчас:

Поскольку это один из самых известных вопросов по libgdx, я дам ему обновление :

В LibGDX v1.0 введена Viewport для решения этой проблемы. Его намного проще использовать, а стратегия масштабирования является подключаемой, что означает, что одна строка может изменить поведение, и вы можете поиграть с ней и посмотреть, какая из них лучше всего подходит для вашей игры.

Все, что вам нужно знать об этом, можно найти здесь .

24 голосов
/ 24 февраля 2012

РЕДАКТИРОВАТЬ: libGDX эволюционировал. Лучший ответ теперь этот от пользователя noone. Обязательно проверьте ссылку на документацию 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, то оба аргумента должны быть изменены на новое разрешение, чтобы добиться цели.

Ссылка на профиль оригинального человека, который фактически решил мою проблему

7 голосов
/ 09 февраля 2012

Черные полосы слева / справа или сверху / снизу выглядят лучше, чем просто искажение всей сцены по размеру экрана. Если вы выбираете соотношение сторон, которое находится в середине возможных диапазонов (4: 3, вероятно, нижний предел, 16: 9, вероятно, верхний предел), то столбцы должны оставаться маленькими для большинства устройств. Это также позволяет вам использовать большинство экрана даже на больших экранах, и у вас уже есть код этого парня, так что это довольно просто. Было бы еще лучше, если бы это была опция, встроенная в libgdx.

Но я думаю, что лучший подход - использовать весь экран. Я еще не сделал этого, но это будет подход, который я выберу для своего следующего проекта. Идея состоит в том, что если у кого-то более широкий экран, то он должен видеть больше по бокам. Крис Пруэтт говорит о том, как это сделать, в одном из своих выступлений ( ссылка на место разговора - на самом деле, все на самом деле довольно неплохо). Идея состоит в том, чтобы масштабировать по высоте, а затем установить окно просмотра достаточно широко, чтобы уместить его на экране. OpenGL должен позаботиться о отображении остальных. То, как он это делает, это здесь .

Для libgdx, возможно, есть простой способ сделать это со scene2d, переместив камеру над сценой, но я никогда не работал со scene2d. В любом случае, запуск приложения в виде собственного окна с изменяемыми размерами является гораздо более простым способом тестирования экранов нескольких размеров, чем создание набора AVD.

5 голосов
/ 18 мая 2013

См. Последнюю часть раздела Viewport в официальных документах: https://code.google.com/p/libgdx/wiki/scene2d#Viewport

3 голосов
/ 15 февраля 2012

Класс ResolutionFileResolver позволяет разрешать имена файлов с наилучшим разрешением.Я считаю, что это будет работать и с различными пропорциями, если вы создали спрайты для этих пропорций.В AssetManagerTest .

есть пример использования.
0 голосов
/ 11 августа 2014

Этот код работает для меня с последним обновлением: * OrthographicCamera - cam, он не обрезает, просто изменяет область просмотра, так что ширина все еще "во много раз" больше, чем фактическое окно / устройство

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);
}
0 голосов
/ 16 марта 2014

Я использую этот метод из 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);
}

Используйте это при касании / вверх / перетаскивании, и вы можете проверить наличие прикосновений в своей игре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...