7. diel - Programujeme Android hru - Rozdelenie hry do tried I
Z minulej lekcie kurzu o programovaní hry pre Android v Jave máme vytvorené prázdne triedy, dnes a nabudúce do nich budeme dopĺňať. Najprv si však ešte v balíčku com.wackychicken.managers vytvoríme novú triedu TurnManager.java, ktorá sa nám bude starať nielen o pohyb a natáčanie sliepky práve tým smerom, ktorým pôjde. Triedu zatiaľ ponecháme od Eclipse v predvolenom stave, tzn. prázdnu as prázdnym konstruktoru.
Teraz už poďme písať kód do triedy, ktorá bude reprezentovať našej hlúpu sliepku. Otvoríme si triedu Chicken.java a vyplníme nasledujúcim kódom:
public class Chicken { private float wholeSpeed,dividedSpeedX,dividedSpeedY,positionX,positionY,distanceX,distanceY; private final float WIDTH=115,HEIGHT=90; private final int BEGINYCONSTANT; private final Vector2 SCREEN_BOUND_BEGIN,SCREEN_BOUND_END,DEMANDED_SCREEN; private boolean xPositionAchieved,yPositionAchieved; public Chicken(final Vector2 screenBoundBegin, final Vector2 screenBoundEnd, final Vector2 demandedScreen, final int BEGINYCONSTANT) { this.wholeSpeed = 50; this.dividedSpeedX=dividedSpeedY=0; this.xPositionAchieved=this.yPositionAchieved=true; this.positionX=screenBoundBegin.x+200; this.positionY=screenBoundBegin.y+BEGINYCONSTANT+(demandedScreen.y-BEGINYCONSTANT)/2 -(HEIGHT/2); this.BEGINYCONSTANT=BEGINYCONSTANT; this.SCREEN_BOUND_BEGIN=screenBoundBegin; this.SCREEN_BOUND_END=screenBoundEnd; this.DEMANDED_SCREEN=demandedScreen; } public void update(float delta) { checkBorders(); //druha kotva ohraniceni, kdyby byla spatne spocitana distance a kvuli //BEGINYCONSTANT if (!xPositionAchieved) { if (distanceX<0) { // kdyz je distance zaporna, tak dividedSpeed take positionX+= dividedSpeedX *delta; distanceX+=((-1)*dividedSpeedX *delta); if (dis anceX>0) xPositionAchieved=true; } if distanceX>0) { positionX+= dividedSpeedX *delta; distanceX+=((-1)*dividedSpeedX *delta); if(distanceX<0)xPositionAchieved=true; } } if (!yPositi nAchieve ) { if ( istanceY<0) { positionY+= dividedSpeedY *delta; distanceY+=((-1)*dividedSpeedY *delta); if(distanceY>0)yPositionAchieved=true; } if(distanceY>0) { positionY+= dividedSpeedY*delta; distanceY+=((-1)* dividedSp edY *delta); if (distanceY<0) yPositionAchieved=true; } } if(isStanding()) resetWholeSpeed(); } // konec update public float getWholeSpeed() { return wholeSpeed; } public void incrWholeSpeed(float speed) { this.wholeSpeed+=speed; } public void resetWholeSpeed() { this.wholeSpeed=50; } public void setXPositionAchieved(boolean achieved) { xPositionAchieved=achieved; } public void setYPositionAchieved(boolean achieved) { yPositionAchieved=achieved; } public boolean isStanding() { return (xPositionAchieved&&yPositionAchieved); } private void checkBorders() { if(positionX<=SCREEN_BOUND_BEGIN.x) { positionX=SCREEN_BOUND_BEGIN.x; } if(positionX+WIDTH>=SCREEN_BOUND_END.x) { positionX=SCREEN_BOUND_END.x-WIDTH; } if(positionY+HEIGHT<SCREEN_BOUND_BEGIN.y+BEGINYCONSTANT) { positionY=SCREEN_BOUND_BEGIN.y+BEGINYCONSTANT-HEIGHT; } if(positionY+HEIGHT>SCREEN_BOUND_END.y) { positionY=SCREEN_BOUND_END.y-HEIGHT; } } public float getPositionX() { return positionX; } public float getPositionY() { return positionY; } public float getWidth() { return WIDTH; } public float getHeight() { return HEIGHT; } public float getDistanceX() { return distanceX; } public float getDistanceY() { return distanceY; } public void setDistanceX(float x) { distanceX=x; } public void setDistanceY(float y) { distanceY=y; } public void setDividedSpeedX(float X) { dividedSpeedX = X; } public void setDividedSpeedY(float Y) { dividedSpeedY = Y; } }
Pridáme importy a uložíme. Triedu stručne popíšem, o všetkých premenných alebo konštantách sa nebudem zmieňovať, pretože ich názvom je naznačené, k čomu sú určené. Sliepky bude mať nejakú rýchlosť, ktorou sa bude pohybovať po obrazovke (wholespeed). Aby chodila po oboch osiach xay rovnomerne, je nutné túto celkovú rýchlosť rozložiť (dividedSpeedX, dividedSpeedY) podľa pomeru vzdialeností osí, ktoré má naša hlúpe kurča uraziť. BEGINYCONSTANT je vytýčenie hranice na y súradnicu, aby sliepky chodila len po tráve. Konštanty vektorov SCREEN_BOUND_BEGIN, SCREEN_BOUND_END, DEMANDED_SCREEN už poznáme a slúži na vytýčenie virtuálne obrazovky. Pravdivostná premenné xPositionAchieved a yPositionAchieved uchovávajú informáciu o tom, či sliepky dosiahla požadovaných súradníc. Metóda update () pripočíta do premenných positionX a Y a tým dáva kurča na obrazovke do pohybu. Metódu checkBorders () som opísal v kóde komentárom. Nakoniec máme prístupovej metódy (getters and setters) na získanie alebo nastavenie hodnôt premenných.
Otvoríme našej prázdnu triedu TurnManager.java, ktorú sme pred chvíľou vytvorili a vyplníme jej kódom:
public class TurnManager { private Chicken chicken; private final Vector2 screenBoundEnd; private final Vector2 screenBoundBegin; private final int BEGINYCONSTANT; public TurnManager(GameScreen gameScreen,final int BEGINYCONSTANT) { final Vector2 demandedScreen=gameScreen.DEMANDED_SCREEN; this.screenBoundBegin=gameScreen.SCREEN_BOUND_BEGIN; this.screenBoundEnd=gameScreen.SCREEN_BOUND_END; this.BEGINYCONSTANT=BEGINYCONSTANT; this.chicken = new Chicken(screenBoundBegin,screenBoundEnd,demandedScreen,BEGINYCONSTANT); } public void setChickenDistance(int x, int y) { int clickedPositionX=x,clickedPositionY=y; float distanceX,distanceY; float chickenTailX = chicken.getPositionX() + chicken.getWidth(); //pozice chicken.x a y jsou floaty // je do nich pricitana delta if (Math.abs(clickedPositionX - chicken.getPositionX()) <= Math.abs(clickedPositionX - chickenTailX)) distanceX=clickedPositionX - chicken.getPositionX(); else distanceX=clickedPositionX - chickenTailX; if(distanceX < screenBoundBegin.x-chicken.getPositionX()) distanceX = screenBoundBegin.x-chicken.getPositionX(); if(distanceX > screenBoundEnd.x- chickenTailX) distanceX=screenBoundEnd.x- chickenTailX; distanceY=clickedPositionY-(chicken.getPositionY()+chicken.getHeight()); if(distanceY < (screenBoundBegin.y+BEGINYCONSTANT)-(chicken.getPositionY()+ chicken.getHeight())) distanceY=(screenBoundBegin.y+BEGINYCONSTANT)-(chicken.getPositionY()+ chicken.getHeight()); if(distanceY > (screenBoundEnd.y-(chicken.getPositionY()+chicken.getHeight())) ) distanceY = screenBoundEnd.y-(chicken.getPositionY()+chicken.getHeight()); if(Math.abs(distanceX)<0.5f) { if(distanceX >=0) distanceX=0.5f; else distanceX=-0.5f; } if(Math.abs(distanceY)<0.5f) { if(distanceY >=0) distanceY=0.5f; else distanceY=-0.5f; } chicken.setDistanceX(distanceX); chicken.setDistanceY(distanceY); } public void setChickenSpeed() { float speedRatio = chicken.getWholeSpeed() / (Math.abs(chicken.getDistanceX()) +Math.abs(chicken.getDistanceY())); chicken.setDividedSpeedX(speedRatio*chicken.getDistanceX()); chicken.setDividedSpeedY(speedRatio*chicken.getDistanceY()); } public Chicken getChicken() { // kvuli objectManager return chicken; } }
Pridáme importy a uložíme. Vybehnú na nás tri chyby, že vektory obrazovky v triede GameScreen.java nie sú viditeľné:
Otvoríme si teda túto triedu a zmeníme v nej riadok z:
private final Vector2 DEMANDED_SCREEN,SCREEN_BOUND_BEGIN,SCREEN_BOUND_END;
na:
public final Vector2 DEMANDED_SCREEN,SCREEN_BOUND_BEGIN,SCREEN_BOUND_END;
a zmenu uložíme. Zatiaľ neriešime natáčanie sliepky do požadovaného smeru, metóda setChickenDistance () vypočítava vzdialenosť medzi aktuálnymi súradnicami sliepky a súradnicami dotyku užívateľa na obrazovke. Do výpočtu sa musí zohľadniť, kam užívateľ klikol voči aktuálnej pozíciu sliepky, teda či sa (ne) budú do vzdialenosti pričítať aj jej rozmery. Metódu setChickenSpeed () som už opísal vyššie, keď som popisoval rozdelenie celej rýchlosti v premennej wholeSpeed do premenných dividedSpeedX a dividedSpeedY.
Pre dnešok je to všetko, pokračovať budeme nabudúce.