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

12. diel - MonoGame: Správa herných obrazoviek

V minulej lekcii, Hra tetris v MonoGame: Vychytávky v leveli , sme do levelu s Tetris pridali vylepšenou rotáciu a zameriavač. Tým pre nás Tetrisování končí a budeme hru považovať za hotovú. Vy si tam samozrejme môžete dodať ďalšie power-upy, herné módy a podobne. Dnes sa zameriame na herné obrazovky, vďaka ktorým budeme potom schopní vytvoriť napr. Herné menu.

Herné obrazovka

Vieme, že MonoGame nie je engine, ale framework. Preto MonoGame samotná okrem komponentov neposkytuje žiadny spôsob, ako sa vysporiadať s prepínaním herných obrazoviek. Herný obrazovkou myslím nejakú samostatnú časť hry, treba level, menu, skóre tabuľku, obrazovku autori a podobne. Hlavné menu bude mať určite inú logiku, než level s Tetris. Navyše treba docieliť to, aby sme herné obrazovky môžete prepínať a ukladať ich stav.

Možností je samozrejme veľa. Úplne tá najhlúpejší je napísať celú hru do jedného súboru a urobiť veľa stavov (stav pre menu, stav pre hru a tak). Výsledný súbor by ale asi nevyzeral úplne pekne a keď vieme používať herné komponenty, určite ich využijeme. Občas som videl spôsob, kedy je čo obrazovka, to komponenta. Komponenty sa potom medzi sebou prepínajú (napr. Z komponenty Menu do komponenty Level). Pre malé hry to môže byť dostačujúce, ale pre väčšie projekty už nie. Problém je v tom, že sme obmedzení na 1 komponent pre každú obrazovku, nemohli by sme mať napr. V tetrisu oddelenej Mraky a Level, prípadne ešte nejaké ďalšie súčasti, ktoré by sa vo zložitejšie hre našli.

Riešenie, ktoré si tu ukážeme, definuje herné obrazovku ako súbor komponentov. Do hry sú vložené všetky komponenty a pri prepnutí obrazovky sa zakážu a povoľujú sa len tie, ktoré používa konkrétny obrazovka.

Pridajme si k projektu triedu HerniObrazovka. Jej inštancie budú reprezentovať jednotlivé herné obrazovky. Triedu si nastavte ako public. Bude mať 2 privátne atribúty, jeden bude kolekcia komponentov, ktoré obrazovka obsahuje. Druhý inštancie Hry:

private List<GameComponent> komponenty;
private Hra hra;

Kvôli použitie typu GameComponent dodáme nad triedu using:

using Microsoft.Xna.Framework;

Pridáme verejnú metódu PridejKomponentu(), ktorá komponent odovzdanú v parametri vloží do internej kolekcie komponenty a zároveň aj do kolekcie Components hry. Do Components sa musí komponent vložiť iba vtedy, keď tam už nie je. Niektoré obrazovky totiž využívajú rovnaké komponenty. Metóda vyzerá takto:

public void PridejKomponentu(GameComponent komponenta)
{
    komponenty.Add(komponenta);
    if (!hra.Components.Contains(komponenta))
        hra.Components.Add(komponenta);
}

Vďaka tomu, že je list privátne, všetky pridanie prebehnú cez túto metódu a môžeme si byť istí, že budú dané komponenty aj v Components hry.

V konstruktoru triedy si odovzdáme v parametri inštancii hry tak, ako sme zvyknutí z komponentov a herných objektov. Ďalej pomocou kľúčového slova params umožníme vložiť niekoľko parametrov typu GameComponent. Tie proiterujeme a pridáme pomocou našej metódy.

public HerniObrazovka(Hra hra, params GameComponent[] komponenty)
{
    this.hra = hra;
    this.komponenty = new List<GameComponent>();
    foreach (GameComponent komponenta in komponenty)
    {
        PridejKomponentu(komponenta);
    }
}

Ako posledný pridáme metódu VratKomponenty(), ktorá vráti komponenty v obrazovke ako pole:

public GameComponent[] VratKomponenty()
{
    return komponenty.ToArray();
}

Pre úplnosť si môžete napísať metódu pre vymazanie komponenty, v nejakej zložitejšie hre by sa mohli za behu pridávať a odoberať, ale pre naše účely to nie je nutné.

Menu

Aby sme mali na čom testovať, pridáme si k hre komponent KomponentaMenu (do zložky Komponenty/, ale namespace ponechajte iba na Robotris). Bude sa opäť jednať o DrawableComponent, ako ju pridať sme si ukázali v tutoriálu Rozdelenie MonoGame hry do komponentov. Pre istotu si ukážeme aj kód triedy:

public class KomponentaMenu : Microsoft.Xna.Framework.DrawableGameComponent
{

        private Hra hra;

        public KomponentaMenu(Hra hra)
                : base(hra)
        {
                this.hra = hra;
        }

        public override void Initialize()
        {
                base.Initialize();
        }

        protected override void LoadContent()
        {
                base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
                base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
                base.Draw(gameTime);
        }
}

Komponent zatiaľ ponecháme prázdnu.

Obsluha herných obrazoviek

Samotnú obsluhu herných obrazoviek vložíme do triedy Hra. Docela mi to dáva zmysel a je jednoducho viditeľná zo všetkých komponentov. Ďalšia možnosť by bola vytvoriť nejaký manažér obrazoviek.

Presunieme sa do Hra.cs, kde do atribútov triedy pridáme 2 verejné herné obrazovky, budú to obrazovky pre menu a pre level:

public HerniObrazovka obrazovkaMenu, obrazovkaLevel;

Do Initialize() pridáme k vytvoreniu komponentov aj vytvorenie komponenty menu:

KomponentaMenu menu = new KomponentaMenu(this);

Pripojenie komponentov k hre do kolekcie Components úplne odstránime, pretože to za nás robí herné obrazovka. Namiesto toho si vytvoríme herné obrazovky:

obrazovkaMenu = new HerniObrazovka(this, mraky, menu);
obrazovkaLevel = new HerniObrazovka(this, mraky, level);

Vidíme, že môžeme použiť tú istú komponent Mraky vo viacerých obrazovkách.

Pridáme privátne metódu na prepnutie stavu obrazovky. Ako parameter bude brať komponent a stav (zapnuté / vypnuté). GameComponent v MonoGame má vlastnosť Enabled, ktorá umožňuje zapínať / vypínať vykonávanie metódy Update(). Pokiaľ ho vypneme, komponenta sa zastaví. Ak je komponent ešte typu DrawableGameComponent (čo takmer vždy bude), nastavíme aj vlastnosť Visible. Tá udáva, či sa má vykonávať metóda Draw() a teda či sa má komponta vykresľovať.

private void PrepniKomponentu(GameComponent komponenta, bool zapnout)
{
    komponenta.Enabled = zapnout;
    if (komponenta is DrawableGameComponent)
        ((DrawableGameComponent)komponenta).Visible = zapnout;
}

Keď takto komponent vypneme, nebude sa vykresľovať ani obsluhovať. Stále však existuje a keď ju potom zapneme, bude presne v stave, v akom sme ju nechali. To sa nám niekedy môže hodiť (napr. Prechod medzi rôznymi lokáciami, mini hrami, z menu do hry atď.).

Vrátime sa do Initialize(), po vytvorení obrazoviek proiterujeme všetky komponenty hry a vypneme je:

foreach (GameComponent komponenta in Components)
{
    PrepniKomponentu(komponenta, false);
}

Nakoniec pridáme samotnú metódu na prepnutie obrazovky. Bude verejná a ako parameter bude brať obrazovku, do ktorej sa chceme prepnúť.

public void PrepniObrazovku(HerniObrazovka obrazovka)
{
}

Najprv si z obrazovky vyžiadame komponenty, ktoré obsahuje:

GameComponent[] povolene = obrazovka.VratKomponenty();

Proiterujeme komponenty hry a zistíme, či je daná komponenta povolená. To urobíme tak, že sa ju pokúsime vyhľadať v poli povolených komponentov. Nakoniec komponent nastavíme na požadovaný stav.

foreach (GameComponent komponenta in Components)
{
    bool povolena = povolene.Contains(komponenta);
    PrepniKomponentu(komponenta, povolena);
}

V metóde ešte updatuje minulý stav klávesov, pretože prepnutie komponentov má za následok jeho vynechanie:

klavesyMinule = klavesy;

Na koniec metódy LoadContent() pridáme prepnutie obrazovky (nastane až vo chvíli, keď bude všetko načítané):

PrepniObrazovku(obrazovkaMenu);

Keď hru teraz spustíme, mali by sme vidieť menu, ktoré je predstavované zatiaľ len mraky.

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

Presunieme sa do KomponentaMenu a pridáme do Update() reakciu na Enter, ktorá nás presunie do hry:

if (hra.NovaKlavesa(Keys.Enter))
                hra.PrepniObrazovku(hra.obrazovkaLevel);

Vyskúšame a vidíme, že sme naprogramovali prepínanie obrazoviek. Nabudúce, v lekcii MonoGame: Herné menu , sa zameriame na menu :)


 

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

 

Predchádzajúci článok
Hra tetris v MonoGame: Vychytávky v leveli
Všetky články v sekcii
Od nuly k tetrisu v MonoGame
Preskočiť článok
(neodporúčame)
MonoGame: Herné menu
Č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