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í.

Lekce 8 - Hra tetris v MonoGame: Hrací plocha

V minulé lekci, {PREVIOS}, jsme si naprogramovali generátor kostek do hry Tetris.

Dnes si vytvoříme další herní objekt, kterým bude hrací plocha.

Hrací plocha

Již máme komponentu level, ve které se bude hra odehrávat. Máme generátor náhodných kostek a objekt padající kostky. Chybí nám hrací plocha.

Jedná se o objekt, který bude obsahovat dvourozměrné pole již spadaných kostek. Dále metodu ke zjištění, zda padající kostka s hrací plochou koliduje, metodu k připojení kostky k napadaným kostkám plochy, metodu k vymazání plných řad a samozřejmě metodu k vykreslení políček plochy.

Připojme si k projektu třídu HraciPlocha, opět jí nastavíme jako public a přidáme potřebné using:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

Atributy

Podobně jako u kostky přidáme atribut s políčky:

private int[,] policka;

Dále šířku a výšku hrací plochy v políčkách:

private int sirka;
private int vyska;

Posledním atributem bude vykreslovací pozice hrací plochy na pozadí levelu:

private Vector2 pozice;

Vyprázdnění políček

Přidáme si jednoduchou metodu, která hrací plochu vyprázdní, přesněji inicializuje políčka:

public void Vyprazdni()
{
    policka = new int[sirka, vyska];
}

Konstruktor

Nyní vytvoříme konstruktor, ten bude brát v parametrech rozměry a pozici hrací plochy. Dále instanci inicializuje:

public HraciPlocha(int sirka, int vyska, Vector2 pozice)
{
    this.sirka = sirka;
    this.vyska = vyska;
    this.pozice = pozice;
    Vyprazdni();
}

Posazení nové kostky

Další metodou bude PosadKostku(), které předáme v parametru novou kostku a ona nám vrátí souřadnice, na kterých se kostka objeví nahoře, ve středu hrací plochy.

public Vector2 PosadKostku(Kostka kostka)
{
    return new Vector2(((int)sirka / 2) - 1, 0);
}

Nic složitého k přemýšlení, šířku hrací plochy prostě vydělíme celočíselně dvěma a máme střed. Metoda by se měla chovat podle toho, jakou kostku ji předáváme, aby byla správně vycentrovaná a u některých kostek bychom měli nastavit složku Y na -1, protože je první řada políček kostky prázdná. To ale zatím pro jednoduchust zanedbáme.

Připojení kostky k hrací ploše

Pojďme dále, implementujme metodu Pripoj(), která bude opět brát v parametru kostku a její políčka připojí k políčkům hrací plochy, tedy mezi ostatní, již spadlé kostky. Projedeme cykly všechna políčka kostky a pokud je políčko kostky zaplněné a zároveň nevyčnívá nahoře z hrací plochy (to se může na konci hry stát a musíme s tím počítat), připojíme ho na příslušnou pozici do políček hrací plochy.

public void Pripoj(Kostka kostka)
{
    // projetí všech políček kostky
    for (int j = 0; j < 4; j++)
        for (int i = 0; i < 4; i++)
        {
            // získání souřadnic políčka v hrací ploše
            int x = Convert.ToInt32(i + kostka.pozice.X);
            int y = Convert.ToInt32((j + kostka.pozice.Y));
            // políčko je zaplněné a nevyčnívá zhora z hrací plochy
            if ((kostka.Policka[i, j] > 0) && (y >= 0))
                policka[x, y] = kostka.Policka[i, j];
        }
}

Trochu nešikovné zde je, že musíme zkonvertovat reálné složky vektoru na celočíselné. Někdy se nám vektory ale zas hodí.

Kolize kostky

Další důležitou metodou k implementaci je metoda Kolize(), která vrátí true, pokud kostka koliduje s nějakými políčky v hrací ploše. Metoda bude brát jako parametry kostku a její pozici. Kostka samotná sice svou pozici obsahuje, ale nám se bude hodit ptát se: "Kolidovala by kostka, kdyby byla na pozici...", proto budeme předávat i pozici.

Z počátku budeme předpokládat, že ke kolizi nedošlo. Vytvoříme si tedy proměnnou kolize a nastavíme ji na false. Poté jako vždy projedeme všechna políčka kostky:

