Как справиться с различными соотношениями сторон в libGDX?


я реализовал некоторые экраны с помощью 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, соотношение сторон сохраняется и его. Однако при изменении размера или разных размеров экрана, черная область, которая генерируется, всегда появляется в правой части экрана; то есть экран не центрирован, что делает его довольно уродливым, если черная область существенно велика.

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

7 77

7 ответов:

Как это сделать в наши дни:

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

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

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

EDIT: libGDX эволюционировал. Лучший ответ сейчас этот пользователем noone. Обязательно проверьте ссылку на Viewport документация..

поскольку SteveBlack опубликовал ссылку на проблему, о которой сообщалось в классе stage, я пошел туда, чтобы узнать, что проблема (которая на самом деле не была моей проблемой) была решена в последних nightlies.

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

Это одна строка кода и все, что вам нужно сделать, это:

в resize () methond:

stage.setViewport(640, 480, false);
stage.getCamera().position.set(640/2, 480/2, 0);

где 640 X 480-это разрешение вашего TextureRegion, которое описывает предполагаемое соотношение сторон. Если ваш размер TextureRegion был 320 X 240, то оба аргумента должны быть изменены на новое разрешение, чтобы сделать трюк.

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

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

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

для libgdx, возможно, есть простой способ сделать это с помощью scene2d, перемещая камеру по сцене, но я никогда не работал с scene2d. в любом случае, запуск приложения в качестве собственного изменяемого окна-это гораздо более простой способ проверить несколько размеров экрана, чем создание кучи AVDs.

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

The 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);
}

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

этот код работает для меня с последним обновлением: * 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);
}