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 16 - Hra tetris v MonoGame: Dokončení

V minulé lekci, Hra tetris v MonoGame: Skóre, jsme si vytvořili komponentu skóre a ukázali si jak uvést komponentu do výchozího stavu při zobrazení.

V dnešním MonoGame tutoriálu naprogramujeme ukládání a načítání výsledků a všechno hezky propojíme. Tím uzavřeme náš on-line kurz a budete mít hru hotovou se vším všudy. On-line skóre si necháme do bonusové lekce, jelikož budeme potřebovat použít další technologie a bylo by fajn nejprve dokonči hru v C# za použití ukládání skóre do XML.

Komponenta skóre využívá třídu SkoreKlient, ve které máme připravené metody pro ukládání a načítání.

Ukládání

Budeme ukládat do souboru XML s názvem skore.xml. Ale vůbec nic vám nebrání, abyste ukládali skóre dle libosti kamkoli jinam, i na server, jak si ukážeme dále.

Struktura XML souboru bude vypadat následovně

<?xml version="1.0" encoding="utf-8"?>
<hraci>
  <hrac>
    <prezdivka><!-- Sem přijde přezdívka --></prezdivka>
    <body><!-- Sem přijdou dosažené body --></body>
  </hrac>
</hraci>

V tomto formátu tedy jednotlivé instance třídy Hrac uložíme. Zdrojový kód metody Uloz() bude nyní vypadat takto:

public void Uloz(Hrac hrac)
{
    if (!File.Exists(soubor))
    {
        XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
        xmlWriterSettings.Indent = true;
        xmlWriterSettings.NewLineOnAttributes = true;
        using (XmlWriter xmlWriter = XmlWriter.Create(soubor, xmlWriterSettings))
        {
            xmlWriter.WriteStartDocument();
            xmlWriter.WriteStartElement("hraci");
            xmlWriter.WriteStartElement("hrac");
            xmlWriter.WriteElementString("prezdivka", hrac.prezdivka);
            xmlWriter.WriteElementString("body", hrac.body.ToString());
            xmlWriter.WriteEndElement();
            xmlWriter.WriteEndDocument();
            xmlWriter.Flush();
            xmlWriter.Close();
        }
    }
    else
    {
        XDocument xDocument = XDocument.Load(soubor);
        XElement koren = xDocument.Element("hraci");
        IEnumerable<XElement> polozky = koren.Descendants("hrac");
        XElement polozka = polozky.First();
        polozka.AddBeforeSelf(
           new XElement("hrac",
               new XElement("prezdivka", hrac.prezdivka),
               new XElement("body", hrac.body)));
        xDocument.Save(soubor);
    }
}

Pokud soubor neexistuje, tak jej vytvoříme a uložíme do něj první výsledek. Pokud již existuje, vyhledáme element s hráči a před posledního (prvního zapsaného) přidáme nově přidávaného. Tím budeme mít výsledky řazené podle posledního přidaného. Pokud budeme chtít řadit jinak, vyřešíme to v komponentě KomponentaSkoreTabulka. Proměnná soubor je řetězec obsahující název souboru s příponou .xml, jak jsme si ji minule nachystali.

Načítání

Načítání hráčů může vypadat např. takto:

public List<Hrac> Nacti()
{
    string element = "";
    var hrac = new Hrac();
    var hraci = new List<Hrac>();
    using (var xr = XmlReader.Create(soubor))
    {
        while (xr.Read())
        {
            if (xr.NodeType == XmlNodeType.Element)
                element = xr.Name;
            else
            if (xr.NodeType == XmlNodeType.Text)
            {
                switch (element)
                {
                    case "prezdivka":
                        hrac.prezdivka = xr.Value;
                        break;
                    case "body":
                        hrac.body = long.Parse(xr.Value);
                        break;
                }
            }
            else if ((xr.NodeType == XmlNodeType.EndElement) && (xr.Name == "hrac"))
            {
                hraci.Add(hrac);
                hrac = new Hrac();
            }
        }
    }
    return hraci;
}

Postupně načítáme ze souboru a ukládáme do seznamu, který poté vracíme. Do toho jak pracuje XmlReader, XmlWriter a XDocument zabíhat nebudu, protože jsou detailně popsané v Práce se soubory v C# .NET.

Přidání herní obrazovky

Zbývá upravit třídu Hra a přidat jí herní obrazovku obrazovkaSkore. V komponentě menu navíc upravíme co se má stát pokud uživatel bude na položce Skore a zmáčkne Enter. Kód bude vypadat následovně:

