Lekce 11 - Programujeme Android hru - Grafika II
V minulé lekci, Programujeme Android hru - Grafika I, jsme na obrazovku promítli slepici a pozadí.
Jak tedy pomocí metody turnChicken(int x,int y) provádíme natáčení kuřete?
Představme si, že máme souřadnicovou soustavu podobnou té kartézské. Úmyslně zdůrazňuji podobnou, protože v naší virtuální obrazovce máme pod osou x na ose y kladné hodnoty. Ostatní parametry naší soustavy již definici kartézské soustavy vyhovují: osy jsou vzájemně kolmé, jednotky na nich mají stejnou velikost (vzdálenost v px), počátek soustavy je v bodě [0,0].
Jak to tedy funguje? Obrázek nám řekne více než mnoho slov:

- Odečtením souřadnic kuřete od souřadnic kliku uživatele posuneme souřadnice kuřete do počátku souřadnicového systému - tedy do bodu [0,0] a o tuto stejnou vzdálenost zároveň posuneme souřadnice kliku uživatele.
- Spočítáme proměnnou rt (zkratka ratio) stejným způsobem jako sinus v pravoúhlém trojúhelníku. Úmyslně jsem proměnnou nepojmenoval sinus, protože tím, že nejsme v kartézské soustavě - máme jinak osu y, by znaménka neodpovídala jednotlivým kvadrantům.
- Dle hodnoty proměnné rt a zároveň dle toho, zda proměnná transformedPositionX je menší nebo větší než nula, určíme úhel a směr rotace slepice.
Pojďme konečně promítat, otevřeme si třídu Renderer.java, kterou máme vyplněnou z 8. dílu tak, že se nám zobrazuje místo slepice žlutý obdélník. Abychom neduplikovali text, třídu rovnou vyplníme do níže uvedeného tvaru a příště si vše vysvětlíme.
public class Renderer { private OrthographicCamera cam; private ShapeRenderer shapeRenderer; private SpriteBatch batcher; private final Vector2 demandedScreen,screenBoundBegin; private final GameScreen gameScreen; private Chicken chicken; private GameManager gameMng; private Texture left1,left2,leftSideDown1,leftSideDown2,leftSideUp1,leftSideUp2,leftUp1,leftUp2,leftDown1,leftDown2; private Texture right1,right2,rightSideDown1,rightSideDown2,rightSideUp1,rightSideUp2,rightUp1,rightUp2,rightDown1,rightDown2; private TextureRegion rBackground; private Animation standLeftAnime,standRightAnime; private int counter; private float runTime; private final int COUNTERBEGIN = 20,COUNTEREND =40, BEGINYCONSTANT; public Renderer(GameManager gameManager, float orthoHeight, float orthoWidth) { this.gameMng=gameManager; this.gameScreen=gameMng.getGameScreen(); this.demandedScreen=gameScreen.DEMANDED_SCREEN; this.screenBoundBegin=gameScreen.SCREEN_BOUND_BEGIN; this.BEGINYCONSTANT=gameMng.getObjectManager().getBEGINYCONSTANT(); this.cam = new OrthographicCamera(); this.cam.setToOrtho(true, orthoWidth,orthoHeight); this.shapeRenderer = new ShapeRenderer(); this.shapeRenderer.setProjectionMatrix(cam.combined); this.batcher = new SpriteBatch(); this.batcher.setProjectionMatrix(cam.combined); counter=0; runTime=0; initAssetsObjects(); } public void render(float delta) { Gdx.gl.glClearColor(0, 0, 0, 1); // black background reduce flashing Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); batcher.begin(); //batcher.enableBlending(); //!!!!!!pruhlednost batcher.draw(rBackground,screenBoundBegin.x, screenBoundBegin.y, demandedScreen.x, demandedScreen.y); //pozadi drawChicken(delta); batcher.end(); } private void drawChicken(float delta) { counter+=delta*250*(chicken.getWholeSpeed()/180); // korekce animace pri zrychlovani chicken if(!chicken.isStanding()) { if(chicken.getMovingState()==MovingState.LEFT) { if((int)counter<COUNTERBEGIN) batcher.draw(left1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(left2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND)counter=0; } } else if (chicken.getMovingState()==MovingState.RIGHT) { if((int)counter<COUNTERBEGIN) batcher.draw(right1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(right2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if (chicken.getMovingState()==MovingState.LEFTSIDEDOWN) { if((int)counter<COUNTERBEGIN) batcher.draw(leftSideDown1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(leftSideDown2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if (chicken.getMovingState()==MovingState.LEFTSIDEUP) { if((int)counter<COUNTERBEGIN) batcher.draw(leftSideUp1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(leftSideUp2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if (chicken.getMovingState()==MovingState.RIGHTSIDEUP) { if((int)counter<COUNTERBEGIN) batcher.draw(rightSideUp1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(rightSideUp2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND)counter=0; } } else if (chicken.getMovingState()==MovingState.RIGHTSIDEDOWN) { if((int)counter<COUNTERBEGIN) batcher.draw(rightSideDown1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(rightSideDown2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if(chicken.getMovingState()==MovingState.LEFTUP) { if((int)counter<COUNTERBEGIN) batcher.draw(leftUp1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(leftUp2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND)counter=0; } } else if(chicken.getMovingState()==MovingState.LEFTDOWN) { if((int)counter<COUNTERBEGIN) batcher.draw(leftDown1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(leftDown2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if (chicken.getMovingState()==MovingState.RIGHTUP) { if((int)counter<COUNTERBEGIN) batcher.draw(rightUp1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(rightUp2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else if (chicken.getMovingState()==MovingState.RIGHTDOWN) { if((int)counter<COUNTERBEGIN) batcher.draw(rightDown1,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>=COUNTERBEGIN) { batcher.draw(rightDown2,chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); if((int)counter>COUNTEREND) counter=0; } } else Gdx.app.log("renderer:", "Sem by se rizeni nemelo dostat."); } else { runTime+=delta; //kvuli animaci if(chicken.getStandingState()==StandingState.STANDLEFT) batcher.draw(standLeftAnime.getKeyFrame(runTime),chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); else if(chicken.getStandingState()==StandingState.STANDRIGHT) batcher.draw(standRightAnime.getKeyFrame(runTime),chicken.getPositionX(),chicken.getPositionY(),chicken.getWidth(),chicken.getHeight()); else Gdx.app.log("renderer:", "Sem by se rizeni nemelo dostat."); } } //end of drawChicken private void initAssetsObjects() { this.rBackground=AssetManager.rBackground; this.right1=AssetManager.right1; this.right2=AssetManager.right2; this.rightSideDown1=AssetManager.rightSideDown1; this.rightSideDown2=AssetManager.rightSideDown2; this.rightSideUp1=AssetManager.rightSideUp1; this.rightSideUp2=AssetManager.rightSideUp2; this.rightUp1=rightDown1=AssetManager.right1; this.rightUp2=rightDown2=AssetManager.right2; this.left1=AssetManager.left1; this.left2=AssetManager.left2; this.leftSideDown1=AssetManager.leftSideDown1; this.leftSideDown2=AssetManager.leftSideDown2; this.leftSideUp1=AssetManager.leftSideUp1; this.leftSideUp2=AssetManager.leftSideUp2; this.leftDown1=leftUp1=AssetManager.left1; this.leftDown2=leftUp2=AssetManager.left2; this.standLeftAnime=AssetManager.standLeftAnime; this.standRightAnime=AssetManager.standRightAnime; this.chicken=gameMng.getObjectManager().getChicken(); } }
Přidáme importy a třídu uložíme. Nevyužitou BEGINYCONSTANT máme na příště. Vyběhla na nás chyba, že v AssetManageru není proměnná rBackground, otevřeme tedy AssetManager.java a pod stávající deklaraci proměnné
public static Texture background
přidáme:
public static TextureRegion rBackground;
Dále tuto proměnnou inicializujeme. Do funkce load() pod stávající řádky
background = new Texture(Gdx.files.internal("background.png")); background.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); //proti rozmazavani pri roztahovani
přidáme:
rBackground = new TextureRegion(background,0,0,800,500); rBackground.flip(false, true);
Třídu uložíme a zavřeme.
Ještě jsem zapomněl v konstruktoru třídy Chicken.java inicializovat stavové proměnné movingState a standingState, proto si tuto třídu otevřeme a na konec konstruktoru doplníme:
this.standingState=StandingState.STANDRIGHT; this.movingState=MovingState.RIGHT;
Nevyužité konstanty DEMANDED_SCREEN si zatím nevšímáme. Změnu uložíme a třídu zavřeme. Pro dnešek máme hotovo. Kdyby bylo cokoli nejasné, můžete opisovat z přiloženého zdrojového kódu, který je ke stažení. Aplikaci spustíme.

Vidíme, že nám vše funguje, slepice jde správným směrem na místo kliku a také se naklání.
V příští lekci, Programujeme Android hru - Krmení I, si přidáme třídu, která vytvoří instanci našeho krmiva a třídu pro vyhledávání volné pozice na obrazovce.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 33x (6.07 MB)
Aplikace je včetně zdrojových kódů v jazyce Java