2012-02-08 16 views
76

Ho implementato alcune schermate usando libGDX che ovviamente utilizza la classe Screen fornita dal framework libGDX. Tuttavia, l'implementazione per queste schermate funziona solo con dimensioni dello schermo predefinite. Ad esempio, se lo sprite era pensato per uno schermo di dimensioni 640 x 480 (rapporto di aspetto 4: 3), non funzionerà come previsto su altre dimensioni dello schermo perché gli sprite vanno al di fuori dei limiti dello schermo e non vengono ridimensionati in base alle dimensioni dello schermo affatto. Inoltre, se il libgDX fornisse un semplice ridimensionamento, il problema che sto affrontando sarebbe stato ancora presente perché ciò avrebbe comportato la modifica delle proporzioni della schermata di gioco.Come gestire le diverse proporzioni in libGDX?

Dopo aver effettuato ricerche su Internet, mi sono imbattuto in uno blog/forum che aveva discusso lo stesso problema. L'ho implementato e finora funziona bene. Ma voglio confermare se questa è l'opzione migliore per raggiungere questo obiettivo o se esistono alternative migliori. Di seguito è riportato il codice per mostrare come sto affrontando questo problema legittimo.

FORUM LINK: 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: ho recentemente venuto a sapere che libGDX ha alcune delle propria funzionalità per mantenere rapporti di aspetto che vorrei discutere qui. Durante la ricerca del problema delle proporzioni su Internet, mi sono imbattuto in diversi forum/sviluppatori che avevano questo problema di "Come mantenere le proporzioni su schermi di dimensioni diverse?" Una delle soluzioni che ha funzionato davvero per me è stata pubblicata qui sopra.

Più tardi, quando ho proceduto con l'attuazione delle touchDown() metodi per lo schermo, ho scoperto che a causa di ridimensionamento sul ridimensionamento, le coordinate su cui avevo attuate touchDown() cambierebbero da una grande quantità. Dopo aver lavorato con un po 'di codice per tradurre le coordinate in base al ridimensionamento dello schermo, ho ridotto questa quantità in gran parte, ma non sono riuscito a mantenerle con precisione puntuale. Ad esempio, se avessi implementato touchDown() su una trama, il ridimensionamento dello schermo avrebbe spostato il touchListener nella regione della texture di alcuni pixel a destra oa sinistra, a seconda del ridimensionamento e questo era ovviamente indesiderato.

In seguito sono venuto a sapere che la classe stage ha la propria funzionalità nativa per mantenere le proporzioni (boolean stretch = false). Ora che ho implementato il mio schermo usando la stage class, le proporzioni sono mantenute bene da esso. Tuttavia su ridimensionamento o dimensioni dello schermo diverse, l'area nera che viene generata appare sempre sul lato destro dello schermo; quello è lo schermo non è centrato che lo rende piuttosto brutto se l'area nera è sostanzialmente grande.

Può qualche membro della comunità aiutarmi a risolvere questo problema?

+0

Puoi collegarti al blog o al forum che ha lo stesso problema? –

+0

@SteveBlackwell ecco il link: http://www.java-gaming.org/index.php?topic=25685.new – Rafay

+0

@SteveBlackwell Si prega di consultare la domanda aggiornata e vedere se è possibile aiutare su questo. – Rafay

risposta

50

Come fare al giorno d'oggi:

Dal momento che questo è uno dei più famosi domande sul libgdx qui, darò un po 'aggiornamento:

LibGDX v1.0 introdotto Viewport da gestire questo problema. È molto più facile da usare e la strategia di ridimensionamento è inseribile, il che significa che una singola riga può cambiare il comportamento e puoi giocarci e vedere quale si adatta al tuo gioco.

Tutto ciò che devi sapere su di esso può essere trovato here.

+0

L'ho provato, ma ancora i miei Strati 'TextureRegion'. Se si lascia vuota la funzione 'reszie (int width, int height)' La 'TextureRegion' non si piega. –

+0

Ma anche quando utilizziamo Viewports dobbiamo usare trame separate per differenti proporzioni, no? C'è una logica per semplificare questo metodo? O la progettazione grafica dovrebbe essere eseguita mantenendola indipendente dalle risoluzioni? – WeirdElfB0y

+0

Buon tutorial sull'uso di Viewports: http://www.gamefromscratch.com/post/2014/12/09/LibGDX-Tutorial-Part-17-Viewports.aspx – ubzack

7

