Windows Phone 7 Game Development Opprette Tic-Tac-Toe med XNA

XNA er et rammeverk for spilloppretting for Microsoft-enheter, inkludert Windows-PCer, Xbox 360 og det splitter nye Windows Phone 7-operativsystemet. I en tidligere opplæring dekket vi grunnleggende om XNA-rammen, inkludert håndtering av innspill og visning av sprites. I denne artikkelen lærer du hvordan du kombinerer disse ferdighetene med en egen spillidee for å skape noe morsomt å spille og lett å hente.

prosjekt oversikt

I denne opplæringen skal du lage et enkelt Tic-Tac-Toe-spill som kan spilles med venner. Tic-Tac-Toe er et enkelt spill hvor to spillere tar vekslende svinger som plasserer tegn på et tre til tre rutenett. Den første spilleren bruker en O og den andre spilleren bruker en X. For å vinne spillet må en spiller arrangere tre av deres tegn i en rad, kolonne eller diagonal.

Mens dette spillet er enkelt, krever det et par forskjellige ferdigheter å bygge. For det første bruker du XNA og dets grafikkfunksjoner til å bygge spillet ditt. Som sådan må du være kjent med å vise sprites. For det andre må du vite hvordan du håndterer berøringer på telefonens berøringspanel. Heldigvis gir XNA et høyt nivå API for å få tilgang til disse berøringene. Til slutt må du bruke litt programmering og logisk know-how for å bestemme vinneren. For denne opplæringen vil mye av det bli gitt til deg. Når du bygger spill i fremtiden, må du komme med dine egne ideer og logikk.

Opprette prosjektet ditt

For å starte, må du kontrollere at du har installert de nyeste utviklingsverktøyene for Windows Phone 7. Hvis du ikke har oppdatert verktøyene dine siden den siste WP7-opplæringen på MobileTuts, bør du besøke Microsoft Download Center og få RTW-versjonen. Denne siste versjonen kommer med den endelige emulatoren som demonstrerer hvordan appene dine vil fungere for å frigjøre dagens maskinvare.

Etter at verktøyene dine er oppdatert, åpner du Visual Studio 2010 og klikker koblingen "Ny prosjekt ..." i venstre sidefelt. I dialogboksen som dukker opp, velg "XNA Game Studio 4" i den venstre kolonnen, og kontroller at "Windows Phone Game (4.0)" -malen er valgt til høyre. Gi prosjektet et passende navn som "TicTacToe" og bekreft at avkrysningsboksen "Opprett katalog for løsning" er valgt. Hvis du har gjort alt dette riktig, bør dialogboksen matche følgende bilde:

Klikk på "OK" for å opprette ditt nye prosjekt. Visual Studio 2010 vil generere de nødvendige filene i den angitte katalogen din og åpne Game1.cs for redigering.

Importer mediainnhold

Siden du bruker sprites for all spillgrafikk i dette prosjektet, må du importere de nødvendige elementene til prosjektet ditt. I nedlastingen som følger med denne opplæringen finner du en Media katalog som inneholder en rekke bilder. I løsningsoppdageren på høyre side av skjermen, finn innholdsprosjektet (kalt TicTacToeContent) og høyreklikk på det. Fra hurtigmenyen velger du "Legg til> Eksisterende element ...". Når dialogboksen åpnes, blar du til Media mappe som du unzipped fra opplæringen nedlasting og velg alle bildene som finnes i den. Du bør kunne fortelle fra bildene nøyaktig hva hvert element inneholder.

Etter at du har importert mediene, må løsningsoppdageren likne følgende:

Laster inn og tilordner innhold

Nå som media har blitt importert til innholdsprosjektet som er knyttet til løsningen din, må du laste hvert bilde som en separat tekstur. Fordi du vil bruke disse teksturer gjennom hele spillet ditt, skal du lagre dem i feltene inne i spillklassen din. Åpne filen Game1.cs og legg til følgende felt øverst i klassedeklarasjonen din:

 Texture2D gridTexture; Rektangel gridRectangle; Texture2D resetButton; Rektangel resetButtonPosition; Texture2D oPiece; Texture2D xPiece; Texture2D oWinner; Texture2D xWinner; Texture2D noWinner; Texture2D oTurn; Texture2D xTurn; 

Du ser at hvert av bildene du importerte, har et felt for å sikkerhetskopiere det. I tillegg har hovedspillruten og resetknappens tekstur felt av typen Rektangel som vil bli brukt til å plassere disse elementene. Disse lagres som felt fordi de ikke vil endres i løpet av spillet.

Nå som du har de aktuelle feltene opprettet, er det på tide å instantiere Texture2D og Rektangel objekter som er tilordnet feltene. Rull ned til din Game1.cs filen til du kommer til LoadContent metode. Innsiden av denne metoden, sett inn følgende kode etter linjen som leser spriteBatch = ny SpriteBatch (GraphicsDevice);:

 gridTexture = Content.Load( "TicTacToe_Grid"); gridRectangle = nytt rektangel (0, 0, spriteBatch.GraphicsDevice.Viewport.Width, spriteBatch.GraphicsDevice.Viewport.Height); oPiece = Content.Load( "TicTacToe_O"); xPiece = Content.Load( "TicTacToe_X"); resetButton = Content.Load( "TicTacToe_Reset"); resetButtonPosition = ny rektangel (spriteBatch.GraphicsDevice.Viewport.Width / 2 - (resetButton.Width / 2), spriteBatch.GraphicsDevice.Viewport.Height - 95, resetButton.Width, resetButton.Height); oWinner = Content.Load( "TicTacToe_O_Winner"); xWinner = Content.Load( "TicTacToe_X_Winner"); noWinner = Content.Load( "TicTacToe_Draw"); oTurn = Content.Load( "TicTacToe_O_Turn"); xTurn = Content.Load( "TicTacToe_X_Turn"); 

Definere spill-arbeidsflyten

Etter å ha lastet sprites som vil bli brukt av spillet, må du komme opp med arbeidsflyten som spillet vil løpe på. For Tic-Tac-Toe er dette ganske enkelt og ser noe ut som det følgende:

  1. Tegn spillelisten
  2. Tegn de nåværende spillene
  3. Tegn gjeldende spillstatus (hvis tur er det eller hvis det er en vinner)
  4. Hvis spillet har blitt vunnet eller ikke lenger kan brukes, kan du trekke Reset-knappen
  5. Hvis ingen har vunnet og spillet fortsatt er winnable, håndtak berører på rutenettet og se etter en vinner hvis en berøring blir gjort
  6. Hvis spillet har blitt vunnet eller ikke lenger kan brukes, må du håndtere berøringer på tilbakestillingsknappen
    • Hvis tilbakestillingsknappen blir berørt, tilbakestill spillet

Som du sikkert kan fortelle, faller disse trinnene inn i en av to grunnleggende kategorier, Tegn eller Oppdater. Skanner gjennom Game1.cs filen vil du se at du har to metoder, Tegne og Oppdater Det er de perfekte beholderne for koden som kreves for å beskrive arbeidsflyten.

Lagring av spillstat

Ser du på arbeidsflyten, kan du skille mellom at det er fire forskjellige elementer for å holde styr på for å administrere spilltilstanden. Først må du spore tilstanden til hvert rutenett på spillområdet. Du gjør dette ved å bruke en egendefinert oppsummering og et flerdimensjonalt utvalg. Deretter må du følge med på om spillet har blitt vunnet og av hvem. For det tredje må du spore hvilken tur det er. Til slutt må du spore hvorvidt spillet er winnable. Dette elementet er initialisert som ekte og omberegnes etter at hver spiller har en sving. Når alle rutenettene er fylt ut, endres dette til falsk.

Du starter med å definere den egendefinerte oppregningen som beskriver en spiller for spillet ditt. På toppen av klassen din, over klassedeklarasjonen, legger du til følgende kode:

 publikum TicTacToePlayer None, PlayerO, PlayerX 

