Windows Phone 7 Joc de dezvoltare Crearea Tic-Tac-Toe cu XNA

XNA este un cadru de creare a jocurilor la nivel înalt pentru dispozitivele Microsoft, inclusiv PC-urile Windows, Xbox 360 și noul sistem de operare Windows Phone 7. Într-un tutorial anterior, am acoperit elementele de bază ale cadrului XNA, incluzând manipularea și afișarea spritelor. În acest articol, veți învăța cum să combinați aceste abilități cu o idee de joc proprie pentru a crea ceva distractiv de jucat și ușor de preluat.

rezumatul proiectului

În acest tutorial, veți crea un simplu joc Tic-Tac-Toe ce poate fi jucat cu prietenii. Tic-Tac-Toe este un joc simplu în care doi jucători se rotesc alternativ introducând caractere pe o rețea de trei-trei. Primul jucător folosește un O și al doilea jucător folosește un X. Pentru a câștiga jocul, un jucător trebuie să aranjeze trei personaje în rând, coloană sau diagonală.

În timp ce acest joc este simplu, este nevoie de câteva abilități diferite de construit. În primul rând, veți folosi XNA și capacitățile sale grafice pentru a vă construi jocul. Ca atare, trebuie să fiți familiarizați cu afișarea de sprite. În al doilea rând, trebuie să știți cum să faceți față atingerilor de pe panoul de control al telefonului. Din fericire, XNA oferă un API la nivel înalt pentru a accesa aceste atingeri. În cele din urmă, trebuie să aplicați un pic de programare și know-how logic pentru a decide câștigătorul. Pentru acest tutorial, o mare parte din acest lucru vi se va da. Atunci când construiți jocuri în viitor, va trebui să veniți cu propriile idei și logică.

Crearea Proiectului

Pentru a începe, asigurați-vă că ați instalat cele mai recente instrumente de dezvoltare Windows Phone 7. Dacă nu v-ați actualizat instrumentele de la ultimul tutorial WP7 pe MobileTuts, atunci ar trebui să vizitați Centrul de descărcări Microsoft și să obțineți versiunea RTW. Cea mai recentă versiune vine cu emulatorul final care demonstrează modul în care aplicațiile dvs. vor funcționa pe hardware-ul zilei de lansare.

După ce asigurați-vă că instrumentele dvs. sunt actualizate, deschideți Visual Studio 2010 și faceți clic pe linkul "Proiect nou ..." din bara laterală stângă. În caseta de dialog care apare, alegeți "XNA Game Studio 4" în coloana din stânga și asigurați-vă că șablonul "Windows Phone Game (4.0)" este selectat în partea dreaptă. Oferiți-vă proiectului un nume adecvat, precum "TicTacToe" și confirmați că caseta de selectare "Creare director pentru soluție" este selectată. Dacă ați făcut toate aceste lucruri în mod corect, caseta dvs. de dialog ar trebui să se potrivească cu următoarea imagine:

Faceți clic pe "OK" pentru a vă crea noul proiect. Visual Studio 2010 va genera fișierele necesare în directorul specificat și va fi deschis Game1.cs pentru editare.

Importați conținut media

Deoarece veți folosi sprite pentru toate jocurile grafice în acest proiect, trebuie să importați elementele necesare în proiectul dvs. În descărcarea care însoțește acest tutorial, veți găsi a Mass-media care conține o varietate de imagini. În exploratorul de soluții din partea dreaptă a ecranului, găsiți proiectul Content (numit TicTacToeContent) și faceți clic dreapta pe el. Din meniul contextual, selectați "Adăugați> Element existent ...". Când dialogul se deschide, navigați la Mass-media folderul pe care l-ați dezarhivat din descărcarea tutorialului și selectați toate imaginile conținute în el. Ar trebui să puteți spune din imagine numele exact ce conține fiecare element.

După importul suportului media, exploratorul de soluții ar trebui să semene cu următoarele:

Încărcarea și atribuirea conținutului

