libGDXでさまざまなアスペクト比を処理する方法は?


81

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

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

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

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

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


同じ問題が発生したブログやフォーラムにリンクしていただけますか?
スティーブブラックウェル

@SteveBlackwellここにリンクがあります:java-gaming.org/index.php
topic =

@SteveBlackwell更新された質問を参照して、これについて支援できるかどうかを確認してください。
ラファイ2012

1
ステージについてはよくわかりませんが、ここを見ると修正されているはずです。ドキュメントは、センタリングのためにあまりにも多くの助けではありません。たぶん、カメラを少し動かしたり、ビューポートを調整したりできます。
スティーブブラックウェル

1
さて私の問題は実際に解決されました。答えとして投稿しています。
ラファイ2012

回答:


51

今日それを行う方法:

これはここでlibgdxに関する最も有名な質問の1つなので、少し更新します。

Viewportこの問題を処理するために導入されたLibGDXv1.0 。はるかに使いやすく、スケーリング戦略はプラグイン可能です。つまり、1行で動作を変更でき、それを試して、どれがゲームに最適かを確認できます。

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


私はそれを試しましたが、それでも私のTextureRegion筋。reszie(int width, int height)関数を空のままにした場合。TextureRegionstrectchしません。
ムハンマドババール2014

しかし、ビューポートを使用する場合でも、アスペクト比ごとに別々のテクスチャを使用する必要がありますね。その方法を単純化するロジックはありますか?それとも、グラフィックデザインは、解像度に依存しないようにして行う必要がありますか?
WeirdElfB0y 2016年

ビューポートを使用しての良いチュートリアル:gamefromscratch.com/post/2014/12/09/...
ubzack

この回答に加えて、コメントの質問に回答することで、16:9の世界を描き、4:3で読み込むことができるように、テクスチャの高さを増やすことができます。次に、ビューポートをインスタンス化するときに、画面の実際のアスペクト比を確認できます。幅の標準を維持しながら、実行しているアスペクト比に合う高さをビューポートに指定できます。欠点は、4:3の解像度で多くの「空の」スペースがあることですが、テクスチャでそれを処理できる場合は、すべてが描画され、引き伸ばされていないように表示されます
Klitos G. 2016

24

編集: libGDXは進化しました。最良の答えは、これがユーザーによるものではありません。Viewportドキュメントへのリンクを必ず確認してください

SteveBlackがステージクラスで報告された問題のリンクを投稿したとき、私はそこに行って、問題(実際には私の問題ではなかった)が最近の夜に解決されたことを発見しました。

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

これは1行のコードであり、実行する必要があるのは次のとおりです。

resize()メソッドで:

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

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

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


6
libGDX 0.9.6では、stage.setViewport(640、480、false)で十分です。これには、stage.getCamera()。position.set(640 / 2、480 / 2、0);への呼び出しがすでに含まれているためです。
Alexis Pautrot 2012

1
setViewport3つのパラメータは現在利用できません!
ムハンマドババール2014

受け入れられた回答を、Steve Blackwellが指摘したように、ユーザーnooneによって投稿されたものに変更しました。これは、最新で正しいもののようです。
ラファイ2014年

7

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

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

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


「いずれにせよ、アプリをネイティブのサイズ変更可能なウィンドウとして実行する方が、多数のAVDを作成するよりもはるかに簡単に複数の画面サイズをテストできます。」よく言われます。実際、私はこの現象に取り組み、さまざまなサイズのテクスチャでさまざまな画面サイズをターゲットにするのではなく、最大限の互換性を確保しようとしています。
ラファイ2012


3

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


0

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

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


これは、カメラの投影解除方法に似ているようです。それは同じことをしますか?
milosmns 2014

@milosmnsこれは私が1年前のようにやっていた方法です、良い私はプロジェクト外のことを見つけました..あなたのカメラが常に同じ位置にあるときは良いです
..– Boldijar Paul 2014

0

このコードは最新のアップデートで機能します:* 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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.