Lekce 18 - Hra tetris v MonoGame: Webový klient
V minulé lekci, Hra tetris v MonoGame: Webový server, jsme si připravili jednoduchý PHP server s MySQL databází.
V dnešní bonusové lekci si ukážeme jak na tento server skóre odeslat a také jak internetové skóre v naší hře zobrazit. Tak směle do toho.
WebKlient
Po vzoru třídy SkoreKlient
si nyní vytvoříme novou třídu
WebKlient
. Ta nebude se skóre pracovat lokálně, ale přes
internet. Jinak bude fungovat úplně stejně. Rovněž bude třeba upravit
komponentu KomponentaSkoreTabulka
. A to je celé.
Třída WebKlient
bude mít metody Uloz()
,
Nacti()
a nově i Stahni()
. Přidáme
ještě konstanty pro držení URL potřebných pro uložení a načtení.
Třída bude vypadat 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 } }
Nezapomeňte si upravit 2 URL adresy na vaše skripty. Mohly by vypadat např. takto:
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 jste si určitě nového atributu typu WebClient
. Tato
.NET třída obsahuje vše potřebné pro vykonání HTTP dotazu a zabaluje je
do jednoduchých metod, které záhy použijeme. Jsou to OpenRead()
a DownloadFile()
. WebClient
je třeba naimportovat
pomocí přidání using System.Net;
mezi using
y na
začátku souboru.
Konstruktor
V třídě WebKlient
neinicializujeme proměnnou
soubor
hned při její deklaraci, ale až v konstruktoru, protože
chceme popsat cestu k souboru a vytvořit složku.
K vytvoření cesty je velmi užitečné používání metody
Path.Combine()
, která bere jednotlivé části cesty jako
parametry a vytvoří z nich jednu validní cestu k souboru či složce.
Nemusíme se tak zabývat chybějícími nebo přebývajícími lomítky a
podobně.
Další užitečná metoda je Environment.GetFolderPath()
,
která nám vrátí cestu k nějaké systémové složce. Výraz
Environment.SpecialFolder.ApplicationData
získá ze speciálních
složek složku dat aplikací. Microsoft má několik speciálních složek,
které může naše aplikace využít pro ukládání dat potřebných pro svůj
běh, např. uložené pozice ve hře, a každý uživatel počítače má pak
své vlastní.
A jako poslední v aplikační složce vytvoříme novou složku
robotris/
se souborem skore.xml
.
Ukládání
Pro uložení skóre musíme vytvořit URL s QueryString (to je ta část za
otazníkem), v němž bude přezdívka a dosažené body. Využijeme třídu
Hrac
a z ní vytáhneme vše potřebné. Pro formátování stringu
použijeme notaci $""
. Poté použijeme již zmíněnou metodu
OpenUrl()
třídy WebClient
. Celá metoda
Uloz()
bude vypadat takto:
public void Uloz(Hrac hrac) { string url = $"{urlPridat}?prezdivka={hrac.prezdivka}&body={hrac.body}&rady={hrac.rady}&level={hrac.level}"; webKlient.OpenRead(url); }
Stažení
Abychom ze serveru dostali třídu Hrac
, lépe řečeno seznam
hráčů List<Hrac>
, je nutné nejdříve získat soubor XML.
Využijeme tedy metodu DownloadFile()
na WebClient. Ta požaduje
URL, kde nalezne soubor a dále cestu, kam má soubor uložit. Metoda
Stahni()
bude vypadat takto:
public void Stahni() { webKlient.DownloadFile(urlVypsat, soubor); }
Načtení
Soubor máme stažený a teď ho ještě potřebujeme deserializovat na seznam hráčů a použít v naší tabulce.
Zbývá doplnit metodu Nacti()
. Metoda bude identická se
stejnojmennou metodou ve třídě SkoreKlient
. Pro lepší
udržitelnost a správu kódu bychom se ideálně měli vyhnout duplicitám v
logice aplikace, ale doufám že mi to pro tentokrát prominete
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še k našemu webovému klientovi. Teď zbývá jen provést změny k komponentě pro vykreslení skóre a máme hotovo
KomponentaSkoreTabulka
Zde přidáme nový atribut jménem webKlient
, který bude
držet instanci naší nové třídy:
private WebKlient webKlient;
Atribut nezapomeneme inicializovat v metodě Initialize()
:
webKlient = new WebKlient();
Ještě přidáme nový stav do výčtu eStav
a tím bude
ChybaWebu
. Tuto chybu nebudeme považovat za fatální a tedy pokud
se vyskytne, dáme uživateli vědět a zeptáme se, zda bude chtít pokus o
stažení opakovat nebo ne. Pokud zvolí ne, skóre zobrazíme pouze formou
lokálně uložených dat. Enum eStav
nyní vypadá takto:
private enum eStav { ChybaNacteni, ChybaUlozeni, ChybaWebu, Zapis, Vypis, Otazka, }
Nacti()
Změníme metodu Nacti()
, ve které přidáme stažení a
načtení skóre ze serveru a přidáme tyto hráče mezi hráče již lokálně
načtené:
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(); }
Nejprve načteme lokálně uložené hráče a pokud se vyskytne chyba, ukončíme vykonávanou metodu. Poté stáhneme data ze serveru, kde opět chytáme chybu a nakonec hráče seřadíme podle dosažených bodů.
K využítí metody řazení na seznamu OrderByDescending()
je
nutný using using System.Linq;
.
Uloz()
Ukládání provedeme pokusem o uložení na server a pokud bude pokus
neúspěšný, tak data uložíme lokálně. Nechceme přeci, aby uživatel
přišel o těžce vydřené 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()
Následuje upravení metody 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); }
Zde načteme skóre a při chybě webu nejdříve zjistíme, zda má hráč něco k uložení. Pokud nemá, tak teprve nastavíme stav na výpis, pokud není chyba webu. Tímto umožníme hráči uložit skóre, pokud nastala chyba v komunikaci se serverem.
Draw() a Update()
A dostali jsme se k závěru, kde upravíme metody Draw()
a
Update()
, ve kterých budeme reagovat na námi přidaný nový stav
ChybaWebu
:
V metodě Draw()
přidá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 metody Update()
rovněž do switch
přidáme
další pří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;
Pokud se vyskytla chyba webu, tak ji zobrazíme. A pokud uživatel nebude chtít akci opakovat, vypíšeme skóre.
PHP server
PHP server jsme si vytvořili minule a aplikaci s ním můžete nyní vyzkoušet.
C# server
Pokud jste měli problémy s PHP serverem nebo jej chcete v C#, tak slíbený
C# server je součástí kódů k této lekci. Po rozbalení je ve složce
RobotrisServer/
. Aplikace má název
robotris_web_server/
a vytvoří server, který poslouchá na
adrese a portu http://localhost:8000
. Obsahuje pouze dvě URL,
které jsou uloz
a stahnout
. Aplikace vytvoří ve
své složce XML soubor s uloženým skóre, který funguje jako "webové"
uložiště. Tento XML je neplatně formátován.
- Po dotazu
uloz
server vytáhne z QueryStringu parametryprezdivka
,body
,rady
alevel
. Parametrprezdivka
je text. Zbylé hodnoty musí být číslo. Uloží se do předem zmíněného souboru. - Po dotazu na
stahnout
se obsah předem zmíněného souboru zformátuje na platný XML a odešle. A tento soubor už v Robotrisu získáváme, ukládáme a deserializujeme.
Serverové hlášky jsou v angličtině. A vypisují se do konzole aplikace.
Toto je konec bonusové lekce o tom jak ukládat skóre na web. Pokud jste
došli až jsem tak děkuji za pozornost a v nějákem dalším tutoriálu nebo
článku nashledanou
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 24x (13.93 MB)
Aplikace je včetně zdrojových kódů v jazyce C#