6. diel - Programujeme Android hru - Úvaha nad obrazovkami
Pri tvorbe akejkoľvek appky pre Android narazíme na problém s prispôsobením pre mnoho displejov. Musíme sa vysporiadať s tým, že naša hra bude bežať na zariadeniach s rozdielnym rozlíšením a pomerom obrazovky. Uvažujme tri konkrétne príklady tabletov:
- Prestigio Multipad PMP 5780D s rozlíšením 1024 x 768 pixelov tj. Pomer 4: 3
- Samsung Galaxy Tab SM-T535NYKAXEZ s obrazovkou 1280 x 800 px tj. Pomer 16:10
- Alcatel One Touch Pop7 P310X s 1024 x 600 tj. Takmer pomer 16: 9
Problém nám v libgdx pomáha riešiť trieda OrthographicCamera, vďaka ktorej si v jej inštancii môžeme nastavil virtuálne rozlíšenie, v tejto súvislosti ma napadajú tri možnosti, ako orthocameru nastaviť:
1. Nič neriešiť a jednoducho orthokameře rozkázať svoje rozlíšenie. V tomto vidím veľký nedostatok, ak napríklad na obrazovke sa skutočným pomerom obrazovky 16: 9 nastavím rozlíšenie s pomerom 4: 3, tak sa obrázok neúmerne roztiahne, ak to urobím opačne, tak sa neúmerne zmrští a tiež sa deformuje.
2. Vo virtuálnom rozlíšení využiť jednoducho iba pomer 4: 3, pretože predpokladám, že veľká väčšina displejov je práve minimálne v pomere 4: 3 (Všetky? Patrí sem predsa aj množina 16: 9.). No a zostávajúce pixely, ktoré zostanú navyše nad tento pomer, jednoducho nechať prázdne, či do nich umiestniť reklamu. Nazval by som to "preferovať obrazovky s pomerom 4: 3". Ako výhodu tohto postupu vidím jednoduchosť, ako nevýhodu vidím to, že naše appky nechá na displejoch s pomerom obrazovky väčším ako 4: 3 nevyužité miesto.
3. Ďalšia možnosť by som nazval "preferovať širokouhlé obrazovky" a spočívala by v tom, že obrázok v pomere napr. 16: 9 by som na obrazovke napr. 4: 3 zobrazil tak, že ho celý výrazne zmenším, ale stále bude v pomere 16: 9, avšak dosť zmenšený na to, aby sa zmestil na obrazovku 4: 3. Nevýhodu tohto postupu vidím v tom, že užívatelia s displeji napr. 4: 3 uvidí obrázok dosť zmenšený (prídu o mnoho detailov) a tiež v tom, že bude zostávať nejaké nevyužité miesto. Naopak veľkú výhodu vidím v tom, že sa využijú "širokouhlé" obrazovky v plnej svojej sile a to bude tiež cesta, ktorou sa vydám, pričom čo je "širokouhlé" a čo už nie je, som si stanovil sám a to tak, že obrazovku, ktorá má pomer 1,6 a viac považujem za "širokouhlou" a obrázky na nej nezmenšuje a na obrazovke, ktorá je pod touto hodnotou obrázky zmenšujú. Túto hodnotu som zvolil zámerne, pretože výrobcovia tabletov, sa okolo tohto čísla točí naozaj často a tiež pretože osobne považujem obrazovky s pomerové hodnotou pod 1,6 za akýsi "podstandard". Takže obrazovky 16: 9 nebudú o detaily ochudobnené. Obrazovky 16:10 budú plne využité a to čo je viac a viac pod 16:10 bude viac a viac ochudobnené, avšak stále funkčné.
Už som toho zase napísal dosť, je čas ísť niečo nakódovať. Otvoríme si triedu GameScreen.java z minulého dielu a odstránime v nej všetky premenné, všetko z konstruktoru a všetko tiež vyprázdnime z metódy render (float delta). Pridáme importy (klávesová skratka, aby nám naopak zmizli), takže to máme nejako takto:
package com.wackychicken.screens; import com.badlogic.gdx.Screen; public class GameScreen implements Screen{ public GameScreen(){ } @Override public void show() { // TODO Auto-generated method stub } @Override public void render(float delta) { } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void hide() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } }
Do triedy si pridáme kód pre obsluhu nastavenie obrazovky a celá trieda GameScreen.java tak bude vyzerať nasledovne:
package com.wackychicken.screens; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Screen; import com.badlogic.gdx.math.Vector2; public class GameScreen implements Screen{ private final float SCREENRATIO = 1.6f; private float orthoWidth,orthoHeight; private final Vector2 DEMANDED_SCREEN,SCREEN_BOUND_BEGIN,SCREEN_BOUND_END; public GameScreen(){ DEMANDED_SCREEN=new Vector2(800,500); float w = Gdx.graphics.getWidth(); float h = Gdx.graphics.getHeight(); if(w/h>=SCREENRATIO)//je to sirokouhly? { orthoWidth = w * (DEMANDED_SCREEN.y / h); orthoHeight = DEMANDED_SCREEN.y; SCREEN_BOUND_BEGIN=new Vector2( (orthoWidth - DEMANDED_SCREEN.x)/2, 0); SCREEN_BOUND_END=new Vector2(SCREEN_BOUND_BEGIN.cpy().add(DEMANDED_SCREEN)); } else { orthoHeight = h * (DEMANDED_SCREEN.x / w); orthoWidth = DEMANDED_SCREEN.x; SCREEN_BOUND_BEGIN=new Vector2(0, (orthoHeight - DEMANDED_SCREEN.y) / 2); SCREEN_BOUND_END=new Vector2(SCREEN_BOUND_BEGIN.cpy().add(DEMANDED_SCREEN)); } } @Override public void show() { // TODO Auto-generated method stub } @Override public void render(float delta) { } @Override public void resize(int width, int height) { // TODO Auto-generated method stub } @Override public void pause() { // TODO Auto-generated method stub } @Override public void resume() { // TODO Auto-generated method stub } @Override public void hide() { // TODO Auto-generated method stub } @Override public void dispose() { // TODO Auto-generated method stub } }
Uložíme, pridáme importy a skúsime si spustiť, či nám Eclipse nevyhodí chybu. Zatiaľ nebude v okne nič vidieť, zatiaľ nič nevykresľuje. Virtuálne rozlíšenie máme týmto ošetrené a ideme trošku plánovať našej hru viac do tried. Podľa našej dohody vytvorte:
- nový balík com.wackychicken.gameobjects a v ňom triedu Chicken.java
- nový balík com.wackychicken.managers a v ňom triedy AssetManager.java, GameManager.java, InputManager.java, ObjectManager.java
- nový balík com.wackychicken.rendering a v ňom triedu Renderer.java
tu je obrázok pre orientáciu:
Triedy zatiaľ ponecháme prázdne, písať do nich budeme od ďalšieho dielu, dnes si ešte povieme, čo budú mať jednotlivé triedy na starosť, aj keď už je to zrejmé z ich názvov.
- Chicken.java - vytvorí inštanciu nášho hlúpeho kurčaťa
- AssetManager.java - stará sa o naloadování zdrojov do pamäti (obrázky, zvuky)
- GameManager.java - stará sa o enum stav hry (ready, running, game over), počíta skóre
- InputManager.java - obsluhuje udalosti užívateľského vstupu, v našom prípade to bude klik myšou alebo dotyk prstom
- ObjectManager.java - obsluhuje všetky pohyblivé objekty v hre (sliepku a žrádlo)
- Renderer.java - premietačka, vykresľovacích na virtuálne obrazovku
Takmer všetky inštancie týchto tried nám rozhýbe už predtým vytvorená trieda GameScreen.java. To by bolo pre dnešok všetko, nabudúce nadviažeme. Celý zdrojový kód je samozrejme priložený.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 17x (631.92 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java