Hra.cs

public HerniObrazovka obrazovkaMenu, obrazovkaLevel, obrazovkaAutori, obrazovkaSkore; // přidáno

/* Ostatní kód */

protected override void Initialize()
{
    KomponentaMraky mraky = new KomponentaMraky(this);
    KomponentaLevel level = new KomponentaLevel(this);
    KomponentaAutori autori = new KomponentaAutori(this);
    KomponentaSkoreTabulka skoreTabulka = new KomponentaSkoreTabulka(this); // přidáno
    KomponentaPolozkyMenu polozkyMenu = new KomponentaPolozkyMenu(this, new Vector2(700, 250), Color.Red, Color.Yellow, 80);
    polozkyMenu.PridejPolozku("StArT");
    polozkyMenu.PridejPolozku("SkOrE");
    polozkyMenu.PridejPolozku("AuToRi");
    polozkyMenu.PridejPolozku("KoNeC");
    KomponentaMenu menu = new KomponentaMenu(this, polozkyMenu);

    obrazovkaMenu = new HerniObrazovka(this, mraky, menu);
    obrazovkaLevel = new HerniObrazovka(this, mraky, level);
    obrazovkaMenu = new HerniObrazovka(this, mraky, menu, polozkyMenu);
    obrazovkaAutori = new HerniObrazovka(this, mraky, autori);
    obrazovkaSkore = new HerniObrazovka(this, mraky, skoreTabulka); // přidáno

    foreach (GameComponent komponenta in Components)
    {
        PrepniKomponentu(komponenta, false);
    }
    graphics.PreferredBackBufferWidth = sirkaOkna;
    graphics.PreferredBackBufferHeight = vyskaOkna;
    graphics.IsFullScreen = false;
    graphics.ApplyChanges();
    base.Initialize();
}

KomponentaMenu.cs

public override void Update(GameTime gameTime)
{
    // enter - akce podle vybrané položky
    if (hra.NovaKlavesa(Keys.Enter))
    {
        switch (polozkyMenu.vybranaPolozka.text)
        {
            case "StArT":
                hra.PrepniObrazovku(hra.obrazovkaLevel);
                hra.PrepniHudbu(hra.hudba_zardax);
                break;
            case "SkOrE":
                hra.PrepniObrazovku(hra.obrazovkaSkore);
                break;
            case "AuToRi":
                hra.PrepniObrazovku(hra.obrazovkaAutori);
                break;
            case "KoNeC":
                hra.Exit();
                break;
        }
    }
    base.Update(gameTime);
}

KomponentaLevel.cs

/* Update skce pro vytvoření nové kostky */
if (hraciPlocha.Kolize(kostka, kostka.pozice))
    hra.PrepniObrazovku(hra.obrazovkaSkore);

Po těchto úpravách již bude možné uložení skóre po skončení hry. Určitě si ale povšimnete malé nedokonalosti a to že pokud chceme z menu zobrazit tabulku skóre, tak se nám zobrazí otázka, zda chceme uložit skóre. To je samozřejmě špatně, protože jsme hru dosud nehráli a současně by se nám uložil pokaždé hráč, který nemá žádné body. Oprava nezabere moc času ani úsilí. Upravíme komponentu skóre, aby když hráč nebude mít body, tak rovnou nastavíme stav na výpis a nikoli na otázku. To vše obstará jedna podmínka v try bloku v metodě OnEnabledChanged(). Bude vypadat takto:

if (hra.hrac != null && hra.hrac.body > 0)
    stav = eStav.Otazka;
else
    stav = eStav.Vypis;

Toto byla malá úprava, abychom odchytili poslední nedostatek, který rušil jinak pěkný zážitek ze hry.

Kompletní kódy jsou přiloženy jako vždy. Hru máme kompletní se všemi funkcionalitami, které jsme chtěli :).

Příště, v lekci Hra tetris v MonoGame: Webový server, na vás čeká on-line skóre tabulka.


 

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 495x (13.23 MB)

 

Předchozí článek
Hra tetris v MonoGame: Skóre
Všechny články v sekci
Od nuly k tetrisu v MonoGame
Přeskočit článek
(nedoporučujeme)
Hra tetris v MonoGame: Webový server
Článek pro vás napsal Matouš Kratochvíl
Avatar
Uživatelské hodnocení:
1 hlasů
Autor se věnuje C#
Aktivity