IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

18. diel - Hra tetris v MonoGame: Webový klient

V minulej lekcii, Hra tetris v MonoGame: Webový server , sme si pripravili jednoduchý PHP server s MySQL databázou. V dnešnej bonusovej lekcii si ukážeme ako na tento server skóre odoslať a tiež ako internetové skóre v našej hre zobraziť. Tak smelo do toho.

WebKlient

Po vzore triedy SkoreKlient si teraz vytvoríme novú triedu WebKlient. Tá nebude sa skóre pracovať lokálne, ale cez internet. Inak bude fungovať úplne rovnako. Rovnako bude potrebné upraviť komponent KomponentaSkoreTabulka. A to je celé.

Trieda WebKlient bude mať metódy Uloz(), Nacti() a novo i Stahni(). Pridáme ešte konštanty pre držanie URL potrebných pre uloženie a načítanie.

Trieda bude vyzerať takto:

public class WebKlient
{
    public string ChybaNacitani => $"Chyba při načítání skóre z internetu.";

    // přidáno
    private WebClient webKlient;
    private const string urlPridat = "http://localhost:8000/uloz";
    private const string urlVypsat = "http://localhost:8000/stahnout";


    private string soubor;

    public WebKlient()
    {
        webKlient = new WebClient();
        soubor = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"robotris\skore.xml");
            Directory.CreateDirectory(System.IO.Path.GetDirectoryName(soubor));
    }

    public void Uloz(Hrac hrac)
    {
        // Doplníme později
    }

    public void Stahni()
    {
        // Doplníme později
    }

    public List<Hrac> Nacti()
    {
        // Doplníme později
    }

}

Nezabudnite si upraviť 2 URL adresy na vaše skripty. Mohli by vyzerať napr. Nasledovne:

private const string urlPridat = "https://www.mujweb.cz/robotris_skore_uloz.php";
private const string urlVypsat = "https://www.mujweb.cz/robotris_skore_nacti.php";

Všimli ste si určite nového atribútu typu WebClient. Táto .NET trieda obsahuje všetko potrebné pre vykonanie HTTP dotazu a zábalom ich do jednoduchých metód, ktoré vzápätí použijeme. Sú to OpenRead() a DownloadFile(). WebClient treba naimportovať pomocou pridanie using System.Net; medzi using y na začiatku súboru.

Konštruktor

V triede WebKlient neinicializujú premennú soubor hneď pri jej deklarácii, ale až v konstruktoru, pretože chceme opísať cestu k súboru a vytvoriť priečinok.

K vytvoreniu cesty je veľmi užitočné používanie metódy Path.Combine(), ktorá berie jednotlivé časti cesty ako parametre a vytvorí z nich jednu validný cestu k súboru či zložke. Nemusíme sa tak zaoberať chýbajúcimi alebo Zotrvávajúcim lomítkami a podobne.

Ďalšia užitočná metóda je Environment.GetFolderPath(), ktorá nám vráti cestu k nejakej systémovej zložke. Výraz Environment.SpecialFolder.ApplicationData získa zo špeciálnych zložiek zložku dát aplikácií. Microsoft má niekoľko špeciálnych zložiek, ktoré môže naše aplikácie využiť na ukladanie dát potrebných pre svoj beh, napr. Uloženej pozície v hre, a každý užívateľ počítača má potom svoje vlastné.

A ako posledný v aplikačnej zložke vytvoríme novú zložku robotris/ so súborom skore.xml.

Ukladanie

Pre uloženie skóre musíme vytvoriť URL s QueryString (to je tá časť za otáznikom), v ktorom bude prezývka a dosiahnuté body. Využijeme triedu Hrac az nej vytiahneme všetko potrebné. Pre formátovanie stringu použijeme notáciu $"". Potom použijeme už spomínanú metódu OpenUrl() triedy WebClient. Celá metóda Uloz() bude vyzerať takto:

public void Uloz(Hrac hrac)
{
    string url = $"{urlPridat}?prezdivka={hrac.prezdivka}&body={hrac.body}&rady={hrac.rady}&level={hrac.level}";
    webKlient.OpenRead(url);
}

