Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 14 - Programujeme Android hru - Collision detection

V minulé lekci programování hry pro Android, Programujeme Android hru - Krmení II, jsme se věnovali krmení.

Dnes budeme zjišťovat možnou kolizi našeho kuřete s krmením a pokud zjistíme, že k této kolizi došlo, zvýšíme herní skóre o jedničku. Skóre a některé další údaje budeme chtít samozřejmě promítnout na obrazovku, pro tento účel si do assets nahrajeme své vlastní písmo.

Otevřeme si třídu AssetManager.java a doplníme k deklaracím proměnných:

public static BitmapFont yellowFont, shadowFont;

Do metody load() přidáme:

yellowFont = new BitmapFont(Gdx.files.internal("yellowfont.fnt"),true);
yellowFont.getData().setScale(0.5f, 0.5f);
shadowFont = new BitmapFont(Gdx.files.internal("blackfont.fnt"),true);
shadowFont.getData().setScale(0.5f, 0.5f);

Dále do třídy přidáme metodu dispose(), která slouží k uvolnění paměti po našich zdrojích:

public static void dispose() {
    Gdx.app.log("AssetMng ", "dispose()");
    background.dispose();
    carrot.dispose();
    autumn.dispose();
    corn.dispose();
    wheat.dispose();

    yellowFont.dispose();
    shadowFont.dispose();

    left1.dispose();
    left2.dispose();
    leftSideDown1.dispose();
    leftSideDown2.dispose();
    leftSideUp1.dispose();
    leftSideUp2.dispose();

    right1.dispose();
    right2.dispose();
    rightSideDown1.dispose();
    rightSideDown2.dispose();
    rightSideUp1.dispose();
    rightSideUp2.dispose();

    standLeft12.dispose();
    standRight12.dispose();
}

Přidáme importy a uložíme. Nezapomeneme naimportovat soubory písma a jeho stínu do složky assets, to již umíme. Metodu dispose() musíme ještě zavolat, otevřeme si třídu WackyChicken.java a zde na konec funkce dispose() přidáme řádek:

AssetManager.dispose();

Už jsme si zvykli, že již vypisuji pouze změny (přírůstky) kódu, na celý výpis tady nemáme prostor, vše najdeme v kompletním zdrojovém kódu, který je jako obvykle níže ke stažení.

Ohledně písma to je vše a nic nám nebrání v jeho použití, budeme ho potřebovat později při implementaci promítání skóre. Nyní pojďme řešit kolizi.

V balíčku com.wackychic­ken.managers si vytvoříme novou třídu OverlapsManager­.java a vyplníme ji do následujícího tvaru:

public class OverlapsManager {

    private Food food;
    private Chicken chicken;
    private int []score;

    public OverlapsManager(Food food) {
        this.food=food;
        this.chicken=food.getChicken();
        this.score=new int[1];
        this.score[0]=0;
    }

    public void update(float delta) { // trida hlida zda instance food a chicken se protinaji!
        if (Intersector.overlaps(food.getRectForOverlap(),chicken.getRectForOverlap()) && food.getWasClicked() && (!food.getWasCounted()) && chicken.isStanding()   )
        {
            score[0]++;
            food.setWasCounted(true);
            food.setLifeTime(0);
        }
    }

    public void clickedPosition(int x, int y) { // souradnice kliku z inputMng!
        if(food.getRectForOverlap().contains(x, y))
        {
            food.setWasClicked(true);
            chicken.incrWholeSpeed(10); // vzdy kdyz tapneme jidlo, zvysit rychlost
        }
        else { // zvysit rychost ale chceme i kdyz se neklika primo na zradlo
            if( (!chicken.isStanding() && chicken.getStandingState()==StandingState.STANDLEFT && x<chicken.getPositionX()) || (!chicken.isStanding() && chicken.getStandingState()==StandingState.STANDRIGHT && x>chicken.getPositionX()+chicken.getWidth()) )
            {
                chicken.incrWholeSpeed(10);
            }
        }
        // nize vyresetovani rychlosti pri zmene smeru
        if (!chicken.isStanding() && chicken.getStandingState()==StandingState.STANDLEFT && x>chicken.getPositionX()+chicken.getWidth())
            chicken.resetWholeSpeed();
        if (!chicken.isStanding() && chicken.getStandingState()==StandingState.STANDRIGHT && x<chicken.getPositionX())
            chicken.resetWholeSpeed();

    }

    public int[] getScore() {
        return score;
    }

    public void scoreRestart() {
        this.score[0]=0;
    }
}

Přidáme importy a uložíme. Eclipse na nás oprávněně vyhodí chybu, že v instanci chicken nezná přístupovou metodu getRectForOver­lap(), nejenže tam nemáme tuto přístupovou metodu, nemáme tam ani proměnnou, ke které přistupovat chceme. Pojďme to napravit, otevřeme třídu Chicken.java, kde k deklaracím proměnných přidáme:

private Rectangle rectForOverlap;

Do konstruktoru přidáme:

this.rectForOverlap = new Rectangle(positionX,positionY,this.WIDTH,this.HEIGHT);

Na začátek metody update(...) doplníme:

rectForOverlap.set(positionX, positionY, this.WIDTH, this.HEIGHT);

Na konec třídy pod stávající metody přidáme:

public Rectangle getRectForOverlap() {
    return rectForOverlap;
}

Přidáme importy a uložíme. Co nám zbývá dále? Založit instanci naší třídy OverlapsManager­.java, zavolat její metody update(...) a clickedPositi­on(...), otevřeme třídu ObjectManager.java, kde k deklaracím proměnných přidáme:

private OverlapsManager overlapsMng;

Na konec konstruktoru přidáme:

this.overlapsMng=new OverlapsManager(food);

Na konec funkce update(...) přidáme:

overlapsMng.update(delta);

Na začátek funkce receivePositi­on(...) přidáme:

overlapsMng.clickedPosition(x,y);

Na konec třídy ještě přidáme přístupovou metodu:

public OverlapsManager getOverlapsManager(){
    return this.overlapsMng;
}

Změny v třídě ObjectManager.java uložíme, třída je ve stejném balíčku, proto importy nejsou vyžadovány.

Nyní nám zbývá pouze pomocí našeho nově naimportovaného písma promítnout skóre, rychlost a "životnost" krmiva na obrazovku.

Otevřeme třídu Renderer.java, kde k deklaracím proměnných přidáme:

private OverlapsManager overlapsMng;
private BitmapFont yellowFont,shadowFont;
private int score[];

Na konci funkce initAssetsObjects() provedeme inicializaci výše uvedených proměnných přidáním:

this.overlapsMng=gameMng.getObjectManager().getOverlapsManager();
this.score=overlapsMng.getScore();
this.yellowFont=AssetManager.yellowFont;
this.shadowFont=AssetManager.shadowFont;

Dále do třídy Renderer.java přidáme 3 privátní metody, která umístíme například ihned pod metodu render(...):

private void drawTextScore() {
    shadowFont.draw(batcher, "Score: "+score[0],    screenBoundBegin.x+demandedScreen.x*0.22f+2,screenBoundBegin.y+5+2);
    yellowFont.draw(batcher, "Score: "+score[0], screenBoundBegin.x+demandedScreen.x*0.22f,screenBoundBegin.y+5);
}

private void drawTextSpeed() {
    shadowFont.draw(batcher, "Speed: "+(int)(chicken.getWholeSpeed()/10), screenBoundBegin.x+demandedScreen.x*0.45f+2,screenBoundBegin.y+5+2 );
    yellowFont.draw(batcher, "Speed: "+(int)(chicken.getWholeSpeed()/10), screenBoundBegin.x+demandedScreen.x*0.45f,screenBoundBegin.y+5 );
}

private void drawTextFood() {
    shadowFont.draw(batcher, "Food: "+(int)(1+food.getLifeTime()), screenBoundBegin.x+demandedScreen.x*0.7f+2,screenBoundBegin.y+5+2 );
    yellowFont.draw(batcher, "Food: "+(int)(1+food.getLifeTime()),screenBoundBegin.x+demandedScreen.x*0.7f,screenBoundBegin.y+5 );
}

A již nám nezbývá nic jiného, než provést volání těchto metod, provedeme to ve funkci render(...) ihned po promítnutí pozadí:

drawTextScore();
drawTextSpeed();
drawTextFood();

Přidáme importy, třídu uložíme a apk. spustíme.

Skóre se započítává - Programujeme Android hru

Vše nám funguje, slepici můžeme postupně popohánět k vyšší rychlosti. Při kolizi dojde k vylosování nové pozice krmiva a samozřejmě k započítání skóre. Rovněž "životnost" krmiva je odčítána.

Příště, Programujeme Android hru - Animace, zvuky, si ve stručnosti vysvětlíme princip činnosti a přidáme další fíčury.


 

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 29x (6.18 MB)
Aplikace je včetně zdrojových kódů v jazyce Java

 

Předchozí článek
Programujeme Android hru - Krmení II
Všechny články v sekci
Programujeme Android hru
Přeskočit článek
(nedoporučujeme)
Programujeme Android hru - Animace, zvuky
Článek pro vás napsal Jaroslav Polívka
Avatar
Uživatelské hodnocení:
Ještě nikdo nehodnotil, buď první!
Autor se věnuje převážně jazykům JAVA a C++
Aktivity