Denne oppstillingen delinerer tre spillere (Ingen, PlayerO og PlayerX) og vil bli brukt til å spore både rutenett og spillvinner. Legg til instansvariablene som vil hjelpe deg med å spore spillets tilstand. Disse elementene skal legges til toppen av klassedeklarasjonen din:

 bool winnable; TicTacToePlayer vinner; TicTacToePlayer strøm; TicTacToePlayer [,] grid; 

Du lagrer fire ting her. Først avgrenser du om spillet fortsatt er winnable. For det andre, erklærer du vinneren. Hvis vinneren er Ingen, fortsetter spillingen. Deretter lagrer du gjeldende spiller. Til slutt lagrer du rutenettet. På dette tidspunktet trenger du fortsatt å initialisere hver av disse variablene. Når du tenker fremover, vet du at du må reinitialisere dem når noen klikker på Tilbakestill-knappen, og som sådan kan vi lage en ny metode som håndterer den initialiseringen. Legg til den nye metoden i klassen din under initial~~POS=TRUNC metode som følger:

 privat ugyldig tilbakestilling () winnable = true; vinner = TicTacToePlayer.None; grid = ny TicTacToePlayer [3, 3]; for (int i = 0; i < 3; i++)  for (int j = 0; j < 3; j++)  grid[i, j] = TicTacToePlayer.None;    

Nå, ring denne nye metoden fra initial~~POS=TRUNC metode ved å endre den til å lese som følger:

 beskyttet overstyre ugyldig Initialize () Reset (); base.Initialize ();  

På dette punktet lagrer du all data du trenger, så det bør være enkelt å begynne å tegne grensesnittet.

Tegne spillgrensesnittet

Før du begynner å tegne noe, må du angi ønsket bredde og høyde for enheten. Du vil gjøre dette inne i Spill1 konstruktør. Endre det for å lese som følger:

 offentlig Game1 () graphics = new GraphicsDeviceManager (this); Content.RootDirectory = "Innhold"; graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800; // Rammefrekvensen er 30 fps som standard for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks (333333);  

Du har lagt til setninger som erklærer at du vil at bakbufferbredden skal være 480 piksler og høyden skal være 800 piksler. Dette forenkler i stor grad tegningen av resten av komponentene for spillet.

For å holde ting enkelt, skal du utføre hvert tegningstrinn inne i en egen metode. Disse metodene vil da bli kalt fra basen Tegne metode som allerede eksisterer. La oss begynne med å tenke på noen gode navn for hver av spillets arbeidsflytstrinn, opprette metoder for det navnet, og legge til samtaler til de metodene fra Tegne. Etter min mening beskriver følgende metodenavn tilstrekkelig både hva de skal gjøre og arbeidstrinnstrinnene dekket:

  • DrawGrid - Dekker arbeidsflyt trinn ett og tegner spillelisten
  • DrawPieces - Dekker arbeidsflyt trinn to og trekker brikker hvor et stykke har blitt spilt
  • DrawStatus - Dekker arbeidsflyt trinn tre og trekker gjeldende spillstatus ("O's Turn", "X's Turn", "O Wins!", "X Wins!", Eller "Draw!")
  • DrawResetButton - Dekker arbeidsflyt trinn fire og trekker tilbakestillingsknappen

Lag disse metodene nå ved å sette inn følgende kode under din Tegne metode:

 private void DrawGrid ()  private void DrawPieces ()  private void DrawStatus ()  private void DrawResetButton ()  

Du skriver koden for disse metodene i et øyeblikk, men for nå må du legge dem til din Tegne metode ved å endre den til å lese som følger:

 beskyttet overstyring ugyldig tegning (GameTime gameTime) GraphicsDevice.Clear (Color.Black); spriteBatch.Begin (); DrawGrid (); DrawPieces (); DrawStatus (); DrawResetButton (); spriteBatch.End (); base.Draw (gametime);  

Du vil legge merke til at du har omringet samtalene til hjelpemetoder med anrop til spriteBatch objektets Begynne og Slutt metoder. Du gjør dette fordi dine hjelpemetoder alle vil tegne sprites, og det er mye mer effektivt å ringe Begynne og Slutt par en gang innsiden av Tegne heller enn innsiden av hver hjelpemetode.

