Cvičení – logika hry
V tomto cvičení přidáme do naší aplikace logiku hry, abychom zajistili, že skončíme plně funkční hrou.
Abychom vám pomohli udržet tento kurz na téma s výukou o Blazoru, poskytujeme třídu s názvem GameState
, která obsahuje logiku pro správu hry.
Přidání stavu hry
Pojďme do projektu přidat GameState
třídu a pak ji zpřístupnit komponentám jako jednoúčelovou službu prostřednictvím injektáže závislostí.
Zkopírujte soubor GameState.cs do kořenového adresáře projektu.
Otevřete soubor Program.cs v kořenovém adresáři projektu a přidejte tento příkaz, který se ve vaší aplikaci konfiguruje
GameState
jako jednoúčelová služba:builder.Services.AddSingleton<GameState>();
Teď můžeme do naší
Board
komponenty vložit instanciGameState
třídy.Na začátek souboru Board.razor přidejte následující
@inject
direktivu. směrnice vloží aktuální stav hry do komponenty:@inject GameState State
Teď můžeme začít připojovat naši
Board
komponentu ke stavu hry.
Resetování stavu
Začněme resetováním stavu hry, když Board
je komponenta poprvé namalována na obrazovce. Přidejte kód pro resetování stavu hry při inicializaci komponenty.
Přidejte metodu s voláním
OnInitialized
ResetBoard
, uvnitř@code
bloku v dolní části souboru Board.razor , například takto:@code { protected override void OnInitialized() { State.ResetBoard(); } }
Když se panel poprvé zobrazí uživateli, stav se obnoví na začátek hry.
Vytváření herních kousků
V dalším kroku přidělme možné 42 herních kusů, které by se daly hrát. Herní části můžeme reprezentovat jako pole odkazované 42 prvky HTML na panelu. Tyto části můžeme přesunout a umístit tak, že přiřadíme sadu tříd CSS s pozicemi sloupců a řádků.
Abychom mohli uchovávat herní kousky, definujeme pole pole řetězců v bloku kódu:
private string[] pieces = new string[42];
Do oddílu HTML přidejte kód, který vytvoří 42
span
značek, jeden pro každou část hry ve stejné komponentě:@for (var i = 0; i < 42; i++) { <span class="@pieces[i]"></span> }
Celý kód by měl vypadat takto:
<div> <div class="board"> @for (var i = 0; i < 42; i++) { <span class="container"> <span></span> </span> } </div> @for (var i = 0; i < 42; i++) { <span class="@pieces[i]"></span> } </div> @code { private string[] pieces = new string[42]; protected override void OnInitialized() { State.ResetBoard(); } }
Tím se přiřadí prázdný řetězec třídě CSS každého herního rozsahu. Prázdný řetězec pro třídu CSS zabraňuje zobrazení herních částí na obrazovce, protože na ně není použit žádný styl.
Zpracování umístění herního kusu
Pojďme přidat metodu pro zpracování, když hráč umístí kus do sloupce. Třída GameState
ví, jak přiřadit správný řádek pro herní kus a hlásí řádek, ve které se dostane. Tyto informace můžeme použít k přiřazení tříd CSS představujících barvu hráče, konečné umístění kusu a animaci pro přetažení CSS.
Tuto metodu PlayPiece
nazýváme a přijímá vstupní parametr, který určuje sloupec, který hráč zvolí.
Přidejte tento kód pod
pieces
pole, které jsme definovali v předchozím kroku.private void PlayPiece(byte col) { var player = State.PlayerTurn; var turn = State.CurrentTurn; var landingRow = State.PlayPiece(col); pieces[turn] = $"player{player} col{col} drop{landingRow}"; }
PlayPiece
Kód dělá takto:
- Řekneme stavu hry, aby hrál kus v odeslaném sloupci volané
col
a zachytit řádek, do který kus přistál. - Pak můžeme definovat tři třídy CSS, které se mají přiřadit k herní části, abychom identifikovali, který hráč právě působí, sloupec, do kterého byla část umístěna, a cílový řádek.
- Poslední řádek metody přiřadí tyto třídy k této hře v
pieces
poli.
Pokud se podíváte do zadaného Board.razor.css, najdete třídy CSS odpovídající sloupec, řádek a hráč otočit.
Výsledným efektem je, že herní kus je umístěn ve sloupci a animovaný, aby se při zavolání této metody dostal do dolního řádku nejvíce.
Výběr sloupce
Dále musíme umístit některé ovládací prvky, které hráčům umožňují vybrat sloupec a volat novou PlayPiece
metodu. Pomocí znaku "🔽" označujeme, že můžete v tomto sloupci vložit kus.
Nad počáteční
<div>
značku přidejte řádek tlačítek, na která můžete kliknout:<nav> @for (byte i = 0; i < 7; i++) { var col = i; <span title="Click to play a piece" @onclick="() => PlayPiece(col)">🔽</span> } </nav>
Atribut
@onclick
určuje obslužnou rutinu události události pro událost kliknutí. Aby bylo možné zpracovávat události uživatelského rozhraní, musí se komponenta Blazor vykreslit pomocí interaktivního režimu vykreslování. Ve výchozím nastavení se komponenty Blazor vykreslují staticky ze serveru. Interaktivní režim vykreslování můžeme použít u komponenty pomocí atributu@rendermode
.Aktualizujte komponentu
Board
Home
na stránce tak, aby používalaInteractiveServer
režim vykreslování.<Board @rendermode="InteractiveServer" />
Režim
InteractiveServer
vykreslování zpracovává události uživatelského rozhraní pro komponenty ze serveru přes připojení WebSocket s prohlížečem.Spusťte aplikaci s těmito změnami. Teď by měl vypadat takto:
Ještě lepší je, že když vybereme jedno z tlačítek pro přetažení v horní části, můžete pozorovat následující chování:
Pěkně jste pokročili! Teď můžeme přidat kusy na desku. Objekt GameState
je dostatečně chytrý, aby se mezi těmito dvěma hráči otočil dopředu a zpět. Pokračujte a vyberte další tlačítka pro vkládání a podívejte se na výsledky.
Vítězné zpracování a zpracování chyb
Pokud hru hrajete v aktuální konfiguraci, zjistíte, že při pokusu o vložení příliš mnoho kusů do stejného sloupce a když jeden hráč vyhraje hru.
Pojďme zjasnit aktuální stav naší hry přidáním některých indikátorů zpracování chyb a indikátorů na náš panel. Přidejte nad panel a pod tlačítka pro vkládání stavovou oblast.
Za prvek vložte následující kód
nav
:<article> @winnerMessage <button style="@ResetStyle" @onclick="ResetGame">Reset the game</button> <br /> <span class="alert-danger">@errorMessage</span> <span class="alert-info">@CurrentTurn</span> </article>
Tento kód nám umožňuje zobrazit indikátory pro:
- Oznámení vítěze hry
- Tlačítko, které nám umožňuje restartovat hru
- Chybové zprávy
- Otočení aktuálního hráče
Teď vyplníme určitou logiku, která tyto hodnoty nastaví.
Za pole částí přidejte následující kód:
private string[] pieces = new string[42]; private string winnerMessage = string.Empty; private string errorMessage = string.Empty; private string CurrentTurn => (winnerMessage == string.Empty) ? $"Player {State.PlayerTurn}'s Turn" : ""; private string ResetStyle => (winnerMessage == string.Empty) ? "display: none;" : "";
- Vlastnost
CurrentTurn
se automaticky vypočítá na základě stavuwinnerMessage
aPlayerTurn
vlastnosti objektuGameState
. - Vypočítá se
ResetStyle
na základě obsahuWinnerMessage
. Pokud sewinnerMessage
objeví tlačítko pro resetování, zobrazí se na obrazovce.
- Vlastnost
Pojďme zpracovat chybovou zprávu při přehrávání kusu. Přidejte řádek pro vymazání chybové zprávy a pak kód v
PlayPiece
metodě zabalte blokemtry...catch
, který nastavíerrorMessage
, pokud došlo k výjimce:errorMessage = string.Empty; try { var player = State.PlayerTurn; var turn = State.CurrentTurn; var landingRow = State.PlayPiece(col); pieces[turn] = $"player{player} col{col} drop{landingRow}"; } catch (ArgumentException ex) { errorMessage = ex.Message; }
Náš indikátor obslužné rutiny chyby je jednoduchý a používá architekturu CSS bootstrap k zobrazení chyby v režimu nebezpečí.
V dalším kroku přidáme metodu
ResetGame
, kterou naše tlačítko aktivuje k restartování hry. Jediným způsobem, jak restartovat hru, je v současné době aktualizovat stránku. Tento kód nám umožňuje zůstat na stejné stránce.void ResetGame() { State.ResetBoard(); winnerMessage = string.Empty; errorMessage = string.Empty; pieces = new string[42]; }
Naše
ResetGame
metoda teď má následující logiku:- Resetujte stav panelu.
- Skryjte naše indikátory.
- Obnovte pole částí na prázdnou matici 42 řetězců.
Tato aktualizace by nám měla umožnit hrát hru znovu, a teď vidíme indikátor přímo nad deskou deklarující otočení hráče a nakonec dokončení hry.
Stále máme situaci, kdy nemůžeme vybrat tlačítko resetování. Pojďme do metody přidat nějakou logiku
PlayPiece
, která detekuje konec hry.Pojďme zjistit, jestli je ve hře vítěz, a to přidáním výrazu switch za blok
try...catch
vPlayPiece
souboru .winnerMessage = State.CheckForWin() switch { GameState.WinState.Player1_Wins => "Player 1 Wins!", GameState.WinState.Player2_Wins => "Player 2 Wins!", GameState.WinState.Tie => "It's a tie!", _ => "" };
Metoda
CheckForWin
vrátí výčt, který hlásí, který hráč, pokud některý z hráčů vyhrál hru nebo pokud je hra vázaná. Tento výraz přepínače nastavíwinnerMessage
pole odpovídajícím způsobem, pokud dojde ke stavu hry.Když teď hrajeme a dostaneme se ke scénáři ukončení hry, zobrazí se tyto indikátory:
Shrnutí
Dozvěděli jsme se hodně o Blazoru a vytvořili jsme čistou hru. Tady jsou některé dovednosti, které jsme se naučili:
- Vytvoření komponenty
- Přidání této komponenty na domovskou stránku
- Použití injektáže závislostí ke správě stavu hry
- Interaktivní hra s obslužnými rutinami událostí pro umístění kusů a resetování hry
- Napsal(a) obslužnou rutinu chyby pro hlášení stavu hry.
- Přidání parametrů do naší komponenty
Projekt, který jsme vytvořili, je jednoduchá hra a s ní můžete dělat mnohem víc. Hledáte nějaké výzvy ke zlepšení?
Výzvy
Vezměte v úvahu následující výzvy:
- Pokud chcete aplikaci zmenšit, odeberte výchozí rozložení a další stránky.
- Vylepšete parametry komponenty, abyste mohli předat libovolnou platnou
Board
hodnotu barvy CSS. - Vylepšete vzhled indikátorů pomocí některých rozložení CSS a HTML.
- Představte si zvukové efekty.
- Přidání vizuálního indikátoru a zabránění použití tlačítka pro přetažení, když je sloupec plný.
- Přidejte síťové funkce, abyste mohli v prohlížeči přehrát přítele.
- Vložte hru do .NET MAUI s aplikací Blazor a hrajte ji na telefonu nebo tabletu.
Šťastné kódování a bavte se!