Oefening: gamelogica
In deze oefening voegen we gamelogica toe aan onze app om ervoor te zorgen dat we uiteindelijk een volledig functionerend spel hebben.
Om deze zelfstudie on-topic te houden met lesgeven over Blazor, bieden we een klasse GameState die de logica bevat voor het beheren van het spel.
Gamestatus toevoegen
We gaan de GameState klasse toevoegen aan uw project en deze vervolgens beschikbaar maken voor onderdelen als een singleton-service via afhankelijkheidsinjectie.
Kopieer het GameState.cs bestand naar de hoofdmap van uw project.
Open het Program.cs-bestand in de hoofdmap van het project en voeg deze instructie toe waarmee
GameStateals een singleton-service in uw app wordt geconfigureerd:builder.Services.AddSingleton<GameState>();We kunnen nu een exemplaar van de
GameStateklasse in onsBoardonderdeel injecteren.Voeg de volgende
@injectinstructie toe bovenaan het Board.razor-bestand . de richtlijn injecteert de huidige status van het spel in het onderdeel:@inject GameState StateWe kunnen nu beginnen met het verbinden van ons
Boardonderdeel met de status van het spel.
Status opnieuw instellen
Laten we beginnen met het opnieuw instellen van de status van het spel wanneer het onderdeel voor het eerst op het Board scherm wordt geschilderd. Voeg code toe om de status van de game opnieuw in te stellen wanneer het onderdeel wordt geïnitialiseerd.
Voeg een
OnInitializedmethode toe met een aanroep naarResetBoard, in het@codeblok onderaan het Board.razor-bestand , zoals:@code { protected override void OnInitialized() { State.ResetBoard(); } }Wanneer het bord voor het eerst aan een gebruiker wordt getoond, wordt de status opnieuw ingesteld op het begin van een game.
Game-onderdelen maken
Vervolgens gaan we de mogelijke 42 spelstukken toewijzen die kunnen worden gespeeld. We kunnen de spelstukken vertegenwoordigen als een matrix waarnaar wordt verwezen door 42 HTML-elementen op het bord. We kunnen deze onderdelen verplaatsen en plaatsen door een set CSS-klassen met kolom- en rijposities toe te wijzen.
Om onze spelonderdelen te bewaren, definiëren we een tekenreeksmatrixveld in het codeblok:
private string[] pieces = new string[42];Voeg code toe aan de HTML-sectie waarmee 42
spantags, één voor elk spelstuk, in hetzelfde onderdeel worden gemaakt:@for (var i = 0; i < 42; i++) { <span class="@pieces[i]"></span> }Uw volledige code moet er als volgt uitzien:
<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(); } }Hiermee wordt een lege tekenreeks toegewezen aan de CSS-klasse van elk stuk van het spel. Een lege tekenreeks voor een CSS-klasse voorkomt dat de spelstukken op het scherm worden weergegeven, omdat er geen stijl op deze onderdelen wordt toegepast.
Plaatsing van spelstuk verwerken
Laten we een methode toevoegen die moet worden verwerkt wanneer een speler een stuk in een kolom plaatst. De GameState klasse weet hoe de juiste rij voor het spelstuk moet worden toegewezen en rapporteert de rij waarin deze terechtkomt. We kunnen deze informatie gebruiken om CSS-klassen toe te wijzen die de kleur van de speler vertegenwoordigen, de uiteindelijke locatie van het stuk en een CSS-neerloopanimatie.
Deze methode PlayPiecewordt aangeroepen en er wordt een invoerparameter geaccepteerd die de kolom aangeeft die de speler kiest.
Voeg deze code toe onder de
piecesmatrix die we in de vorige stap hebben gedefinieerd.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}"; }
Dit is wat de PlayPiece code doet:
- We vertellen de gamestatus om een stuk in de ingediende kolom
colte spelen en de rij vast te leggen waarin het stuk terecht is gekomen. - Vervolgens kunnen we de drie CSS-klassen definiëren die aan het spelstuk moeten worden toegewezen om te bepalen welke speler momenteel werkt, de kolom waarin het stuk is geplaatst en de landingsrij.
- De laatste regel van de methode wijst deze klassen toe aan dat spelstuk in de
piecesmatrix.
Als u in de Board.razor.css kijkt, vindt u de CSS-klassen die overeenkomen met de kolom, rij en de beurt van de speler.
Het resulterende effect is dat het spelstuk wordt geplaatst in de kolom en geanimeerde om in de onderste rij te vallen wanneer deze methode wordt aangeroepen.
Een kolom kiezen
We moeten vervolgens enkele besturingselementen plaatsen waarmee spelers een kolom kunnen kiezen en onze nieuwe PlayPiece methode kunnen aanroepen. We gebruiken het teken '🔽' om aan te geven dat u een stuk in deze kolom kunt neerzetten.
Voeg boven de starttag
<div>een rij met klikbare knoppen toe:<nav> @for (byte i = 0; i < 7; i++) { var col = i; <span title="Click to play a piece" @onclick="() => PlayPiece(col)">🔽</span> } </nav>Het
@onclickkenmerk geeft een gebeurtenis-handler op voor de klik-gebeurtenis. Maar voor het afhandelen van UI-gebeurtenissen moet een Blazor-onderdeel worden weergegeven met behulp van een interactieve rendermodus. Blazor-onderdelen worden standaard statisch van de server weergegeven. We kunnen een interactieve rendermodus toepassen op een onderdeel met behulp van het@rendermodekenmerk.Werk het
Boardonderdeel op deHomepagina bij zodat het deInteractiveServerrendermodus gebruikt.<Board @rendermode="InteractiveServer" />De
InteractiveServerrendermodus verwerkt ui-gebeurtenissen voor uw onderdelen van de server via een WebSocket-verbinding met de browser.Voer de app uit met deze wijzigingen. Deze ziet er nu als volgt uit:
Nog beter, wanneer we bovenaan een van de drop-knoppen selecteren, kan het volgende gedrag worden waargenomen:
Goed bezig! We kunnen nu stukken aan het bord toevoegen. Het GameState object is slim genoeg om heen en weer te draaien tussen de twee spelers. Ga verder en selecteer meer drop-knoppen en bekijk de resultaten.
Winnende en foutafhandeling
Als u het spel in de huidige configuratie speelt, merkt u dat het fouten veroorzaakt wanneer u te veel stukken in dezelfde kolom probeert te plaatsen en wanneer één speler het spel wint.
Laten we de huidige status van ons spel duidelijk maken door een aantal foutafhandeling en indicatoren toe te voegen aan ons bord. Voeg een statusgebied toe boven het bord en onder de knoppen voor neerzetten.
Voeg de volgende markeringen toe na het
navelement:<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>Met deze markering kunnen we indicatoren weergeven voor:
- Aankondiging van een wedstrijdwinnaar
- Een knop waarmee we de game opnieuw kunnen starten
- Foutberichten
- De beurt van de huidige speler
Laten we nu een aantal logica invullen waarmee deze waarden worden ingesteld.
Voeg de volgende code toe na de stukmatrix:
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;" : "";- De
CurrentTurneigenschap wordt automatisch berekend op basis van de status van dewinnerMessageen dePlayerTurneigenschap van deGameState. - De
ResetStylewordt berekend op basis van de inhoud van deWinnerMessage. Als er eenwinnerMessageis, wordt de knop Opnieuw instellen weergegeven op het scherm.
- De
Laten we het foutbericht afhandelen wanneer een stuk wordt afgespeeld. Voeg een regel toe om het foutbericht te wissen en verpakt de code vervolgens in de
PlayPiecemethode met eentry...catchblok om inerrorMessagete stellen of er een uitzondering is opgetreden: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; }Onze indicator voor fouthandler is eenvoudig en maakt gebruik van het Bootstrap CSS-framework om een fout in de gevaarmodus weer te geven.
Vervolgens gaan we de
ResetGamemethode toevoegen die door de knop wordt geactiveerd om een game opnieuw te starten. Momenteel is de enige manier om een game opnieuw te starten de pagina te vernieuwen. Met deze code kunnen we op dezelfde pagina blijven.void ResetGame() { State.ResetBoard(); winnerMessage = string.Empty; errorMessage = string.Empty; pieces = new string[42]; }ResetGameOnze methode heeft nu de volgende logica:- Stel de status van het bord opnieuw in.
- Verberg onze indicatoren.
- Stel de stukkenmatrix opnieuw in op een lege matrix van 42 tekenreeksen.
Met deze update kunnen we het spel opnieuw spelen en nu zien we een indicator net boven het bord dat de beurt van de speler aangeeft en uiteindelijk de voltooiing van het spel.
We hebben nog steeds een situatie waarin we de knop Opnieuw instellen niet kunnen selecteren. Laten we wat logica toevoegen aan de
PlayPiecemethode waarmee het einde van het spel wordt gedetecteerd.Laten we eens kijken of er een winnaar aan het spel is door na ons
try...catchblokPlayPieceeen switchexpressie toe te voegen.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!", _ => "" };De
CheckForWinmethode retourneert een opsomming die rapporteert welke speler, indien aanwezig het spel heeft gewonnen of als het spel een gelijkspel is. Met deze switchexpressie wordt het veld op dewinnerMessagejuiste manier ingesteld als er een game over de status plaatsvindt.Wanneer we nu een scenario met speleindpunten spelen en bereiken, worden deze indicatoren weergegeven:
Samenvatting
We hebben veel geleerd over Blazor en een netjes klein spel gebouwd. Hier volgen enkele van de vaardigheden die we hebben geleerd:
- Een onderdeel gemaakt
- Dat onderdeel toegevoegd aan onze startpagina
- Gebruikte afhankelijkheidsinjectie om de status van een game te beheren
- Het spel interactief gemaakt met gebeurtenis-handlers om stukken te plaatsen en het spel opnieuw in te stellen
- Schreef een fouthandler om de status van het spel te rapporteren
- Parameters toegevoegd aan ons onderdeel
Het project dat we hebben gebouwd, is een eenvoudig spel en er is nog veel meer dat je ermee kunt doen. Zoekt u een aantal uitdagingen om het te verbeteren?
Uitdagingen
Houd rekening met de volgende uitdagingen:
- Als u de app kleiner wilt maken, verwijdert u de standaardindeling en extra pagina's.
- Verbeter de parameters voor het
Boardonderdeel, zodat u elke geldige CSS-kleurwaarde kunt doorgeven. - Verbeter het uiterlijk van indicatoren met een CSS- en HTML-indeling.
- Introduceer geluidseffecten.
- Voeg een visuele indicator toe en voorkom dat er een drop button wordt gebruikt wanneer de kolom vol is.
- Voeg netwerkmogelijkheden toe zodat u een vriend in hun browser kunt afspelen.
- Plaats het spel in een .NET MAUI met Blazor-toepassing en speel het op uw telefoon of tablet.
Gelukkig coderen en plezier hebben!