Stiahnutie

Aby sme zo servera dostali triedu Hrac, lepšie povedané zoznam hráčov List<Hrac>, je nutné najskôr získať súbor XML. Využijeme teda metódu DownloadFile() na WebClient. Tá požaduje URL, kde nájde súbor a ďalej cestu, kam má súbor uložiť. Metóda Stahni() bude vyzerať takto:

public void Stahni()
{
    webKlient.DownloadFile(urlVypsat, soubor);
}

Načítanie

Súbor máme stiahnutý a teraz ho ešte potrebujeme deserializovat na zoznam hráčov a použiť v našej tabuľke.

Zostáva doplniť metódu Nacti(). Metóda bude identická s rovnomennou metódou v triede SkoreKlient. Pre lepšiu udržateľnosť a správu kódu by sme sa ideálne mali vyhnúť duplicite v logike aplikácie, ale dúfam že mi to pre tentokrát prepáčite :)

public List<Hrac> Nacti()
{
    string element = "";
    Hrac hrac = new Hrac();
    List<Hrac> hraci = new List<Hrac>();
    // parsování XML
    using (XmlReader xr = XmlReader.Create(soubor))
    {
        // postupné načítání uzlů
        while (xr.Read())
        {
            // uzel typu element
            if (xr.NodeType == XmlNodeType.Element)
                element = xr.Name;  // uložení jména elementu
            else
                if (xr.NodeType == XmlNodeType.Text) // uzel typu text
                {
                    switch (element)
                    {
                        case "prezdivka":
                            hrac.prezdivka = xr.Value;
                            break;
                        case "body":
                            hrac.body = long.Parse(xr.Value);
                            break;
                    }
                }
            // konec elementu hráč
                else if ((xr.NodeType == XmlNodeType.EndElement) && (xr.Name == "hrac"))
                {
                    hraci.Add(hrac);
                    hrac = new Hrac();
                }
        }
    }
    return hraci;
}

To je všetko k internetovému klientovi. Teraz zostáva len vykonať zmeny k komponente pre vykreslenie skóre a máme hotovo

KomponentaSko­reTabulka

Tu pridáme nový atribút menom webKlient, ktorý bude držať inštanciu našej novej triedy:

private WebKlient webKlient;

Atribút nezabudneme inicializovať v metóde Initialize():

webKlient = new WebKlient();

Ešte pridáme nový stav do zoznamu eStav a tým bude ChybaWebu. Túto chybu nebudeme považovať za fatálne a teda ak sa vyskytne, dáme užívateľovi vedieť a spýtame sa, či bude chcieť pokus o stiahnutie opakovať alebo nie. Ak zvolí nie, skóre zobrazíme iba formou lokálne uložených dát. Enum eStav teraz vyzerá takto:

private enum eStav
{
    ChybaNacteni,
    ChybaUlozeni,
    ChybaWebu,
    Zapis,
    Vypis,
    Otazka,
}

Nacitaj ()

Zmeníme metódu Nacti(), v ktorej pridáme stiahnutie a načítanie skóre zo servera a pridáme týchto hráčov medzi hráčov už lokálne načítané:

public void Nacti()
{
    stav = eStav.Vypis;
    hraci = new List<Hrac>();

    try
    {
        var xmlHraci = klient.Nacti();

        hraci.AddRange(xmlHraci);

    }
    catch
    {
        stav = eStav.ChybaNacteni;
        return;
    }

    try
    {
        webKlient.Stahni();
        var webHraci = webKlient.Nacti();

        hraci.AddRange(webHraci);
    }
    catch
    {
        stav = eStav.ChybaWebu;
    }

    hraci = hraci.OrderByDescending(x => x.body).ToList();
}

Najprv načítame lokálne uložené hráčov a ak sa vyskytne chyba, ukončíme vykonávanú metódu. Potom stiahneme dáta zo servera, kde opäť chytáme chybu a nakoniec hráča zoradíme podľa dosiahnutých bodov.

K využitie metódy radenia na zozname OrderByDescending() je nutný using using System.Linq;.

Uloz ()