Le barre nere a sinistra/a destra o in alto/in basso sembrano più che distorcere l'intera scena per adattarla allo schermo. Se scegli come target un rapporto tra gli intervalli possibili (4: 3 è probabilmente di fascia bassa, 16: 9 è probabilmente di fascia alta), quindi le barre dovrebbero rimanere piccole per la maggior parte dei dispositivi. Questo ti permette di usare anche più dello schermo anche su schermi più grandi, e hai già il codice di quel ragazzo, quindi è abbastanza facile. Sarebbe ancora più bello se questa fosse solo un'opzione integrata in libgdx.

Ma, penso che l'approccio migliore sia utilizzare l'intero schermo. Non l'ho ancora fatto, ma sarà l'approccio che prendo per il mio prossimo progetto. L'idea è che se qualcuno ha uno schermo più ampio, dovrebbe vedere di più sui lati. Chris Pruett parla di come farlo in uno dei suoi discorsi (link to spot in talk - in realtà, il tutto è in realtà piuttosto buono). L'idea è di ridimensionare l'altezza e quindi impostare il viewport abbastanza largo per adattarlo allo schermo. OpenGL dovrebbe occuparsi di visualizzare il resto.Il modo in cui lo fa è here.

Per libgdx, forse c'è un modo semplice per farlo con scene2d spostando la telecamera sul palco, ma in realtà non ho mai lavorato con scene2d. In ogni caso, l'esecuzione dell'app come una finestra ridimensionabile nativa è un modo molto più semplice per testare più dimensioni dello schermo rispetto alla creazione di un gruppo di AVD.

+0

"In qualsiasi caso, far funzionare l'app come una finestra ridimensionabile nativa è un modo molto più semplice per testare più dimensioni dello schermo rispetto alla creazione di un gruppo di AVD. "Ben detto, in realtà sto provando a lavorare su questo fenomeno per garantire la massima compatibilità invece di indirizzare schermi di dimensioni diverse con diverse dimensioni delle trame – Rafay

3

La classe ResolutionFileResolver consente di risolvere i nomi dei file alla migliore risoluzione. Credo che funzionerà anche con differenti proporzioni, a patto di aver creato degli sprite per quei rapporti d'aspetto. C'è un esempio di utilizzo nello AssetManagerTest.

24

MODIFICA: libGDX si è evoluto. La migliore risposta è ora this one dall'utente noone. Assicurati di controllare il link allo Viewport documentation..

Come SteveBlack ha pubblicato il collegamento del problema riportato nella lezione di teatro, sono andato lì solo per scoprire che il problema (che in realtà non era il mio problema) è stato risolto nelle ultime serate notturne.

Dopo aver cercato qua e là su Internet per il problema che stavo avendo, non sono riuscito a trovare nessuna soluzione, quindi ho deciso di contattare direttamente la persona che ha segnalato il bug. Dopo di ciò, mi ha risposto sui forum di libgdx e sono in debito con lui per il suo aiuto. Here is the link

E 'stata una sola riga di codice e tutto quello che dovete fare è:

Nel ridimensionamento() methond:

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

Dove 640 X 480 è la risoluzione del vostro TextureRegion che descrive lo aspect ratio desiderato. Se la tua dimensione TextureRegion era 320 X 240, allora entrambi gli argomenti dovrebbero essere cambiati nella nuova risoluzione per fare il trucco.

Profile link of the original person who actually resolved my issue

+6

In libGDX 0.9.6, cervo e.setViewport (640, 480, false) è sufficiente in quanto include già una chiamata a stage.getCamera() .position.set (640/2, 480/2, 0); –

+0

non funziona !!! –

+1

'setViewport' con 3 parametri non è ora disponibile! –

0

sto usando quel metodo da http://blog.acamara.es/2012/02/05/keep-screen-aspect-ratio-with-different-resolutions-using-libgdx/

ho fatto questa funzione che restituisce il punto sulla schermo toccato, ridimensionato alla posizione di gioco che si desidera.

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

Utilizzare questo nel touchdown/su/trascinare e è possibile verificare la presenza di tocco nel gioco.

+0

Questo sembra simile al metodo non project della fotocamera. Fa la stessa cosa? – milosmns

+0

@milosmns questo è il modo in cui stavo facendo come 1 anno fa, buono ho scoperto la cosa non proiettata .. è buono quando la tua fotocamera è sempre nella stessa posizione .. –

0

Questo codice funziona per me con l'ultimo aggiornamento: * OrthographicCamera è cam, questo non ha ritaglio, cambia solo la finestra in modo che la larghezza è ancora "che molte" volte superiore rispetto a quella reale della finestra/dispositivo

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