La oss nå jobbe med å få spillelisten til å dukke opp. Spillegitteret er 480 piksler bredt med 800 piksler høyt bilde med gjennomsiktig bakgrunn og et hvitt rutenett på kvadrater 150 piksler bred i midten. Du importerte den tidligere. Det kan ikke være enklere å tegne det på telefonens skjerm. Du tar tekstur du lastet inn og lagret i gridTexture variabel og tegne den ved å plassere den ved hjelp av prevoiusly instantiated gridRectangle variabel, passerer begge elementene til spriteBatch objektets Tegne metode. Forandre din DrawGrid metode for å lese som følger:

 privat ugyldig DrawGrid () spriteBatch.Draw (gridTexture, gridRectangle, Color.White);  

Lagre filen du jobber med, og klikk F5 for å kompilere og kjøre prosjektet. Windows Phone 7-emulatoren skal dukke opp og vise ditt Tic-Tac-Toe-rutenett på en svart bakgrunn, akkurat som følgende bilde:

Nå som rutenettet er på plass, la oss tegne spillebitene. På dette punktet kan vi bruke noen enkel logikk for å vise brikkene, men ingenting vil vises før vi legger til koden for å håndtere berører og spille spillet. Endre din DrawPieces metode som følger:

 private void DrawPieces () for (int i = 0; i < 3; i++)  for (int j = 0; j < 3; j++)  if (grid[i, j] != TicTacToePlayer.None)  Texture2D texture = grid[i, j] == TicTacToePlayer.PlayerO ? oPiece : xPiece; Rectangle position = GetGridSpace(i, j, texture.Width, texture.Height); spriteBatch.Draw(texture, position, Color.White);     

Hvis du har et skarpt øye (eller mer sannsynlig, viser Visual Studio deg røde skarpe linjer) ser du at GetGridSpace metoden mangler. GetGridSpace er en praktisk metode som bidrar til å holde litt kode ut av DrawPieces metode og vil også komme til nytte når du prøver å håndtere berører senere. Legg det til bunnen av klassedeklarasjonen din som følger:

 privat rektangel GetGridSpace (int kolonne, int rad, int bredde, int høyde) int centerX = spriteBatch.GraphicsDevice.Viewport.Width / 2; int centerY = spriteBatch.GraphicsDevice.Viewport.Height / 2; int x = centerX + ((kolonne - 1) * 150) - (bredde / 2); int y = centerY + ((rad - 1) * 150) - (høyde / 2); returnere nytt rektangel (x, y, bredde, høyde);  

Nå, la oss se på resten av DrawPieces. Denne metoden er litt mer komplisert enn DrawGrid men det skal fortsatt være ganske enkelt å forstå. Du itererer over hver rad og kolonne i spillefeltet, lagret i Nett variabel, og sjekk for å se tilstanden til det aktuelle rutenettet. Hvis rutenettplassen inneholder en annen spiller enn "Ingen" enn å tegne riktig tekstur. Du bruker den ternære operatøren til å hente den riktige tekstur basert på rutenettens tilstand og deretter tegne den ved hjelp av rektangelet hentet fra GetGridSpace.

Det neste problemet å håndtere, tegner nåværende status. Statusen viser hvilken tur det er, hvem vant spillet, eller om spillet er uavgjort. Fyll ut metoden som følger:

 privat tomt DrawStatus () Texture2D texture; hvis (vinneren! = TicTacToePlayer.None) texture = winner == TicTacToePlayer.PlayerO? oWinner: xWinner;  annet hvis (! winnable) tekstur = noWinner;  else texture = current == TicTacToePlayer.PlayerO? oTurn: xTurn;  Rektangulær posisjon = ny rektangel (spriteBatch.GraphicsDevice.Viewport.Width / 2 - (texture.Width / 2), 15, texture.Width, texture.Hight); spriteBatch.Draw (tekstur, posisjon, Color.White);  

