Lekce 13 - Programujeme Android hru - Krmení II
Zdravím vás v dalším díle našeho kurzu. V tom minulém, Programujeme Android hru - Krmení I, jsme navenek nepřidali žádnou funkcionalitu, pouze jsme přidali dvě třídy.
Dnes si ve stručnosti popíšeme jejich princip a rozjedeme promítání krmení na obrazovku.
Začneme proměnnými třídy PosFinder.java, screen konstanty dobře známe, beginConstant též známe a je okomentovaná. Random je jasná, slouží k vylosování souřadnic. Instance třídy PosFinder.java musí při každém hledání volného místa mj. znát:
- aktuální polohu kuřete
- rozměry kuřete
- rozměry krmiva
První dvě položky ukládáme do proměnné receivedRectangle a do proměnných width, height rozměry krmiva.
Dvouprvkové float pole generatedPosition je konečným výstupem a obsahuje vylosované vhodné souřadnice, na které je možné krmení v daný okamžik umístit.
Pole area[] inicializujeme v konstruktoru kódem:
this.area = new Rectangle[4]; for (int i = 0; i < area.length; i++) area[i]=new Rectangle();
Tedy jako pole čtyř obdélníků, proč zrovna tak? Na to více než slova odpoví obrázky:



Ano, plochu, po které může naše hloupá slepice chodit, jsme si rozdělili na 4 oblasti. Ať slepice půjde po našem "jevišti" kamkoli, vždy vzniknou 2, 3 nebo 4 oblasti (obdélníky), které jsou vhodné pro umístění krmení.
Jak to funguje?
Souřadnice krmiva mají nějakou dobu životnosti, která je dána odčítáním proměnné lifeTime instance třídy Food.java. Vždy, když je proměnná lifeTime <= 0, zavolá se metoda findOutFreePosition(...), která dle aktuální pozice kuřete stanoví, zda se utvořily 2, 3, nebo 4 zmíněné oblasti (obdélníky). Korekce pomocí proměnné coefficient zabezpečí, aby oblasti vznikly teprve tehdy, až pro ně bude existovat větší místo, než je velikost krmiva, tedy minimálně 32*1,25 px, abychom měli z čeho losovat.
Podle vzniklých oblastí metoda findOutFreePosition(...) zavolá s příslušným char argumentem metodu generatePosition(...), která dle tohoto argumentu vybere konkrétní oblasti a nastaví je na konkrétní rozměry, dle aktuální pozice kuřete. Posledním úkolem metody generatePosition(...) je zavolání metody setCoordinate(...), která vylosuje oblast a souřadnice, na kterých se má krmivo objevit a nastaví tyto souřadnice do pole generatedPosition. Řízení se vrátí metodě findOutFreePosition(...), která vrací pole s požadovanými souřadnicemi.
Třída Food.java
Instance bude mít nějaké rozměry, dále souřadnice, kde se na obrazovce nachází (WIDTH, HEIGHT, positionX, positionY). Proměnnou lifeTime jsem již objasnil výše. Ještě k ní dodám, že je inicializovaná pomocí newLifeTime, protože postupně chceme snižovat dobu životnosti krmiva a tím zvyšovat obtížnost hry. Do counter se postupně přičítá delta a až součet dosáhne určité hodnoty, vyvolá to snížení hodnoty newLifeTime. Proměnná rectForOverlap bude sloužit k detekci kolize krmiva a kuřete. Vždy při promítnutí krmiva na nových souřadnicích se zobrazí jiný obrázek, toto přepnutí zajistí proměnná mask.
Řádek s výčtovými konstantami
enum Type {WHEAT,CORN,BERRY,CARROT}
jsem odstranil (vykomentoval).
Pravdivostní wasClicked a wasCounted slouží k tomu, aby vyhodnocení
kliknutí na krmivo a započítání bodu bylo provedeno jen jednou.
Promítání krmení
Co musíme splnit pro promítnutí krmiva?
- načíst potřebné obrázky krmení ve třídě Assets.java
- vytvořit instanci dle třídy Food.java a volat metodu update(...) této instance
- renderovat instanci
Do složky assets přidáme 4 soubory obrázků krmení, jsou součástí balíku ke stažení dole. Ve třídě AssetManager.java tyto obrázky načteme do paměti, výsledná podoba třídy:
public class AssetManager { public static Texture background; public static TextureRegion rBackground; public static Texture left1,left2,leftSideDown1,leftSideDown2,leftSideUp1,leftSideUp2; public static Texture right1,right2,rightSideDown1,rightSideDown2,rightSideUp1,rightSideUp2; public static Texture carrot,autumn,corn,wheat; public static Texture standLeft12; //na animaci oka public static TextureRegion rStandLeft1,rStandLeft2; //na animaci oka public static Animation standLeftAnime; //na animaci oka public static Texture standRight12; //na animaci oka public static TextureRegion rStandRight1,rStandRight2; //na animaci oka public static Animation standRightAnime; //na animaci oka public static void load() { background = new Texture(Gdx.files.internal("background.png")); background.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); //proti rozmazavani pri roztahovani rBackground = new TextureRegion(background,0,0,800,500); rBackground.flip(false, true); carrot = new Texture(Gdx.files.internal("carrot.png")); carrot.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); autumn = new Texture(Gdx.files.internal("autumn.png")); autumn.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); corn = new Texture(Gdx.files.internal("corn.png")); corn.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); wheat = new Texture(Gdx.files.internal("wheat.png")); wheat.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); left1 = new Texture(Gdx.files.internal("left1.png")); left1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); left2 = new Texture(Gdx.files.internal("left2.png")); left2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); leftSideDown1 = new Texture(Gdx.files.internal("leftsidedown1.png")); leftSideDown1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); leftSideDown2 = new Texture(Gdx.files.internal("leftsidedown2.png")); leftSideDown2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); leftSideUp1 = new Texture(Gdx.files.internal("leftsideup1.png")); leftSideUp1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); leftSideUp2 = new Texture(Gdx.files.internal("leftsideup2.png")); leftSideUp2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); right1 = new Texture(Gdx.files.internal("right1.png")); right1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); right2 = new Texture(Gdx.files.internal("right2.png")); right2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rightSideDown1 = new Texture(Gdx.files.internal("rightsidedown1.png")); rightSideDown1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rightSideDown2 = new Texture(Gdx.files.internal("rightsidedown2.png")); rightSideDown2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rightSideUp1 = new Texture(Gdx.files.internal("rightsideup1.png")); rightSideUp1.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rightSideUp2 = new Texture(Gdx.files.internal("rightsideup2.png")); rightSideUp2.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); /* zacatek obsluhy animace mrkani oka, kdyz kure stoji doleva nebo doprava */ standLeft12 = new Texture(Gdx.files.internal("standleft12.png")); standLeft12.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rStandLeft1 = new TextureRegion(standLeft12,0,0,115,90); rStandLeft1.flip(false, false); rStandLeft2 = new TextureRegion(standLeft12,115,0,115,90); rStandLeft2.flip(false, false); TextureRegion[]rStandLeft12={rStandLeft1,rStandLeft1,rStandLeft1, rStandLeft1,rStandLeft1,rStandLeft2}; standLeftAnime = new Animation(0.2f, rStandLeft12); standLeftAnime.setPlayMode(Animation.PlayMode.LOOP_PINGPONG); standRight12 = new Texture(Gdx.files.internal("standright12.png")); standRight12.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); rStandRight1 = new TextureRegion(standRight12,0,0,115,90); rStandRight1.flip(false, false); rStandRight2 = new TextureRegion(standRight12,115,0,115,90); rStandRight2.flip(false, false); TextureRegion[]rStandRight12={rStandRight1,rStandRight1,rStandRight1, rStandRight1,rStandRight1,rStandRight2}; standRightAnime = new Animation(0.2f, rStandRight12); standRightAnime.setPlayMode(Animation.PlayMode.LOOP_PINGPONG); /* konec obsluhy animace mrkani oka, kdyz kure stoji doleva nebo doprava */ } }
Vytvoření instance dle třídy Food.java a volání metody update(...)
Do třídy ObjectManager.java přidáme tyto řádky:
private Food food; this.food = new Food(gameScreen, chicken, BEGINYCONSTANT); food.update(delta); public Food getFood() { return food; }
Přidáme importy a uložíme. Již nemáme prostor dělat výpis celé třídy, takže pokud si nejsme jisti, kam řádky do třídy přidat, podíváme se do zdrojového kódu, který je na konci této kapitoly ke stažení.
Promítnutí krmení
Do třídy Renderer.java přidáme následující kód:
private Food food; private Texture carrot, autumn, corn, wheat; this.carrot = AssetManager.carrot; this.autumn = AssetManager.autumn; this.corn = AssetManager.corn; this.wheat = AssetManager.wheat; this.food = gameMng.getObjectManager().getFood(); drawFood(); private void drawFood() { if (food.getMask() == 0) batcher.draw(autumn, food.getPositionX(),food.getPositionY(),food.getWidth(),food.getHeight()); else if(food.getMask()==1) batcher.draw(corn, food.getPositionX(),food.getPositionY(),food.getWidth(),food.getHeight()); else if(food.getMask()==2) batcher.draw(wheat, food.getPositionX(),food.getPositionY(),food.getWidth(),food.getHeight()); else batcher.draw(carrot, food.getPositionX(),food.getPositionY(),food.getWidth(),food.getHeight()); }
Přidáme importy a uložíme. Stejně jako v předchozí třídě, pokud si nejsme jisti, kam řádky do třídy přidat, podíváme se do zdrojového kódu. Aplikaci spustíme a pokud máme vše správně, postupně se nám za sebou promítnou krmiva bobule, kukuřice, pšenice a mrkev na náhodných souřadnicích.
Příště, Programujeme Android hru - Collision detection, se budeme zabývat kolizí našeho hloupého kuřete s krmením, promítáním skóre, rychlosti a životnosti krmiva.
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 28x (6.1 MB)
Aplikace je včetně zdrojových kódů v jazyce Java