Acum că media dvs. a fost importată în proiectul Content atașat la soluția dvs., trebuie să încărcați fiecare imagine ca o textura separată. Pentru că veți folosi aceste texturi în timpul jocului, veți să le stocați în câmpurile din clasa de joc. Deschideți fișierul Game1.cs și adăugați următoarele câmpuri în partea de sus a declarației de clasă:

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

Vedeți că fiecare dintre imaginile pe care le-ați importat are un câmp care să o susțină. În plus, grila principală de joc și textura butonului de resetare au câmpuri de tip Dreptunghi care vor fi utilizate pentru poziționarea acelor elemente. Acestea sunt stocate ca câmpuri deoarece nu se vor schimba pe parcursul jocului.

Acum că ați creat câmpurile corespunzătoare, este timpul să instanțiați Texture2D și Dreptunghi obiecte care sunt atribuite câmpurilor. Derulați în jos până la dvs. Game1.cs până când ajungeți la LoadContent metodă. În interiorul acestei metode, introduceți următorul cod după linia care citește spriteBatch = nou SpriteBatch (GraphicsDevice);:

 gridTexture = Content.Load( "TicTacToe_Grid"); gridRectangle = nou dreptunghi (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 = nou dreptunghi (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"); 

Definirea fluxului de lucru al jocului

După încărcarea spritelor care vor fi folosite de joc, trebuie să veniți cu fluxul de lucru pe care va juca jocul. În scopul Tic-Tac-Toe, acest lucru este destul de simplu și arată cam așa:

  1. Desenați grila de joc
  2. Desenați piesele redate în prezent
  3. Desenați starea actuală a jocului (a cărei rundă este sau dacă există un câștigător)
  4. Dacă jocul a fost câștigat sau nu mai poate fi câștigat, desenați butonul Resetare
  5. Dacă nimeni nu a câștigat și jocul este în continuare câștigător, manipulați atinge grila și verificați dacă un câștigător este câștigat
  6. Dacă jocul a fost câștigat sau nu mai poate fi câștigat, mânerul atinge butonul de resetare
    • Dacă atingeți butonul de resetare, resetați jocul

După cum probabil puteți spune, acești pași intră într-una din cele două categorii de bază, Draw sau Update. Scanarea prin Game1.cs fișier veți vedea că aveți două metode, A desena și Actualizați care sunt containerele perfecte pentru codul necesar pentru a descrie fluxul de lucru.

Stocarea statului de joc

Privind fluxul de lucru, puteți observa că există patru elemente diferite pentru a ține evidența pentru a gestiona starea jocului. În primul rând, trebuie să urmăriți situația fiecărui loc de rețea pe terenul de joc. Veți face acest lucru folosind o enumerare personalizată și o matrice multidimensională. Apoi, trebuie să urmăriți dacă jocul a fost câștigat și cine. În al treilea rând, trebuie să urmăriți care este rândul său. În cele din urmă, trebuie să urmăriți dacă jocul poate fi câștigat. Acest element este inițializat ca Adevărat și este recalculat după ce fiecare jucător are un turn. Când toate locurile de rețea sunt completate, aceasta se schimbă fals.

Veți începe prin definirea enumerării personalizate care descrie un jucător pentru jocul dvs. În partea de sus a fișierului din clasă, deasupra declarației de clasă, adăugați următorul cod:

 public enum TicTacToePlayer Nici unul, PlayerO, PlayerX 

Această enumerare descrie trei jucători (Nici unul, PlayerO, și PlayerX) și va fi folosit pentru a urmări atât starea grilei, cât și câștigătorul jocului. Acum, adăugați variabilele de instanță care vă vor ajuta să urmăriți starea jocului. Aceste elemente ar trebui adăugate în partea de sus a declarației de clasă:

 bool winnable; Câștigătorul TicTacToePlayer; TicTacToePlayer curent; TicTacToePlayer [,] grila; 

Tu stochezi patru lucruri aici. În primul rând, puteți delimita dacă jocul este în continuare câștigător. În al doilea rând, declarați câștigătorul. Dacă câștigătorul este Niciuna, atunci jocul continuă. După aceasta, stocați playerul curent. În cele din urmă, stocați starea rețelei. În acest moment, trebuie să inițializați fiecare dintre aceste variabile. Gândindu-ne în față, știi că va trebui să le reinitializați ori de câte ori cineva face clic pe butonul Reset și, ca atare, putem crea o nouă metodă care să o gestioneze pe acea inițializare. Adăugați noua metodă la clasa dvs. sub Inițializare după cum urmează:

 void privat Resetare () winnable = true; câștigător = TicTacToePlayer.None; grila = noul TicTacToePlayer [3, 3]; pentru (int i = 0; i < 3; i++)  for (int j = 0; j < 3; j++)  grid[i, j] = TicTacToePlayer.None;    

Acum, numiți această nouă metodă din Inițializare modificând-o astfel:

 suprascriere protejată void Initialize () Reset (); base.Initialize ();  

În acest moment, stocați toate datele de care aveți nevoie, deci ar trebui să fie simplu să începeți desenarea interfeței.

Desenarea interfeței de joc

Înainte de a începe să trageți ceva, trebuie să setați lățimea și înălțimea dorită pentru dispozitivul dvs. Veți face acest lucru în interior Game1 constructor. Modificați-l astfel:

 public Joc1 () graphics = new GraphicsDeviceManager (acest lucru); Content.RootDirectory = "Conținut"; graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800; // Rata cadrelor este de 30 fps în mod implicit pentru Windows Phone. TargetElapsedTime = TimeSpan.FromTicks (333333);  

Ați adăugat declarații prin care declarați că doriți ca lățimea tamponului de spate să fie 480 de pixeli, iar înălțimea să fie 800 de pixeli. Acest lucru simplifică foarte mult desenarea celorlalte componente pentru joc.

Pentru a păstra lucrurile simple, veți efectua fiecare pas de desen în cadrul unei metode separate. Aceste metode vor fi apoi apelate din bază A desena care există deja. Să începem să ne gândim la câteva nume buni pentru fiecare dintre pașii fluxului de lucru al jocului, să creăm metode ale acelui nume și să adăugăm apeluri către acele metode de la A desena. În opinia mea, următoarele nume de metode descriu în mod adecvat atât ceea ce vor face, cât și pașii fluxului de lucru vizați:

  • DrawGrid - Acoperă fluxul de lucru pasul unu și trage grila de joc
  • DrawPieces - Acoperă fluxul de lucru pasul doi și trage piesele oriunde a fost redată o piesă
  • DrawStatus - Acoperă pasul trei de lucru și atrage starea actuală a jocului ("Turn O", "Turnul lui X", "O câștigă!", "X câștigă!" Sau "Draw!")
  • DrawResetButton - Acoperă pasul patru de lucru și atrage butonul de resetare

Creați acum aceste metode introducând următorul cod de mai jos A desena metodă:

 ()  void privat DrawPieces ()  void privat DrawStatus ()  void privat DrawResetButton ()  

Veți scrie codul pentru aceste metode într-un moment, dar pentru moment trebuie să le adăugați la dvs. A desena modificând-o astfel:

 protejat suprascrie void Draw (GameTime gameTime) GraphicsDevice.Clear (Color.Black); spriteBatch.Begin (); DrawGrid (); DrawPieces (); DrawStatus (); DrawResetButton (); spriteBatch.End (); base.Draw (GameTime);  

Veți observa că ați înconjurat apelurile la metodele dvs. de ajutor cu apeluri către spriteBatch obiecte Începe și Sfârșit metode. Faceți acest lucru deoarece metodele dvs. de ajutor vor fi toate sprites și este mult mai eficient să apelați Începe și Sfârșit se cuplează o dată în interiorul A desena mai degrabă decât în ​​interiorul fiecărei metode de ajutor.

Acum, hai să lucrăm pentru ca grila de joc să apară. Grilă de joc este o imagine înaltă de 480 pixeli lățime până la 800 de pixeli, cu fundal transparent și o rețea albă de pătrate cu o lățime de 150 de pixeli situată în centru. L-ai importat mai devreme. Desenul pe ecranul telefonului nu ar putea fi mai ușor. Luați textura încărcată și stocată în gridTexture variabilă și trageți-o prin poziționarea acesteia folosind instanța inițială gridRectangle variabilă, trecând ambele elemente la spriteBatch obiecte A desena metodă. Schimba-ti DrawGrid metodă de citire după cum urmează:

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

Salvați fișierul în care lucrați și loviți F5 pentru a vă compila și rula proiectul. Emulatorul Windows Phone 7 trebuie să afișeze și să afișeze grilă Tic-Tac-Toe pe un fundal negru, la fel ca următoarea imagine:

Acum, când grila este în poziție, să desenăm piesele de joc. În acest moment putem aplica o logică simplă pentru a arăta piesele, dar nimic nu va fi afișat până când nu adăugăm codul pentru a manipula efectele și pentru a juca jocul. Modificați-vă DrawPieces după cum urmează:

 privat void DrawPieces () pentru (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);     

Dacă aveți un ochi ascuțit (sau mai probabil, Visual Studio vă arată linii roșii ciudate) veți vedea că GetGridSpace metoda lipsește. GetGridSpace este o metodă convenabilă care vă ajută să păstrați un pic de cod din DrawPieces și va veni de asemenea la îndemână atunci când încearcă să se ocupe de atingeri mai târziu. Adăugați-o în partea de jos a declarației de clasă după cum urmează:

 privat dreptunghi GetGridSpace (int coloană, int rând, int lățime, int înălțime) int centerX = spriteBatch.GraphicsDevice.Viewport.Width / 2; int centerY = spriteBatch.GraphicsDevice.Viewport.Height / 2; int x = centruX + ((coloană - 1) * 150) - (lățime / 2); int y = centruY + ((rând - 1) * 150) - (înălțimea / 2); returnați nou dreptunghi (x, y, lățime, înălțime);  

Acum, să ne uităm la restul DrawPieces. Această metodă este un pic mai complicată decât cea DrawGrid dar ar trebui să fie destul de ușor de înțeles. Returnezi peste fiecare rând și coloană a câmpului de joc, stocate în grilă și verificați pentru a vedea starea acelui spațiu de rețea. Dacă spațiul de rețea conține un alt jucător decât "None" decât desenarea texturii corespunzătoare. Utilizați operatorul ternar pentru a apuca textura corectă în funcție de starea spațiului grilă și apoi trageți-l folosind dreptunghiul obținut din GetGridSpace.

Următoarea problemă de abordat este trasarea statutului actual. Statutul arată care este rândul său, cine a câștigat jocul sau dacă jocul este o remiză. Completați metoda după cum urmează:

 void privat DrawStatus () textură Texture2D; dacă (câștigător! = TicTacToePlayer.None) texture = winner == TicTacToePlayer.PlayerO? oWinner: xWinner;  altfel dacă (! winnable) texture = noWinner;  altceva texture = current == TicTacToePlayer.PlayerO? oTurn: xTurn;  Poziție dreptunghi = nou dreptunghi (spriteBatch.GraphicsDevice.Viewport.Width / 2 - (textură.Width / 2), 15, textură.Lățime, textură.Înălțime); spriteBatch.Draw (textura, poziția, culoarea albă);  

Această metodă nu diferă mult de celelalte metode de desen pe care le-ați creat până acum. Aveți o textură și o poziție și trebuie să desenați textura pe ecran. Partea interesantă a acestei metode este de a determina ce textură să fie desenată. Mai întâi verificați dacă există un câștigător. Dacă există, alegeți textura corectă a câștigătorului și trageți asta. Apoi, verificați dacă toate spațiile de rețea au fost ocupate și jocul nu mai poate fi câștigat. În acest caz, alegeți textura fără câștigător și desenați acel. Dacă nici una dintre aceste condiții nu este adevărată, atunci verificați care este rândul jucătorului, alegeți textura potrivită și trageți-o. Dacă compilați și executați proiectul în acest moment (apăsând F5), veți vedea că interfața arată că este rândul lui O:

În sfârșit, veți crea codul care atrage butonul de resetare. Acest lucru este destul de simplu. Dacă există un câștigător sau jocul nu mai poate fi câștigat, desenați textura butonului de resetare. Modificați DrawResetButton astfel încât:

 void privat DrawResetButton () if (câștigător! = TicTacToePlayer.None ||! winnable) spriteBatch.Draw (resetButton, resetButtonPosition, Color.White);  

În acest moment, ați creat tot codul necesar pentru desenarea interfeței și a tuturor pieselor sale componente. Acum, trebuie doar să vă ocupați de actualizarea jocului dvs. pe baza atingerilor de la jucători.

Manipularea tactile și actualizarea stării

Dacă ați urmat ultimul tutorial pe XNA, multe dintre codurile următoare vor arăta familiare. Manipularea atingerilor pe ecran este ceva destul de standard și numai în interiorul codului de manipulare tactil veți avea logica jocului. Pentru a începe, să punem codul de bază pentru manipularea tactilului în Actualizați metodă. Găsi Actualizați în tine Game1 clasați-l și modificați-l astfel:

 protejate override void Actualizare (GameTime gameTime) if (GamePad.GetState (PlayerIndex.One) .Buttons.Back == ButtonState.Pressed) this.Exit ();  TouchCollection atinge = TouchPanel.GetState (); dacă (atingeți && touchs.Count> 0) touching = true; TouchLocation touch = touchs.First (); HandleBoardTouch (atingere); HandleResetTouch (atingere);  altfel dacă (atinge.Count == 0) touching = false;  base.Update (gameTime);  

Există câteva lucruri în această metodă de a acorda atenție. În primul rând, veți observa o nouă emoționant care nu există. Această variabilă stochează dacă jucătorul atingea tabloul pe cel anterior Actualizați apela și împiedică un deget care nu mai poate juca de mai multe ori fără a fi eliberat de pe ecran. Adăuga emoționant ca variabilă instanță în partea de sus a declarației de clasă.

 bool atinge; 

De asemenea, veți observa că efectuați două apeluri de metode în cadrul Actualizați la metode care nu există încă. Adăugați aceste metode la declarația dvs. de clasă direct sub Actualizați metodă:

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

Acum, trecând prin Actualizați metoda vedeți că verificați dacă atingeți curent pe ecran. Dacă există atingeri și jucătorul nu atinge anterior ecranul, atunci apucați prima atingere și treceți-l la metodele care manipulează bordul atinge și reseta atingerile. Dacă playerul nu atinge ecranul și au fost anterior, atunci actualizați emoționant variabilă la falsă.

În acest moment, să completăm HandleBoardTouch și HandleResetTouch metode. Acestea corespund etapelor fluxului de lucru 5 și, respectiv, 6.

Consiliul de gestionare atinge

Când un utilizator atinge ecranul, jocul trebuie să facă câteva lucruri:

  • Verificați dacă atingerea se află în zona de joc
  • Dacă se află în zona de joc, verificați dacă punctul atins este deja ocupat
  • Dacă este fața locului nu ocupat, apoi plasați o piesă acolo și verificați dacă actualul jucător a câștigat
  • Dacă piesa jucată a fost câștigătoare, actualizați starea jocului ca atare. Dacă piesa jucată a ocupat ultimul loc disponibil, marcați jocul drept unwinnable
  • În cele din urmă, schimbați jucătorul curent

Actualizați HandleBoardTouch să citiți după cum urmează, tratând toți pașii de mai sus:

 privat void HandleBoardTouch (atingere TouchLocation) if (câștigător == TicTacToePlayer.None) pentru (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;      

După cum puteți vedea, această metodă urmează conturul de bază de mai sus. Dacă nu există un câștigător, acesta se repetă peste fiecare spațiu de rețea, verifică dacă atingerea este în acel spațiu, verifică dacă spațiul este deschis și apoi plasează o bucată acolo. Verificarea unui câștigător și asigurarea faptului că jocul este în continuare câștigător sunt tratate prin alte metode. Să eliminăm aceste metode acum. Dedesubt HandleBoardTouch , adăugați următorul cod:

 private void CheckForWin (player TicTacToePlayer)  void private CheckForWinnable ()  

Pentru moment, lăsați aceste metode goale și compilați și executați jocul. Încercați să atingeți bordul făcând clic pe emulator și urmăriți schimbarea mesajului de stare și afișarea pieselor de redare. Esti pe drumul spre un joc complet acum!

Condiții de câștig

În acest moment ajungeți la carnea reală a jocului, logica câștigătoare. După cum sa discutat anterior, o situație câștigătoare apare atunci când piesele unui jucător ocupă una dintre rânduri, una dintre coloane sau una dintre cele două diagonale. Jocul devine imposibil de câștigat atunci când nu este declarat niciun câștigător și nu mai sunt locuri rămase neocupate. Pentru acest joc, folosim o matrice multidimensională pentru a stoca starea rețelei și a ieși din cutie. C # nu oferă metode pentru a verifica rânduri, coloane sau diagonale. Din fericire, limba acceptă o caracteristică minunată numită metode de extensie pe care o veți folosi aici pentru a vă face codul un pic mai curat.

Crearea asistenților

Pentru a crea metode de extensie, trebuie mai întâi să creați o nouă clasă. Faceți clic pe numele proiectului din Solution Explorer și faceți clic pe "Add> Class ...". Denumiți clasa MultiDimensionalArrayExtensions și faceți clic pe "Adăugați". Atunci când noul fișier se deschide pentru editare, modificați-l astfel încât declarația de clasă să arate astfel:

 clasa publică statică MultiDimensionalArrayExtensions  

Veți vedea că ați adăugat modificatorii public și static la declarația de clasă. Acest lucru este necesar pentru crearea metodelor de extensie. Acum, vom crea câteva metode de care vom avea nevoie, fiecare dintre ele returnându-se IEnumerable pentru interogare ușoară:

  • Row - Returnează toate elementele dintr-un anumit rând
  • Column - Returnează toate elementele dintr-o anumită coloană
  • Diagonal - Returnează toate elementele dintr-o diagonală
  • Toate - Returnează toate elementele din matricea multidimensională

Modificați din nou clasa, adăugând metodele după cum urmează:

 clasa publică statică MultiDimensionalArrayExtensions public static IEnumerable Rând(acest T [,] matrice, int rând) var columnLower = array.GetLowerBound (1); var coloanăUpper = array.GetUpperBound (1); pentru (int i = columnLower; i <= columnUpper; i++)  yield return array[row, i];   public static IEnumerable Coloană(acest T [,] array, coloană int) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); pentru (int i = rowLower; i <= rowUpper; i++)  yield return array[i, column];   public static IEnumerable Diagonală(această direcție T [,], direcția DiagonalDirection) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var colinaLower = array.GetLowerBound (1); var coloanăUpper = array.GetUpperBound (1); pentru (int rând = rândUrmător, coloană = coloanăUrmător; rând <= 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 Toate(acest T [,] matrice) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var colinaLower = array.GetLowerBound (1); var coloanăUpper = array.GetUpperBound (1); pentru (rândul int = rândul rândul rând; rândul <= rowUpper; row++)  for (int column = columnLower; column <= columnUpper; column++)  yield return array[row, column];     

Puteți vedea că nu există multe pentru aceste metode. Pentru fiecare dintre ele, o anumită parte a matricei multidimensionale este repetată și acea porțiune a matricei este returnată ca parte dintr- IEnumerable. Singura parte cu adevărat dificilă poate fi utilizarea Randament cuvinte cheie. O explicație a comportamentului acelui cuvânt cheie este în afara domeniului de aplicare al acestui articol, dar referința C # pe MSDN pentru cuvântul cheie de randament poate fi de ajutor dacă doriți să aflați mai multe. Ca o notă laterală, o mare parte din munca pe aceste metode de extensie este luată dintr-o contribuție de utilizator pe StackOverflow pe care o puteți găsi aici

Implementarea logicii Win

Acum, că metodele de extensie necesare sunt implementate, ar trebui să fie destul de ușor de implementat logica câștigurilor. Să ne întoarcem la CheckForWin metodă și să o pună în aplicare. Actualizați metoda de citire după cum urmează:

 private void CheckForWin (playerul TicTacToePlayer) Func checkWinner = b => b == player; (checkWinner) || grid.Row (1) .Toate (checkWinner) || grid.Row (2) .Toate (checkWinner) || grid.Column (0) .All ( checkWinner) || grid.Column (1). Toate (checkWinner) || grid.Column (2). Toate (checkWinner) || grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownRight). Toate (checkWinner) || grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownLeft). Toate (checkWinner)) winner = player;  

Având în vedere ceea ce știi deja din crearea metodelor de extensie, acest lucru ar trebui să fie destul de simplu de descifrat. Mai întâi creați o "Func": http: //msdn.microsoft.com/en-us/library/bb549151.aspx obiect care acționează un delegat și vă permite să utilizați o declarație lambda (care b => b == player parte) pentru a interoga un IEnumerable (precum cele returnate din metoda extensiei) și returnați a bool. Apoi aplicați acest lucru FUNC obiect pe fiecare rând, coloană și diagonală folosind IEnumerable.All metodă. Dacă oricare din aceste cazuri este adevărat, atunci atribuiți câştigător instanță variabilă la jucător parametru. Dacă nici unul dintre aceste cazuri nu este adevărat, atunci nu se întâmplă nimic.

Acum, modificați-vă CheckForWinnable metodă:

 private void CheckForWinnable () if (câștigător == TicTacToePlayer.None) Func checkNone = b => b == TicTacToePlayer.None; dacă (! grid.All () Orice (checkNone)) winnable = false;  

Această metodă este foarte asemănătoare CheckForWin. În primul rând, verificați dacă jocul are un câștigător. Dacă nu, creați o FUNC obiect care va verifica dacă un element este egal cu TicTacToePlayer Nici unul. Apoi aplicați acest lucru FUNC împotriva tuturor spațiilor din rețea, verificând dacă vreunul dintre spații este neocupat. Dacă nu există, atunci jocul nu mai poate fi câștigat și puteți comuta variabila instanță winnable.

Terminand

În acest moment, jocul dvs. este gata să meargă. Puteți să vă compilați și să executați proiectul prin lovirea F5 și începerea jocului (fie de unul singur, fie de la un partener). Realizați plasarea pieselor pe placă, urmăriți schimbarea mesajului de stare și vedeți ce se întâmplă atunci când câștigați. După ce câștigi sau desenezi, dă clic pe butonul de resetare și urmărești ca jocul să revină la starea inițială.

În acest moment există o varietate de lucruri diferite pe care le puteți face. S-ar putea pune în aplicare un număr câștigător care să arate câte ori a câștigat fiecare jucător. Puteți schimba modul în care se afișează piesele sau puteți adăuga o animație rece când un câștigător este declarat. Ați putea tema jocul pentru a deveni un pic mai interesant, probabil prin prăbușirea Alianței Rebele împotriva Imperiului Galactic?

În acest moment, depinde de dvs. să vă extindeți și să dezvoltați ceea ce doriți. Sper că vă place să urmați acest tutorial la fel de mult cum mi-a plăcut scrisul și aștept cu nerăbdare să vă aud comentariile.

Cod