IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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í.

10. diel - Hra Tetris v MonoGame: Bodovanie a dokončenie levelu

V minulej lekcii, Hra Tetris v MonoGame: Sprevádzkovanie hry , sme sprevádzkovali základy hry a urobili tak level hrateľný. Dnes level dokončíme.

Budúci kocka

Ako je u Tetrisu zvykom, hráč vidí budúci kocku, aby sa podľa toho mohol u súčasnej kocky zariadiť. Naša hra nebude výnimkou. Do KomponentaLevel si pridáme nový atribút s inštanciou budúci kocky:

private Kostka pristiKostka;

Pred volanie DalsiKostka(); v Initialize() vložíme vytvorení inštancie budúci kocky:

pristiKostka = generatorKostek.Generuj(7);
DalsiKostka();

Presunieme sa do metódy DalsiKostka(), ktorá teraz do kostka uloží budúci kocku a zároveň vygeneruje novú. Jej kód bude novo vyzerať takto:

public void DalsiKostka()
{
    kostka = pristiKostka;
    kostka.pozice = hraciPlocha.PosadKostku(kostka);
    pristiKostka = generatorKostek.Generuj(7);
}

Nakoniec budúci kocku vykreslíme. Na pozadí je na to pripravená natiahnutá ruka robota, ktorá vyžaruje modré pole. Na to kocku umiestnime, do Draw() teda za vykreslenie kocky pridáme:

pristiKostka.Vykresli(new Vector2(930, 200), hra.spriteBatch, sprityPolicek);

výsledok:

Ukážkový Tetris v XNA Game Studio - Od nuly k tetrisu v MonoGame

Skóre

Hra by mala hráča samozrejme nejako vyzývať, v Tetrisu je na tento účel skóre (body) a dosiahnutý level. V súvislosti s hráčom nás bude zaujímať ešte počet zaplnených radov a jeho prezývka. V ďalších lekciách si totiž ukážeme, ako skóre nahrať na internet tak, aby bol hráč pod prezývkou vidieť v tabuľke najlepších výsledkov.

K projektu Robotris pripojíme novú triedu Hrac, do ktorej vložíme spomínané atribúty. Tie budú pre zjednodušenie verejné a trieda bude slúžiť len na držanie dát o hráčovi. Nezabudnite dať triede modifikátor public.

public class Hrac
{
    public long body;
    public int rady;
    public int level;
    public string prezdivka;

    public Hrac()
    {
        body = 0;
        rady = 0;
        level = 1;
    }
}

Na triede nie je inak nič zaujímavé, asi len to, že body sú typu long, pretože šikovný hráč by sa nemusel zmestiť do rozsahu typu int :) Konštruktor atribúty inicializuje.

Inštanciu hráča bude spravovať samotná trieda Hra, pretože ju bude v ďalších lekciách potreba zdieľať medzi ďalšími komponentmi (skóre tabuľkou). Presuňme sa teda do Hra.cs a pridajme atribút hrac:

public Hrac hrac;

Tým sme v Hra.cs skončili, prejdime opäť do KomponentaLevel, kde v Initialize() vytvoríme inštanciu hráča:

hra.hrac = new Hrac();

Vykreslenie HUDu

Teraz vykreslíme tzv. HUD (informačný panel s hodnotami hráča), ktorý bude zobrazovať skóre a level. Prejdime do metódy Draw() a jednoducho pridajme výpis týchto hodnôt z inštancie hráča. Budeme na to potrebovať menší font, ktorý máme pripravený. Font sa bude používať len v tejto komponente, preto ho načítame tu. Ako ďalšiu možnosť by sme ho mohli umiestniť do Hra.cs ako verejný. Vytvoríme privátne atribút font:

private SpriteFont font;

A v LoadContent() do neho načítame font z obsahu:

font = hra.Content.Load<SpriteFont>("Fonty/font_blox_maly");

Teraz len v Draw() vykreslíme hodnoty na príslušnú pozíciu:

hra.spriteBatch.TextSeStinem(font, "skore\n " + hra.hrac.body.ToString(), new Vector2(30, 390), Color.Red);
hra.spriteBatch.TextSeStinem(font, "level\n " + hra.hrac.level.ToString(), new Vector2(215, 390), Color.Red);

výsledok:

Ukážkový Tetris v XNA Game Studio - Od nuly k tetrisu v MonoGame

Bodovania

Poďme hru bodovať, samozrejme pôjde o bodovania radov. Budeme vychádzať z originálneho Tetrisu verzie A. Body sa pripisujú podľa počtu zaplnených radov raz kockou:

Počet zaplnených radov vzorec
1 level * 40 + 40
2 level * 100 + 100
3 level * 300 + 300
4 level * 1200 + 1200
Zaplnenie štyroch radov naraz sa hovorí tetris a hráč toho docieli iba kockou tvaru I.

Ak nejaká rad zmizne, ešte prehráme zvuk. Ten si najskôr pripravíme. Pridáme atribút triedy:

private SoundEffect zvukRada;

A načítame v LoadContent():

zvukRada = hra.Content.Load<SoundEffect>(@"Zvuky\zvuk_rada");

Ide sa bodovať, presuňme sa do Update(), do podmienky, kde kontrolujeme kolízii kocky, pripájame ju do hracej plochy a tak podobne. Spomínaný blok kódu teraz vyzerá takto:

if (hraciPlocha.Kolize(kostka, kostka.pozice))
{
    kostka.pozice.Y--;
    hraciPlocha.Pripoj(kostka);
    hraciPlocha.VymazRady();
    DalsiKostka();
}

Návratovú hodnotu metódy VymazRady() uložíme do premennej rady (je to počet radov, ktoré boli vymazané). Kód teda upravíme:

int rady = hraciPlocha.VymazRady();

Pri vymazaní aspoň jednej rady prehráme pripravený zvuk:

if (rady > 0)
    zvukRada.Play();

Radu hráči pripočítame:

hra.hrac.rady += rady;

A tiež mu za to pridelíme body podľa príslušného vzorca:

switch (rady)
{
    case 1: hra.hrac.body += hra.hrac.level * 40 + 40; break;
    case 2: hra.hrac.body += hra.hrac.level * 100 + 100; break;
    case 3: hra.hrac.body += hra.hrac.level * 300 + 300; break;
    case 4: hra.hrac.body += hra.hrac.level * 1200 + 1200; break;
}

Level sa bude zvyšovať každých 10 radov a pri 0 radoch bude 1. Vypočítame ho nasledovne:

int level = hra.hrac.rady / 10 + 1;

Pokiaľ má hráč iný level, než tento nový, vypočítaný, aktualizujeme ho a zároveň zvýšime rýchlosť hry o 5/6:

if (hra.hrac.level != level)
{
    hra.hrac.level = level;
    rychlost = rychlost * 5 / 6;
}

Môžete vyskúšať.

Prehra

Zostaňme ešte v bloku kolízie kocky s hracou plochou. Budeme reagovať na prehru. Hráč prehrá vo chvíli, keď dovŕši kocky až na horný okraj hracej plochy. Inými slovami pokiaľ nie je kam položiť novo padajúce kocku, hra skončila. Preto sa hneď po volaní DalsiKostka() spýtame, či koliduje. Ak nová kocka ihneď po položení koliduje, hru ukončíme. To zatiaľ urobíme tak, že ukončíme celú aplikáciu. V ďalších lekciách zobrazíme obrazovku pre odoslanie skóre a vrátime sa do menu.

Pridajme teda za DalsiKostka() jednoduchú podmienku:

if (hraciPlocha.Kolize(kostka, kostka.pozice))
    hra.Exit();

Metódou Exit() na inštanciu hry sme hru ukončili. Level je teraz už dobre hrateľný.

Pauza

Určite je dobré hráči umožniť hru zapauzovať. Existuje mnoho spôsobov, ako to dosiahnuť, mohli by sme si pre pauzu vytvoriť ďalšie komponent a potom KomponentuLevel zastaviť. Uchýlime sa však k jednoduchšiemu riešeniu, komponente KomponentaLevel pridelíme stavy. Tie budú dva: Hra a Pauza. V triede si deklarujeme Výučbový typ StavHry a atribút tohto typu:

public enum eStavHry
{
    Hra,
    Pauza,
}
public eStavHry stavHry;

V Initialize() stav nastavíme na Hra:

stavHry = eStavHry.Hra;

Pri pauze nebude hra aktívnu a cez obrazovku bude vykreslený zašednutý sprite s hláškou, že je hra zapauzovaní. Sprite si stiahnite:

sprite pauzy - Od nuly k tetrisu v MonoGame

a pridajte do RobotrisContent, do zložky Sprity/.

Ako vždy si pre sprite vytvoríme atribút:

private Texture2D sprPauza;

A načítame ho v LoadContent():

sprPauza = hra.Content.Load<Texture2D>(@"Sprity\spr_pauza");

Podľa stavu hry sa bude správať metóda Update(). Rozdelíme ju na 2 vetvy podľa stavov. Celý súčasný obsah metódy vložíme do podmienky, či je stav hry Hra. Pridáme do neho ešte reakciu na kláves Escape, ktorá spôsobí prepnutie stavu na pauzu a pozastavenie prehrávania hudby.

// Hra
if (stavHry == eStavHry.Hra)
{
    . . .

    if (hra.klavesy.IsKeyDown(Keys.Escape))
    {
        MediaPlayer.Pause();
        stavHry = eStavHry.Pauza;
    }
}

Za vetvu s hrou pridáme ďalšiu vetvu s pauzou. V stave Pauza bude reagovať na klávesy A (Áno, ukončenie hry) a N (Nie, návrat do hry).

if (stavHry == eStavHry.Pauza)
{
    if (hra.klavesy.IsKeyDown(Keys.A))
        hra.Exit(); // Ukončení

    if (hra.klavesy.IsKeyDown(Keys.N))
    {
        stavHry = eStavHry.Hra; // Pokračování
        MediaPlayer.Resume();
    }
}

Zostáva, aby na stav pauzy reagovala aj vykresľovací metóda. Na koniec vykresľovanie v metóde Draw() pridáme vykreslenie Spritu s pauzou a textu:

if (stavHry == eStavHry.Pauza)
{
    hra.spriteBatch.Draw(sprPauza, new Rectangle(0, 0, hra.sirkaOkna, hra.vyskaOkna), Color.White);
    hra.spriteBatch.TextSeStinem(font, "hra pozastavena", new Vector2(480, 260), Color.Red);
    hra.spriteBatch.TextSeStinem(hra.fontCourierNew, "Opravdu si přejete hru ukončit?\n\n\'A\' - ukončení hry \n\n\'N\' - pokračovat ve hře", new Vector2(440, 340), Color.Red);
}

A vyskúšame:

Ukážkový Tetris v XNA Game Studio - Od nuly k tetrisu v MonoGame

Nabudúce, v lekcii Hra tetris v MonoGame: Vychytávky v leveli , do hry pridáme ešte ďalšie vychytávky.


 

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é 285x (12.09 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#

 

Predchádzajúci článok
Hra Tetris v MonoGame: Sprevádzkovanie hry
Všetky články v sekcii
Od nuly k tetrisu v MonoGame
Preskočiť článok
(neodporúčame)
Hra tetris v MonoGame: Vychytávky v leveli
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity