Nice programing

libGDX에서 다른 종횡비를 처리하는 방법은 무엇입니까?

nicepro 2020. 10. 10. 10:57
반응형

libGDX에서 다른 종횡비를 처리하는 방법은 무엇입니까?


ScreenlibGDX 프레임 워크에서 제공 하는 클래스를 분명히 사용하는 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);
        }
    }
}

UPDATE: I recently came to know that libGDX has some of its own functionality to maintain aspect ratios which I would like to discuss here. While searching the aspect ratio issue across the internet, I came across several forums/developers who had this problem of "How to maintain the aspect ratio on different screen sizes?" One of the solutions that really worked for me was posted above.

Later on when I proceeded with implementing the touchDown() methods for the screen, I found that due to scaling on resize, the co-ordinates on which I had implemented touchDown() would change by a great amount. After working with some code to translate the co-ordinates in accordance with the screen resize, I reduced this amount to a great extent but I wasn't successful to maintain them with pin point accuracy. For example, if I had implemented touchDown() on a texture, resizing the screen would shift the touchListener on the texture region some pixels to the right or left, depending on the resize and this was obviously undesired.

Later on I came to know that the stage class has its own native functionality to maintain the aspect ratio (boolean stretch = false). Now that I have implemented my screen by using the stage class, the aspect ratio is maintained well by it. However on resize or different screen sizes, the black area that is generated always appears on the right side of the screen; that is the screen is not centered which makes it quite ugly if the black area is substantially large.

Can any community member help me out to resolve this problem?


How to do it nowadays:

Since this is one of the most famous questions on libgdx here, I'll give it a little update:

LibGDX v1.0 introduced Viewport to handle this problem. It is a lot easier to use and the scaling strategy is pluggable, which means a single line can change the behaviour and you can play with it and see which one fits your game the best.

Everything you need to know about it can be found here.


EDIT: libGDX has evolved. Best answer is now this one by user noone. Be sure to check the link to the Viewport documentation..

As SteveBlack posted the link of the issue that was reported in the stage class, I went there just to discover that the issue (that was not actually my issue) has been resolved in the latest nightlies.

After researching here and there on the internet for the issue I was having, I couldn't find any solutions so decided to contact the person who reported the bug directly. After that, he replied me on libgdx forums and I am indebted to him for his helping me out. Here is the link

It was a single line of code and all you have to do is:

In the resize() methond:

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

Where 640 X 480 is the resolution of your TextureRegion that describes the intended aspect ratio. If your TextureRegion size was 320 X 240, then both the arguments should be changed to the new resolution to do the trick.

Profile link of the original person who actually resolved my issue


Black bars on the left/right or top/bottom look better than just distorting your whole scene to fit the screen. If you target an aspect ratio that's in the middle of the possible ranges (4:3 is probably low end, 16:9 is probably high end), then the bars should stay small for most devices. This also let's you use most of the screen even on bigger screens, and you already have that guy's code so it's pretty easy. It would be even nicer if this was just an option built into libgdx.

But, I think the best approach is to use the whole screen. I haven't done this yet, but it will be the approach I take for my next project. The idea is that if someone has a wider screen, then they should see more on the sides. Chris Pruett talks about how to do this in one of his talks (link to spot in talk--actually, the whole thing is actually pretty good). The idea is to scale for height, and then set your viewport wide enough to fit the screen. OpenGL should take care of displaying the rest. The way he does it is here.

For libgdx, maybe there's an easy way to do this with scene2d by moving the camera over the stage, but I've never actually worked with scene2d. In any case, running the app as a native resizable window is a much easier way to test multiple screen sizes than creating a bunch of AVDs.


See the last part of the Viewport section in the official docs: https://code.google.com/p/libgdx/wiki/scene2d#Viewport


The ResolutionFileResolver class allows you to resolve file names to the best resolution. I believe that will work with different aspect ratios as well, provided you have created sprites for those aspect ratios. There is an example use in the AssetManagerTest.


I'm using that method from http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/

I made this function that returns the point on the screen touched, scaled down to the game position you want.

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

Use this in the touchdown / up/ drag and you can check for touch in your game.


This code works for me with the latest update: * OrthographicCamera is cam, this makes no cropping, just changes the viewport so the width is still "that many" times larger than the actual window/device

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

참고URL : https://stackoverflow.com/questions/9198932/how-to-deal-with-different-aspect-ratios-in-libgdx

반응형