web-dev-qa-db-ja.com

libGDXで異なるアスペクト比に対処する方法は?

LibGDXフレームワークによって提供されるScreenクラスを明らかに使用するlibGDXを使用していくつかの画面を実装しました。ただし、これらの画面の実装は、事前定義された画面サイズでのみ機能します。たとえば、スプライトが640 x 480サイズの画面(アスペクト比4:3)向けである場合、スプライトは画面の境界に合わせられ、画面サイズに合わせてスケーリングされないため、他の画面サイズで意図したとおりに動作しません。まったく。さらに、libGDXによって単純なスケーリングが提供されていた場合、ゲーム画面のアスペクト比が変化するため、私が直面している問題は依然として存在していました。

インターネットで調査した後、同じ問題を議論していた blog/forum に出会いました。私はそれを実装しましたが、今のところうまく機能しています。しかし、私はこれがこれを達成するための最良の選択肢であるかどうか、またはより良い代替案があるかどうかを確認したいと思います。以下は、この合法的な問題にどのように対処しているかを示すコードです。

フォーラムリンク: 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:libGDXには、ここで説明したいアスペクト比を維持するための独自の機能があることを最近知りました。インターネットでアスペクト比の問題を検索しているときに、「さまざまな画面サイズでアスペクト比を維持する方法」というこの問題を抱えているいくつかのフォーラム/開発者に出会いました。本当に役立った解決策の1つが上に投稿されました。

後で画面のtouchDown()メソッドの実装を進めたときに、サイズ変更のスケーリングにより、touchDown()を実装した座標が大きく変化することがわかりました。量。画面のサイズ変更に応じて座標を変換するためにいくつかのコードを操作した後、この量を大幅に削減しましたが、ピンポイントの精度でそれらを維持することに成功しませんでした。たとえば、テクスチャにtouchDown()を実装した場合、画面のサイズを変更すると、テクスチャ領域のtouchListenerがサイズ変更に応じて左右に数ピクセル移動し、これは明らかに望ましくありませんでした。

後で、アスペクト比(_boolean stretch = false_)を維持するための独自のネイティブ機能がステージクラスにあることを知りました。ステージクラスを使用して画面を実装したので、アスペクトクラスはそれによって適切に維持されます。ただし、サイズ変更または異なる画面サイズでは、生成される黒い領域は常に画面の右側に表示されます。つまり、画面が中央に配置されないため、黒い領域がかなり大きい場合、画面が非常にくなります。

コミュニティのメンバーがこの問題を解決するのを手伝ってくれますか?

79
Rafay

最近の方法:

これはlibgdxに関する最も有名な質問の1つであるため、少しupdateで説明します。

LibGDX v1.0は、この問題を処理するためにViewportを導入しました。それははるかに使いやすく、スケーリング戦略はプラガブルです。つまり、1行で動作を変更でき、それを使ってゲームに最適なものを確認できます。

あなたがそれについて知る必要があるものはすべて見つけることができます ここ

50
noone

EDIT:libGDXが進化しました。現在、最良の答えは this one by user nooneです。 Viewport documentation。 へのリンクを必ず確認してください。

SteveBlackがステージクラスで報告された問題のリンクを投稿したので、最新のナイトリーで問題(実際には私の問題ではない)が解決されたことを発見するためにそこに行きました。

私が抱えていた問題についてインターネット上であちこち調査した後、解決策が見つからなかったため、バグを直接報告した人に連絡することにしました。その後、彼はlibgdxフォーラムで私に返事をくれました。彼が私を助けてくれたことに感謝しています。 リンクはこちら

それは1行のコードであり、あなたがしなければならないことはすべてです:

Resize()メソッドで:

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

ここで、640 X 480は、目的のアスペクト比を記述するTextureRegionの解像度です。 TextureRegionのサイズが320 X 240の場合、両方の引数を新しい解像度に変更してトリックを行う必要があります。

私の問題を実際に解決した元の人のプロフィールリンク

24
Rafay

左/右または上/下の黒いバーは、画面全体に合わせてシーン全体を歪めるよりもよく見えます。可能な範囲の中央にあるアスペクト比(4:3はおそらくローエンド、16:9はおそらくハイエンド)をターゲットにすると、ほとんどのデバイスでバーは小さくなります。これにより、大きな画面でも画面のmostを使用することができます。また、その人のコードは既にあるので、とても簡単です。これがlibgdxに組み込まれた単なるオプションである場合はさらに良いでしょう。

しかし、最善のアプローチは画面全体を使用することだと思います。私はまだこれをしていませんが、それは私の次のプロジェクトのために取るアプローチになります。アイデアは、誰かがより広い画面を持っているなら、彼らは側でもっと見るべきだということです。クリス・プルエットは、彼の講演の1つでこれを行う方法について語っています( トーク内のスポットへのリンク -実際、すべてが実際にはかなり良いです)。アイデアは、高さに合わせて拡大縮小し、画面に合わせてビューポートを十分に広く設定することです。 OpenGLは残りを表示する必要があります。彼のやり方は ここ です。

Libgdxの場合、ステージ上でカメラを動かすことでscene2dでこれを行う簡単な方法があるかもしれませんが、scene2dで実際に作業したことはありません。いずれにしても、アプリをネイティブのサイズ変更可能なウィンドウとして実行することは、多数のAVDを作成するよりもはるかに簡単に複数の画面サイズをテストする方法です。

7
Steve Blackwell

公式ドキュメントのビューポートセクションの最後の部分を参照してください: https://code.google.com/p/libgdx/wiki/scene2d#Viewport

5
NateS

ResolutionFileResolver クラスを使用すると、ファイル名を最適な解像度に解決できます。これらのアスペクト比のスプライトを作成していれば、異なるアスペクト比でも機能すると思います。 AssetManagerTest には使用例があります。

3
Doran

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

これをタッチダウン/アップ/ドラッグで使用すると、ゲームのタッチを確認できます。

0
Boldijar Paul

このコードは最新のアップデートで機能します。* 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
milosmns