Ukladanie vykonáme pokusom o uložení na server a ak bude pokus neúspešný, tak dáta uložíme lokálne. Nechceme predsa, aby užívateľ prišiel o ťažko vydreté body :)

public void Uloz()
{
    try
    {
        webKlient.Uloz(hra.hrac);
        Nacti();
        stav = eStav.Vypis;
    }
    catch
    {
        try
        {
            klient.Uloz(hra.hrac);
            hraci = klient.Nacti();
            stav = eStav.Vypis;
        }
        catch
        {
            stav = eStav.ChybaUlozeni;
        }
    }
}

OnEnabledChanged ()

Nasleduje upravenie metódy OnEnabledChanged():

protected override void OnEnabledChanged(object sender, EventArgs args)
{
    if (Enabled)
    {
        Nacti();
        // Pokud budeme ve stavu chyba přeskočíme
        if (!(stav == eStav.ChybaNacteni || stav == eStav.ChybaUlozeni))
        {
            // Rovnou na vypis pokud nejsou body
            if (hra.hrac != null && hra.hrac.body > 0)
                stav = eStav.Otazka;
            else
                if (stav != eStav.ChybaWebu)
                    stav = eStav.Vypis;
        }
    }
    base.OnEnabledChanged(sender, args);
}

Tu načítame skóre a pri chybe webu najprv zistíme, či má hráč niečo na uloženie. Pokiaľ nemá, tak ešte len nastavíme stav na výpis, pokiaľ nie je chyba webu. Týmto umožníme hráči uložiť skóre, ak nastala chyba v komunikácii so serverom.

Draw () a Update ()

A dostali sme sa k záveru, kde upravíme metódy Draw() a Update(), v ktorých budeme reagovať na nami pridaný nový stav ChybaWebu:

V metóde Draw() pridáme do switch:

// vykreslení chyby webu
case eStav.ChybaWebu:
    hra.spriteBatch.TextSeStinem(hra.fontCourierNew, $"{webKlient.ChybaNacitani} \n Zkusit znovu? [A/N]", new Vector2(510, 240), Color.Red);
    break;

A do metódy Update() rovnako do switch pridáme ďalší prípad:

// dotaz při chybě skore na web
case eStav.ChybaWebu:
    if (hra.NovaKlavesa(Keys.A))
        Nacti();
    if (hra.NovaKlavesa(Keys.N))
        stav = eStav.Vypis;
        break;

Ak sa vyskytla chyba webu, tak ju zobrazíme. A ak užívateľ nebude chcieť akciu opakovať, vypíšeme skóre.

Php server

PHP server sme si vytvorili minule a aplikáciu s ním môžete teraz vyskúšať.

C # server

Ak ste mali problémy s PHP serverom alebo ho chcete v C #, tak sľúbený C# server je súčasťou kódov k tejto lekcii. Po rozbalení je v priečinku RobotrisServer/. Aplikácia má názov robotris_web_server/ a vytvorí server, ktorý počúva na adrese a porte http://localhost:8000. Obsahuje iba dve URL, ktoré sú uloz a stahnout. Aplikácia vytvorí vo svojej zložke XML súbor s uloženým skóre, ktorý funguje ako "webové" úložisko. Tento XML je neplatne formátovaný.

  • Po dotazu uloz server vytiahne z QueryStringu parametre prezdivka, body, rady a level. Parameter prezdivka je text. Zvyšné hodnoty musí byť číslo. Uloží sa do vopred spomínaného súboru.
  • Po otázke na stahnout sa obsah vopred spomínaného súboru sformátuje na platný XML a odošle. A tento súbor už v Robotrisu získavame, ukladáme a deserializujeme.

Serverové hlášky sú v angličtine. A vypisujú sa do konzoly aplikácie.

Toto je koniec bonusové lekcie o tom, ako ukladať skóre na web. Ak ste došli až som tak ďakujem za pozornosť a v nejakom ďalšom tutoriálu alebo článku dovidenia :)


 

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

 

Predchádzajúci článok
Hra tetris v MonoGame: Webový server
Všetky články v sekcii
Od nuly k tetrisu v MonoGame
Článok pre vás napísal Matouš Kratochvíl
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje C#
Aktivity