Denne metoden avviger ikke mye fra de andre tegne metoder du har opprettet hittil. Du har en tekstur og en posisjon og trenger å tegne tekstur på skjermen. Den interessante delen av denne metoden er å bestemme hvilken tekstur som skal tegnes. Du sjekker først for å se om det er en vinner. Hvis det er, velger du den riktige vinneren tekstur og tegner det. Deretter sjekker du om alle rutenettene har blitt okkupert og spillet ikke lenger er winnable. Hvis det er tilfelle, velger du ingen vinneren tekstur og tegner den. Hvis ingen av disse forholdene er sanne, så kontroller du hvilken spillerens sving den er, velg den riktige svingteksturen, og trekk den. Hvis du kompilerer og kjører prosjektet ditt på dette punktet (ved å trykke F5), ser du at grensesnittet viser at det er O: s tur:

Til slutt skal du opprette koden som trekker tilbakestillingsknappen. Dette er ganske grei. Hvis det er en vinner eller spillet ikke lenger er winnable, tegner du resetknappens tekstur. Endre DrawResetButton metode slik at den lyder som følger:

 private void DrawResetButton () if (winner! = TicTacToePlayer.None ||! winnable) spriteBatch.Draw (resetButton, resetButtonPosition, Color.White);  

På dette tidspunktet har du opprettet all koden som trengs for å tegne grensesnittet og alle komponentdelene. Nå trenger du bare å håndtere oppdatering av spillet ditt basert på berøringer fra spillerne.

Håndtering av tobak og oppdateringsstatus

Hvis du fulgte den siste opplæringen på XNA, vil mye av følgende kode bli kjent. Håndtering berører på skjermen er noe som er ganske vanlig, og det er bare innsiden av berøringshåndteringskoden som du vil ha spilllogikken din. For å starte, la oss sette den grunnleggende berøringsbehandlingskoden inn i Oppdater metode. Finne Oppdater i din Spill1 klassen og endre den til å lese som følger:

 beskyttet overstyring ugyldig Oppdatering (GameTime gameTime) if (GamePad.GetState (PlayerIndex.One) .Buttons.Back == ButtonState.Pressed) this.Exit ();  TouchCollection berører = TouchPanel.GetState (); hvis (! berører && berører.Count> 0) touching = true; TouchLocation touch = berører.First (); HandleBoardTouch (touch); HandleResetTouch (touch);  annet hvis (berører.Count == 0) berører = false;  base.Update (gameTime);  

Det er noen ting i denne metoden å være oppmerksom på. Først vil du legge merke til en ny rørende variabel som ikke eksisterer. Denne variabelen lagrer om spilleren hadde rørt brettet på forrige eller ikke Oppdater ring og forhindrer en langvarig finger fra å spille flere ganger uten å slippe fra skjermen. Legg til rørende som en instansvariabel øverst på klassen din.

 bool rørende; 

Du vil også legge merke til at du lager to metodeanrop innen Oppdater metode til metoder som ikke eksisterer ennå. Legg til disse metodene i klassedeklarasjonen din direkte under Oppdater metode:

 privat void HandleBoardTouch (TouchLocation touch)  privat void HandleResetTouch (TouchLocation touch)  

Nå går det gjennom Oppdater Metode du ser at du ser etter aktuelle berøringer på skjermen. Hvis det kommer berøringer og spilleren ikke tidligere berørte skjermen, tar du den første berøringen og sender den til metodene som håndterer styret, berører og resetter berører. Hvis spilleren ikke berører skjermen og de var tidligere, oppdaterer du rørende variabel til falsk.

På dette punktet, la oss fylle ut HandleBoardTouch og HandleResetTouch metoder. Disse tilsvarer arbeidsflytstrinn 5 og 6, henholdsvis.

Håndteringskort

Når en bruker berører skjermen, må spillet gjøre noen ting:

  • Sjekk om kontakten er innenfor spillområdet
  • Hvis det er i spillområdet, må du kontrollere om stedet som er berørt, allerede er opptatt
  • Hvis stedet er ikke okkupert, legg et stykke der og se om den nåværende spilleren har vunnet
  • Hvis det spilt var vinneren, må du oppdatere spillets status som sådan. Hvis det spillte stykket okkuperte det siste tilgjengelige punktet, merk spillet som uoppnåelig
  • Endelig bytt gjeldende spiller