public bool Kolize(Kostka kostka, Vector2 pozice)
{
    bool kolize = false;
    for (int j = 0; j < 4; j++)
        for (int i = 0; i < 4; i++)

Nyní nás čeká poměrně složitá podmínka, kterou si však hezky rozepíšeme. Pokud je políčko v kostce plné:

if ((kostka.Policka[i, j] > 0) &&

a vyjelo z hrací plochy:

((j + pozice.Y >= vyska) || (i + pozice.X < 0) || (i + pozice.X >= sirka) ||

nebo se překrývá s jiným políčkem hrací plochy:

(policka[Convert.ToInt32(i + pozice.X), Convert.ToInt32(j + pozice.Y)] > 0)))

pak ke kolizi došlo:

kolize = true;

Nakonec výsledek vrátíme. Kompletní kód metody je následující:

public bool Kolize(Kostka kostka, Vector2 pozice)
{
    // budeme předpokládat, že nedošlo ke kolizi
    bool kolize = false;
    // projetí všech políček kostky
    for (int j = 0; j < 4; j++)
        for (int i = 0; i < 4; i++)
               // Pokud je políčko v kostce plné a
            if ((kostka.Policka[i, j] > 0) &&
               // vyjelo z hrací plochy nebo
               ((j + pozice.Y >= vyska) || (i + pozice.X < 0) || (i + pozice.X >= sirka) ||
               // překrývá se s jiným políčkem hrací plochy
               (policka[Convert.ToInt32(i + pozice.X), Convert.ToInt32(j + pozice.Y)] > 0)))
                    // došlo ke kolizi
                    kolize = true;
    return kolize;
}

Zbývá nám již jen vymazání řad a vykreslení.

Vymazání řad

Metoda VymazRady() vymaže plné řady v políčkách hrací plochy a samozřejmě políčka nad řadou sesune dolů. Návratová hodnota bude typu int a bude udávat, kolik řad bylo vymazáno. To bude později důležité pro výpočet skóre.

Nejprve si vytvoříme počítadlo vymazaných řad a to nastavíme na 0. Dále for cyklem projedeme všechny řady hrací plochy. Nakonec počítadlo vrátíme:

public int VymazRady()
{
    // kontrola plných řad
    int pocet = 0;
    for (int rada = 0; rada < vyska; rada++)
    {

    }
    return pocet;

V každé iteraci cyklu musíme zjistit, zda je daná řada plná. Zpočátku budeme předpokládat že ano, poté projedeme řadu políčko po políčku a pokud nalezneme nějaké prázdné, usoudíme, že řada plná není:

// předpokládáme, že je řada plná
bool plna = true;
// pokud je někde prázdné políčko, plná není
for (int i = 0; i <= (sirka - 1); i++)
    if (policka[i, rada] == 0)
        plna = false;

V případě plné řady zbývá posunout všechna políčka nad řadou o 1 dolů a zvýšit počítadlo plných řad. Pojedeme pozpátku:

// smazání plné řady
if (plna)
{
    // posun políček nad řadou dolů
    for (int j = (rada - 1); j > 0; j--)
        for (int i = 0; i < sirka; i++)
            policka[i, j + 1] = policka[i, j];
    pocet++;
}

Opět pro jistotu přikládám kód celé metody:

public int VymazRady()
{
    // kontrola plných řad
    int pocet = 0;
    for (int rada = 0; rada < vyska; rada++)
    {
        // předpokládáme, že je řada plná
        bool plna = true;
        // pokud je někde prázdné políčko, plná není
        for (int i = 0; i <= (sirka - 1); i++)
            if (policka[i, rada] == 0)
                plna = false;
        // smazání plné řady
        if (plna)
        {
            // posun políček nad řadou dolů
            for (int j = (rada - 1); j > 0; j--)
                for (int i = 0; i < sirka; i++)
                    policka[i, j + 1] = policka[i, j];
            pocet++;
        }
    }
    return pocet;
}

Vykreslení hrací plochy

Doplňme vykreslovací metodu, na té není nic složitého, vykreslení hrací plochy probíhá úplně stejně, jako tomu bylo u vykreslení kostky:

public void Vykresli(SpriteBatch spriteBatch, Texture2D[] sprity)
{
    for (int j = 0; j <= (vyska - 1); j++)
        for (int i = 0; i <= (sirka - 1); i++)
            if (policka[i, j] != 0)
                spriteBatch.Draw(sprity[policka[i, j] - 1], new Vector2(pozice.X + i * sprity[0].Width, pozice.Y + j * sprity[0].Height), Color.White);
}

Třída HraciPlocha je prozatím hotová.

Příště, v lekci Hra Tetris v MonoGame: Zprovoznění hry, si ji vyzkoušíme a hru zprovozníme :)


 

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 206x (11.9 MB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

Předchozí článek
Hra tetris v MonoGame: Generátor kostek
Všechny články v sekci
Od nuly k tetrisu v MonoGame
Přeskočit článek
(nedoporučujeme)
Hra Tetris v MonoGame: Zprovoznění hry
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
5 hlasů
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 se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity