LibGDX'te farklı en boy oranlarıyla nasıl başa çıkılır?


81

Açıkçası ScreenlibGDX çerçevesi tarafından sağlanan sınıfı kullanan libGDX kullanarak bazı ekranlar uyguladım . Bununla birlikte, bu ekranlar için uygulama yalnızca önceden tanımlanmış ekran boyutlarıyla çalışır. Örneğin, hareketli grafik 640 x 480 boyutlu bir ekrana (4: 3 En-boy oranı) yönelikse, diğer ekran boyutlarında tasarlandığı gibi çalışmayacaktır çünkü hareketli görüntüler ekran sınırlarını aşar ve ekran boyutuna ölçeklenmez. hiç. Dahası, basit ölçeklendirme libGDX tarafından sağlanmış olsaydı, karşılaştığım sorun hala orada olurdu çünkü bu, oyun ekranının en boy oranının değişmesine neden olur.

İnternette araştırma yaptıktan sonra aynı konuyu tartışan bir blog / forumla karşılaştım. Ben uyguladım ve şu ana kadar iyi çalışıyor. Ancak bunun bunu başarmak için en iyi seçenek olup olmadığını veya daha iyi alternatifler olup olmadığını teyit etmek istiyorum. Bu meşru problemle nasıl başa çıktığımı gösteren kod aşağıdadır.

FORUM BAĞLANTISI: 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);
        }
    }
}

GÜNCELLEME: Yakın zamanda, libGDX'in burada tartışmak istediğim en boy oranlarını korumak için kendi işlevlerinden bazılarına sahip olduğunu öğrendim. İnternette en boy oranı sorununu araştırırken, "Farklı ekran boyutlarında en boy oranı nasıl korunur?" Sorununu yaşayan birkaç forum / geliştirici ile karşılaştım. Benim için gerçekten işe yarayan çözümlerden biri yukarıda yayınlandı.

Daha sonra touchDown()ekran için yöntemleri uygulamaya başladığımda , yeniden boyutlandırmadaki ölçeklendirme nedeniyle, uyguladığım koordinatların touchDown()büyük miktarda değişeceğini gördüm . Koordinatları ekran boyutuna göre çevirmek için bazı kodlarla çalıştıktan sonra, bu miktarı büyük ölçüde azalttım, ancak pin noktası doğruluğu ile tutmayı başaramadım. Örneğin, touchDown()bir doku üzerine uyguladıysam , ekranın yeniden boyutlandırılması, doku bölgesindeki touchListener'ı yeniden boyutlandırmaya bağlı olarak birkaç piksel sağa veya sola kaydırırdı ve bu açıkça istenmeyen bir durumdu.

Daha sonra sahne sınıfının en boy oranını ( boolean stretch = false) korumak için kendi yerel işlevselliğine sahip olduğunu öğrendim . Artık sahne sınıfını kullanarak ekranımı uyguladığıma göre, en boy oranı iyi korunuyor. Ancak yeniden boyutlandırma veya farklı ekran boyutlarında, oluşturulan siyah alan her zaman ekranın sağ tarafında görünür; yani ekran ortalanmamış, bu da siyah alan çok büyükse oldukça çirkin oluyor.

Herhangi bir topluluk üyesi bu sorunu çözmeme yardım edebilir mi?


Aynı sorunun yaşandığı bloga veya foruma bağlantı verebilir misiniz?
Steve Blackwell

@SteveBlackwell işte bağlantı: java-gaming.org/index.php?topic=25685.new
Rafay

@SteveBlackwell Lütfen güncellenmiş soruya bakın ve bu konuda yardım edip edemeyeceğinize bakın.
Rafay

1
Sahne hakkında pek bir şey bilmiyorum, ama buraya bakınca , bunun düzeltilmesi gerekiyor gibi görünüyor. Docs ortalamak için çok fazla yardımcı değildir. Belki kamerayı biraz hareket ettirebilir veya görüntü alanını ayarlayabilirsiniz.
Steve Blackwell

1
Sorunum aslında çözüldü. Cevap olarak gönderiyorum.
Rafay

Yanıtlar:


51

Bugünlerde nasıl yapılır:

Bu, libgdx ile ilgili en ünlü sorulardan biri olduğu için, biraz güncelleme yapacağım :

LibGDX v1.0 Viewportbu sorunu çözmek için tanıtıldı . Kullanımı çok daha kolaydır ve ölçeklendirme stratejisi takılabilirdir, bu da tek bir satırın davranışı değiştirebileceği ve onunla oynayıp hangisinin oyununuza en uygun olduğunu görmeniz anlamına gelir.

Bununla ilgili bilmeniz gereken her şey burada bulunabilir .


Denedim ama hala TextureRegionSokaklarım. reszie(int width, int height)İşlevi boş bırakırsanız . Esneme TextureRegionyapmaz.
Muhammad Babar

Ancak Viewports'u kullanırken bile farklı en boy oranları için ayrı dokular kullanmamız gerekiyor, değil mi? Bu yöntemi basitleştirecek bir mantık var mı? Yoksa grafik tasarım, çözünürlüklerden bağımsız olarak mı yapılmalı?
WeirdElfB0y

Viewports'u kullanma hakkında iyi eğitim: gamefromscratch.com/post/2014/12/09/…
ubzack

Bu yanıta ekleyerek ve yorumlardaki soruları yanıtlayarak, dünyanızı 16: 9 oranında çizebilir ve 4: 3 oranında yükleyebilmek için dokunuza daha fazla yükseklik kazandırabilirsiniz. Ardından, görüntü alanınızı somutlaştırırken, ekranın gerçek en boy oranını kontrol edebilir ve genişlik standardınızı korurken görüntü alanınıza çalıştırdığınız en boy oranına uyacak bir yükseklik verebilirsiniz. 3 çözünürlük, ancak doku o işleyebilir eğer çizilmiş ve gergin değil, her şey gösterecektir: Bir dezavantajı bir 4 çok "boş" alanına sahip olmasıdır
Klitos G.

24

DÜZENLEME: libGDX gelişti. Şimdi en iyi cevap, hiç kimsenin kullanmadığı bir cevaptır . ViewportBelgelerin bağlantısını kontrol ettiğinizden emin olun . .

SteveBlack, sahne dersinde bildirilen sorunun bağlantısını yayınladığında, sadece sorunun (aslında benim sorunum değildi) son gecelerde çözüldüğünü keşfetmek için oraya gittim.

Yaşadığım sorun için internette burada burada araştırma yaptıktan sonra herhangi bir çözüm bulamadım, bu yüzden hatayı bildiren kişiyle doğrudan iletişime geçmeye karar verdim. Bundan sonra libgdx forumlarında bana cevap verdi ve bana yardım ettiği için ona minnettarım. Bağlantı burada

Bu tek bir kod satırıydı ve yapmanız gereken tek şey:

Resize () metodunda:

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

640 X 480, TextureRegion'unuzun amaçlanan en boy oranını tanımlayan çözünürlüğüdür. TextureRegion boyutunuz 320 X 240 ise, hile yapmak için her iki argüman da yeni çözünürlüğe değiştirilmelidir.

Sorunumu gerçekten çözen asıl kişinin profil bağlantısı


6
LibGDX 0.9.6'da, stage.setViewport (640, 480, false) yeterlidir çünkü stage.getCamera () .position.set (640/2, 480/2, 0) için bir çağrı içerir;
Alexis Pautrot

1
setViewport3 parametreli şu anda mevcut değil!
Muhammad Babar

Steve Blackwell'in belirttiği gibi, kabul edilen yanıtı, hiç kimsenin göndermediği yanıtla değiştirdim çünkü en son ve doğru yanıt gibi görünüyor.
Rafay

7

Soldaki / sağdaki veya üstteki / alttaki siyah çubuklar, tüm sahnenizi ekrana sığacak şekilde bozmaktan daha iyi görünür. Olası aralıkların ortasındaki bir en boy oranını hedeflerseniz (4: 3 muhtemelen düşük uçtur, 16: 9 muhtemelen yüksek uçtur), o zaman çubuklar çoğu cihaz için küçük kalmalıdır. Bu aynı zamanda ekranın çoğunu daha büyük ekranlarda bile kullanmanıza izin verir ve bu adamın koduna zaten sahipsiniz, bu yüzden oldukça kolaydır. Bu sadece libgdx'te yerleşik bir seçenek olsaydı daha da güzel olurdu.

Ama bence en iyi yaklaşım tüm ekranı kullanmak. Bunu henüz yapmadım, ancak bir sonraki projem için benimsediğim yaklaşım bu olacak. Buradaki fikir, eğer biri daha geniş bir ekrana sahipse, yanlarda daha fazlasını görmeleri gerektiğidir. Chris Pruett, konuşmalarından birinde bunun nasıl yapılacağından bahsediyor ( konuşmada nokta bağlantısı - aslında her şey aslında oldukça iyi). Buradaki fikir, yüksekliği ölçeklendirmek ve ardından görüntü alanınızı ekrana sığacak kadar geniş ayarlamaktır. OpenGL geri kalanını göstermeye özen göstermelidir. Bunu yapma şekli burada .

Libgdx için, bunu scene2d ile kamerayı sahne üzerinde hareket ettirerek yapmanın kolay bir yolu olabilir, ancak aslında scene2d ile hiç çalışmadım. Her durumda, uygulamayı yerel bir yeniden boyutlandırılabilir pencere olarak çalıştırmak, birden çok ekran boyutunu test etmenin bir grup AVD oluşturmaktan çok daha kolay bir yoludur.


"Her durumda, uygulamayı yerel bir yeniden boyutlandırılabilir pencere olarak çalıştırmak, birden çok ekran boyutunu test etmenin bir grup AVD oluşturmaktan çok daha kolay bir yoludur." İyi söyledin. aslında, farklı doku boyutlarıyla farklı ekran boyutlarını hedeflemek yerine maksimum uyumluluğu sağlamak için bu fenomen üzerinde çalışıyorum.
Rafay


3

ResolutionFileResolver sınıfı en iyi çözünürlüğe dosya adlarını çözümlemek için izin verir. En boy oranları için sprite yaratmanız şartıyla, farklı en boy oranlarında da işe yarayacağına inanıyorum. AssetManagerTest'te bir örnek kullanım vardır .


0

Bu yöntemi http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/ adresinden kullanıyorum.

Ekranda dokunulan noktayı istediğiniz oyun konumuna küçülterek döndüren bu işlevi yaptım.

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

Bunu touchdown / yukarı / sürüklemede kullanın ve oyununuzda dokunuşu kontrol edebilirsiniz.


Bu, kameranın projesiz yöntemine benziyor. Aynı şeyi mi yapıyor?
milosmns

@milosmns 1 yıl önce yaptığım yol buydu, iyi, projesiz şeyi buldum .. kameranız her zaman aynı pozisyondayken
iyidir

0

Bu kod, en son güncellemeyle benim için çalışıyor: * OrthographicCamera kamdır, bu kırpma yapmaz, sadece görüntü alanını değiştirir, böylece genişlik, gerçek pencere / cihazdan "çok" kat daha büyük olur

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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.