Oppdater HandleBoardTouch å lese som følger, håndtere alle trinnene ovenfor:

 privat void HandleBoardTouch (TouchLocation touch) hvis (vinneren == TicTacToePlayer.None) for (int i = 0; i < 3; i++)  for (int j = 0; j < 3; j++)  Rectangle box = GetGridSpace(i, j, 150, 150); if (grid[i, j] == TicTacToePlayer.None && box.Contains((int)touch.Position.X, (int)touch.Position.Y))  grid[i, j] = current; CheckForWin(current); CheckForWinnable(); current = current == TicTacToePlayer.PlayerO ? TicTacToePlayer.PlayerX : TicTacToePlayer.PlayerO;      

Som du kan se, følger denne metoden den grunnleggende oversikten over. Hvis det ikke er en vinner, det iterates over hvert rutenett, kontrollerer om kontakten er i det rommet, kontrollerer om plassen er åpen, og legger et stykke der. Å sjekke om en vinner og sørge for at spillet fortsatt er winnable, håndteres av andre metoder. La oss stub ut disse metodene nå. Under HandleBoardTouch metode, legg til følgende kode:

 privat tomt CheckForWin (TicTacToePlayer-spiller)  privat tomt CheckForWinnable ()  

For nå, la disse metodene være tomme og kompilere og kjøre spillet ditt. Prøv å berøre brettet ved å klikke på emulatoren og se statusmeldingsendringen og spillebitene vises. Du er godt på vei til et komplett spill nå!

Vinn betingelser

På dette punktet kommer du til det virkelige kjøttet i spillet, den vinnende logikken. Som diskutert tidligere opptrer en vinnende tilstand når en spillers stykker opptar en av radene, en av kolonnene eller en av de to diagonalene. Spillet blir unwinnable når det ikke er noen vinner erklært og det er ingen ledige plasser igjen. For dette spillet bruker vi et flerdimensjonalt array for å lagre gridens tilstand og ut av boksen C # gir ikke metoder for å sjekke rader, kolonner eller diagonaler. Heldigvis støtter språket en fantastisk funksjon som kalles forlengelsesmetoder som du vil bruke her for å gjøre koden litt renere.

Opprette hjelpere

For å lage utvidelsesmetoder må du først opprette en ny klasse. Klikk på prosjektets navn i Solution Explorer og klikk på "Add> Class ...". Gi navnet på klassen MultiDimensionalArrayExtensions og klikk "Add". Når din nye fil åpnes for redigering, må du endre den slik at klassedeklarasjonen din ser ut som følgende:

 offentlig statisk klasse MultiDimensionalArrayExtensions  

Du ser at du har lagt til modifikatørene offentlig og statisk til klassedeklarasjonen. Dette er nødvendig for å lage utvidelsesmetoder. Nå skal vi lage et par metoder som vi trenger, som hver returnerer en IEnumerable for enkel forespørsel:

  • Row - Returnerer alle elementene i en bestemt rad
  • Kolonne - Returnerer alle elementene i en bestemt kolonne
  • Diagonal - Returnerer alle elementene i en diagonal
  • Alle - Returnerer alle elementene i den flerdimensjonale gruppen

Endre klassen din igjen, legg til metodene som følger:

 offentlig statisk klasse MultiDimensionalArrayExtensions public static IEnumerable Rad(denne T [,] array, int rad) var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int i = columnLower; jeg <= columnUpper; i++)  yield return array[row, i];   public static IEnumerable Kolonne(denne T [,] array, int kolonne) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); for (int i = rowLower; jeg <= rowUpper; i++)  yield return array[i, column];   public static IEnumerable Diagonal(denne T [,] array, DiagonalDirection retningen) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int rad = rowLower, column = columnLower; row <= rowUpper && column <= columnUpper; row++, column++)  int realColumn = column; if (direction == DiagonalDirection.DownLeft) realColumn = columnUpper - columnLower - column; yield return array[row, realColumn];   public enum DiagonalDirection  DownRight, DownLeft  public static IEnumerable Alle(denne T [,] array) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int rad = rowLower; rad <= rowUpper; row++)  for (int column = columnLower; column <= columnUpper; column++)  yield return array[row, column];     

Du kan se at det ikke er mye med disse metodene. For hver enkelt av dem blir en bestemt del av det flerdimensjonale arrayet iterert over, og den delen av arrayet returneres som en del av en IEnumerable. Den eneste veldig vanskelige delen kan være bruk av utbytte søkeord. En forklaring på oppførselen til det aktuelle søkeordet er utenfor rammen av denne artikkelen, men referansen til C # på MSDN for utbyttesøkeordet kan være til hjelp hvis du vil lære mer. Som sidenotat er mye av arbeidet med disse utvidelsesmetodene hentet fra et brukerbidrag på StackOverflow som du finner her

Implementere Win Logic

Nå som nødvendige utvidelsesmetoder er implementert, bør det være ganske enkelt å implementere vinnlogikken. La oss gå tilbake til CheckForWin metode og implementere det. Oppdater metoden for å lese som følger:

 privat ugyldig CheckForWin (TicTacToePlayer-spiller) Func checkWinner = b => b == spiller; hvis (grid.Row (0) .All (sjekkWinner) || grid.Row (1) .All (sjekkWinner) || grid.Row (2) .Alle (sjekkWinner) || grid.Column (0) .Alle sjekk Winner) || grid.Column (1) .All (sjekkWinner) || grid.Column (2) .All (sjekk Winner) | grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownRight) .Alle (sjekkWinner) || grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownLeft) .Alle (sjekkWinner)) winner = player;  

Gitt det du allerede vet fra å lage utvidelsesmetoder, bør dette være ganske enkelt å dechiffrere. Du oppretter først en "Func": http: //msdn.microsoft.com/en-us/library/bb549151.aspx objekt som handler en delegat og lar deg bruke en lambda-setning (det b => b == spiller del) for å spørre en IEnumerable (som de returnerte fra forlengelsesmetoden) og returnere a bool. Du bruker da dette Func objekt over hver rad, kolonne og diagonal ved hjelp av IEnumerable.All metode. Hvis noen av tilfellene er sanne, tilordner du vinner instansvariabel til spiller parameter. Hvis ingen av disse sakene er sanne, skjer ingenting.

Nå, endre din CheckForWinnable metode:

 privat tomt CheckForWinnable () if (winner == TicTacToePlayer.None) Func checkNone = b => b == TicTacToePlayer.None; hvis (! grid.All () .Enhver (sjekkNone)) winnable = false;  

Denne metoden ligner veldig CheckForWin. Først sjekker du for å se om spillet har en vinner. Hvis det ikke gjør det, oppretter du en Func objekt som vil sjekke om et element er likt med TicTacToePlayer Ingen. Du bruker da dette Func mot alle mellomrom i rutenettet, kontroller for å se om noen av mellomrommene er ubebodde. Hvis ingen er, er spillet ikke lenger winnable, og du bytter instansvariabelen winnable.

Etterbehandling

På dette punktet er spillet klart for deg. Du kan kompilere og kjøre prosjektet ved å trykke F5 og begynne å spille (enten selv eller med en partner). Slå om til å plassere stykker på brettet, se statusmeldingsendringen og se hva som skjer når du vinner. Når du vinner eller tegner, klikker du på tilbakestillingsknappen og ser spillet gå tilbake til sin opprinnelige status.

På dette punktet er det en rekke forskjellige ting du kan gjøre. Du kan implementere en vinnende telling som viser hvor mange ganger hver spiller har vunnet. Du kan endre måten brikkene viser, eller legge til en kul animasjon når en vinner er erklært. Du kan temaet spillet for å gjøre det litt mer interessant, kanskje ved å sette opp Rebel Alliance mot Galactic Empire?

På dette punktet er det opp til deg å utvide og utvikle hva du vil. Jeg håper du likte å følge denne opplæringen så mye som jeg likte å skrive det og ser frem til å høre kommentarene dine.