XNA ist ein hochentwickeltes Framework zur Erstellung von Spielen für Microsoft-Geräte einschließlich Windows-PCs, Xbox 360 und das brandneue Windows Phone 7-Betriebssystem. In einem früheren Tutorial haben wir die Grundlagen des XNA-Frameworks behandelt, einschließlich der Verarbeitung von Eingaben und der Anzeige von Sprites. In diesem Artikel erfahren Sie, wie Sie diese Fähigkeiten mit einer eigenen Spielidee kombinieren, um etwas Spaß zu schaffen und leicht zu erlernen.
In diesem Tutorial erstellen Sie ein einfaches Tic-Tac-Toe-Spiel, das Sie mit Freunden spielen können. Tic-Tac-Toe ist ein einfaches Spiel, bei dem zwei Spieler abwechselnd Züge auf ein Drei-zu-Drei-Raster setzen. Der erste Spieler verwendet ein O und der zweite Spieler ein X. Um das Spiel zu gewinnen, muss ein Spieler drei seiner Charaktere in eine Reihe, eine Spalte oder eine Diagonale einordnen.
Dieses Spiel ist zwar einfach, erfordert jedoch ein paar unterschiedliche Fähigkeiten. Zuerst verwenden Sie XNA und seine Grafikfunktionen, um Ihr Spiel zu erstellen. Daher müssen Sie mit der Anzeige von Sprites vertraut sein. Zweitens müssen Sie wissen, wie Sie mit dem Touchpanel des Telefons umgehen. Glücklicherweise bietet XNA eine API auf hoher Ebene, um auf diese Berührungen zuzugreifen. Schließlich müssen Sie ein wenig Programmier- und Logik-Know-how anwenden, um den Gewinner zu bestimmen. Für dieses Tutorial wird Ihnen viel davon gegeben. Wenn Sie in Zukunft Spiele entwickeln, müssen Sie Ihre eigenen Ideen und Ihre eigene Logik entwickeln.
Stellen Sie zunächst sicher, dass Sie die neuesten Windows Phone 7-Entwicklungstools installiert haben. Wenn Sie Ihre Tools seit dem letzten WP7-Lernprogramm für MobileTuts nicht aktualisiert haben, sollten Sie das Microsoft Download Center besuchen und die RTW-Version erhalten. Diese neueste Version wird mit dem endgültigen Emulator geliefert, der zeigt, wie Ihre Apps auf der Hardware des Releasetags funktionieren.
Wenn Sie sichergestellt haben, dass Ihre Tools auf dem neuesten Stand sind, öffnen Sie Visual Studio 2010 und klicken Sie in der linken Seitenleiste auf den Link „Neues Projekt…“. Wählen Sie im daraufhin angezeigten Dialogfeld "XNA Game Studio 4" in der linken Spalte aus und stellen Sie sicher, dass rechts die Vorlage "Windows Phone Game (4.0)" ausgewählt ist. Geben Sie Ihrem Projekt einen geeigneten Namen wie "TicTacToe" und bestätigen Sie, dass das Kontrollkästchen "Verzeichnis für Lösung erstellen" aktiviert ist. Wenn Sie dies alles richtig gemacht haben, sollte Ihr Dialogfeld mit dem folgenden Bild übereinstimmen:
Klicken Sie auf "OK", um Ihr neues Projekt zu erstellen. Visual Studio 2010 generiert die erforderlichen Dateien in Ihrem angegebenen Verzeichnis und öffnet sie Game1.cs
zur Bearbeitung.
Da Sie Sprites für alle Spielgrafiken in diesem Projekt verwenden, müssen Sie die erforderlichen Elemente in Ihr Projekt importieren. Im Download dieses Tutorials finden Sie eine Medien
Verzeichnis mit einer Vielzahl von Bildern. Suchen Sie im Solution Explorer auf der rechten Seite des Bildschirms das Content-Projekt (TicTacToeContent) und klicken Sie mit der rechten Maustaste darauf. Wählen Sie im Kontextmenü „Hinzufügen> Vorhandenes Element…“. Wenn sich das Dialogfeld öffnet, navigieren Sie zu Medien
Ordner, den Sie aus dem Tutorial-Download entpackt haben, und wählen Sie alle darin enthaltenen Bilder aus. Sie sollten in der Lage sein, anhand der Bildnamen genau zu erkennen, was jedes Element enthält.
Nachdem Sie Ihre Medien importiert haben, sollte Ihr Solution Explorer folgendermaßen aussehen:
Nachdem Ihr Medium in das an Ihre Lösung angehängte Content-Projekt importiert wurde, müssen Sie jedes Bild als separate Textur laden. Da Sie diese Texturen im gesamten Spiel verwenden, werden Sie sie in Feldern Ihrer Spielklasse speichern. Öffnen Sie die Datei Game1.cs und fügen Sie die folgenden Felder oben in Ihre Klassendeklaration ein:
Texture2D gridTexture; Rechteck gridRectangle; Texture2D resetButton; Rechteck resetButtonPosition; Texture2D oPiece; Texture2D xPiece; Texture2D oWinner; Texture2D xWinner; Texture2D noWinner; Texture2D oTurn; Texture2D xTurn;
Sie sehen, dass jedes der importierten Bilder ein Feld hat, um es zu sichern. Zusätzlich haben das Hauptspielgitter und die Textur der Rücksetztasten Felder vom Typ Rechteck
die zum Positionieren dieser Elemente verwendet wird. Diese werden als Felder gespeichert, da sie sich im Laufe des Spiels nicht ändern.
Nachdem Sie nun die entsprechenden Felder erstellt haben, ist es Zeit, das zu instanziieren Textur2D
und Rechteck
Objekte, die den Feldern zugeordnet sind. Scrollen Sie nach unten zu Ihrem Game1.cs
Datei, bis Sie die LoadContent
Methode. Fügen Sie innerhalb dieser Methode den folgenden Code nach der Zeile ein, die liest spriteBatch = new SpriteBatch (GraphicsDevice);
:
gridTexture = Content.Load("TicTacToe_Grid"); gridRectangle = new Rectangle (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 = new Rectangle (spriteBatch.GraphicsDevice.Viewport.Width / 2 - (resetButton.Width / 2), spriteBatch.GraphicsDevice.Viewport.Height - 95, resetButton.Width); 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");
Nachdem Sie die Sprites geladen haben, die vom Spiel verwendet werden, müssen Sie den Workflow festlegen, mit dem das Spiel ausgeführt wird. Für die Zwecke von Tic-Tac-Toe ist dies ziemlich einfach und sieht in etwa wie folgt aus:
Wie Sie wahrscheinlich feststellen können, lassen sich diese Schritte in eine von zwei grundlegenden Kategorien einteilen: Zeichnen oder Aktualisieren. Durchsuchen der Game1.cs
Datei Sie werden sehen, dass Sie zwei Methoden haben, Zeichnen
und Aktualisieren
Das sind die perfekten Container für den Code, der zur Beschreibung des Workflows erforderlich ist.
Wenn Sie sich den Arbeitsablauf anschauen, können Sie feststellen, dass es vier verschiedene Elemente gibt, über die Sie nachverfolgen können, um den Spielstatus zu verwalten. Zunächst müssen Sie den Status jedes Rasterfeldes auf dem Spielfeld verfolgen. Dazu verwenden Sie eine benutzerdefinierte Aufzählung und ein mehrdimensionales Array. Als Nächstes müssen Sie nachverfolgen, ob und von wem das Spiel gewonnen wurde. Drittens müssen Sie verfolgen, wer an der Reihe ist. Schließlich müssen Sie nachverfolgen, ob das Spiel gewinnbar ist. Dieses Element wird als initialisiert wahr
und wird neu berechnet, nachdem jeder Spieler an der Reihe ist. Wenn alle Rasterfelder ausgefüllt sind, ändert sich dies zu falsch
.
Sie beginnen mit der Definition der benutzerdefinierten Aufzählung, die einen Spieler für Ihr Spiel beschreibt. Fügen Sie oben in Ihrer Klassendatei über Ihrer Klassendeklaration den folgenden Code ein:
public enum TicTacToePlayer Keine, PlayerO, PlayerX
Diese Aufzählung umfasst drei Spieler (None, PlayerO und PlayerX) und wird verwendet, um sowohl den Gitterstatus als auch den Spielgewinner zu verfolgen. Fügen Sie nun die Instanzvariablen hinzu, mit denen Sie den Status des Spiels nachverfolgen können. Diese Elemente sollten oben in Ihrer Klassendeklaration eingefügt werden:
Bool gewinnbar; TicTacToePlayer-Gewinner; TicTacToePlayer aktuell; TicTacToePlayer [,] Raster;
Sie speichern hier vier Dinge. Zuerst legen Sie fest, ob das Spiel noch gewinnbar ist. Zweitens erklären Sie den Gewinner. Wenn der Gewinner keine ist, wird das Spiel fortgesetzt. Danach speichern Sie den aktuellen Player. Zum Schluss speichern Sie den Netzzustand. Zu diesem Zeitpunkt müssen Sie noch jede dieser Variablen initialisieren. Wenn Sie vorausdenken, wissen Sie, dass Sie sie jedes Mal neu initialisieren müssen, wenn jemand auf die Schaltfläche Zurücksetzen klickt. Daher können wir eine neue Methode erstellen, die diese Initialisierung handhabt. Fügen Sie Ihrer Klasse die neue Methode unter dem hinzu Initialisieren
Methode wie folgt:
privat void Reset () gewinnbar = wahr; Gewinner = TicTacToePlayer.None; grid = neuer TicTacToePlayer [3, 3]; für (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) grid[i, j] = TicTacToePlayer.None;
Rufen Sie nun diese neue Methode aus der Initialisieren
Methode, indem Sie es wie folgt ändern:
protected override void Initialize () Reset (); base.Initialize ();
An diesem Punkt speichern Sie alle Daten, die Sie benötigen, daher sollte es einfach sein, die Oberfläche zu zeichnen.
Bevor Sie mit dem Zeichnen beginnen, müssen Sie Ihre bevorzugte Breite und Höhe für Ihr Gerät festlegen. Sie werden dies innerhalb der tun Game1
Konstrukteur. Ändern Sie es wie folgt zu lesen:
public Game1 () graphics = new GraphicsDeviceManager (this); Content.RootDirectory = "Inhalt"; graphics.PreferredBackBufferWidth = 480; graphics.PreferredBackBufferHeight = 800; // Die Bildrate beträgt standardmäßig 30 fps für Windows Phone. TargetElapsedTime = TimeSpan.FromTicks (333333);
Sie haben Anweisungen hinzugefügt, dass die Breite des hinteren Puffers 480 Pixel und die Höhe 800 Pixel betragen soll. Dies vereinfacht das Zeichnen der restlichen Komponenten für das Spiel erheblich.
Der Einfachheit halber führen Sie jeden Zeichnungsschritt in einer separaten Methode aus. Diese Methoden werden dann von der Basis aus aufgerufen Zeichnen
Methode, die bereits existiert. Beginnen wir damit, einige gute Namen für jeden der Workflow-Schritte des Spiels zu überdenken, Methoden dieses Namens zu erstellen und diesen Methoden Aufrufe von hinzuzugeben Zeichnen
. Meines Erachtens beschreiben die folgenden Methodennamen sowohl ihre Arbeitsweise als auch die Arbeitsschritte des Arbeitsablaufs ausreichend:
Erstellen Sie diese Methoden jetzt, indem Sie den folgenden Code unterhalb Ihres einfügen Zeichnen
Methode:
private void DrawGrid () private void DrawPieces () private void DrawStatus () private void DrawResetButton ()
Sie schreiben den Code für diese Methoden in Kürze, aber jetzt müssen Sie sie zu Ihrem hinzufügen Zeichnen
Methode, indem Sie es wie folgt ändern:
protected override void Draw (GameTime gameTime) GraphicsDevice.Clear (Color.Black); spriteBatch.Begin (); DrawGrid (); DrawPieces (); DrawStatus (); DrawResetButton (); spriteBatch.End (); base.Draw (gameTime);
Sie werden bemerken, dass Sie die Aufrufe Ihrer Hilfemethoden mit Anrufen in umgeben haben spriteBatch
Objekt ist Start
und Ende
Methoden. Sie tun dies, weil Ihre Hilfemethoden alle Sprites zeichnen und das Aufruf von Start
und Ende
Paar einmal in Zeichnen
anstatt innerhalb jeder Hilfsmethode.
Lassen Sie uns nun daran arbeiten, dass das Spielfeld angezeigt wird. Das Wiedergabegitter ist ein 480 Pixel breites und 800 Pixel hohes Bild mit einem transparenten Hintergrund und einem weißen Raster von 150 Pixel breiten Feldern in der Mitte. Sie haben es früher importiert. Das Zeichnen auf dem Bildschirm des Telefons könnte nicht einfacher sein. Sie nehmen die geladene und gespeicherte Textur in die gridTexture
Variable und zeichnen Sie es, indem Sie es mit dem zuvor instanziierten positionieren gridRectangle
Variable, beide Elemente an die übergeben spriteBatch
Objekt ist Zeichnen
Methode. Ändere dein DrawGrid
Methode wie folgt zu lesen:
private void DrawGrid () spriteBatch.Draw (gridTexture, gridRectangle, Color.White);
Speichern Sie die Datei, in der Sie arbeiten, und drücken Sie F5, um Ihr Projekt zu kompilieren und auszuführen. Der Windows Phone 7-Emulator sollte erscheinen und Ihr Tic-Tac-Toe-Raster auf schwarzem Hintergrund anzeigen, genau wie das folgende Bild:
Nun, da das Raster vorhanden ist, zeichnen wir die Spielsteine. An dieser Stelle können wir eine einfache Logik anwenden, um die Stücke anzuzeigen, aber nichts wird angezeigt, bis wir den Code hinzufügen, um Berührungen zu handhaben und das Spiel zu spielen. Ändern Sie Ihre DrawPieces
Methode wie folgt:
private void DrawPieces () für (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);
Wenn Sie ein scharfes Auge haben (oder wahrscheinlicher, Visual Studio zeigt Ihnen rote Linien), werden Sie sehen, dass das GetGridSpace
Methode fehlt. GetGridSpace
ist eine bequeme Methode, die dazu beiträgt, dass ein wenig Code aus dem DrawPieces
Methode und wird sich auch als nützlich erweisen, wenn Sie später versuchen, Berührungen zu bearbeiten. Fügen Sie es wie folgt am Ende Ihrer Klassendeklaration hinzu:
privates Rechteck GetGridSpace (int-Spalte, int-Zeile, Int-Breite, Int-Höhe) int centerX = spriteBatch.GraphicsDevice.Viewport.Width / 2; int centerY = spriteBatch.GraphicsDevice.Viewport.Height / 2; int x = centerX + ((Spalte - 1) * 150) - (Breite / 2); int y = centerY + ((Reihe - 1) * 150) - (Höhe / 2); Neues Rechteck zurückgeben (x, y, Breite, Höhe);
Nun wollen wir uns den Rest anschauen DrawPieces
. Diese Methode ist etwas komplizierter als die DrawGrid
aber es sollte immer noch ziemlich leicht zu verstehen sein. Sie durchlaufen jede Zeile und jede Spalte des Spielfelds, die im gespeichert sind Gitter
Variable, und überprüfen Sie den Status dieses Rasterfelds. Wenn das Rasterfeld einen anderen Spieler als „Keiner“ enthält, zeichnen Sie die entsprechende Textur. Sie verwenden den ternären Operator, um die korrekte Textur basierend auf dem Zustand des Rasterbereichs zu erfassen und sie dann mit dem Rechteck zu zeichnen, das Sie erhalten haben GetGridSpace
.
Die nächste Ausgabe, mit der Sie sich befassen, ist das Zeichnen des aktuellen Status. Der Status zeigt an, wer an der Reihe ist, wer das Spiel gewonnen hat oder ob das Spiel unentschieden ist. Füllen Sie die Methode wie folgt aus:
private void DrawStatus () Texture2D-Textur; if (Gewinner! = TicTacToePlayer.None) Textur = Gewinner == TicTacToePlayer.PlayerO? oWinner: xWinner; else if (! gewinnbar) texture = noWinner; else texture = current == TicTacToePlayer.PlayerO? oTurn: xTurn; Rectangle position = new Rectangle (spriteBatch.GraphicsDevice.Viewport.Width / 2 - (Textur.Width / 2), 15, Textur.Width, Textur.Height); spriteBatch.Draw (Textur, Position, Color.White);
Diese Methode unterscheidet sich nicht wesentlich von den anderen von Ihnen erstellten Zeichenmethoden. Sie haben eine Textur und eine Position und müssen die Textur auf dem Bildschirm zeichnen. Der interessante Teil dieser Methode ist die Bestimmung der zu zeichnenden Textur. Sie prüfen zunächst, ob es einen Gewinner gibt. Wenn ja, wählen Sie die richtige Sieger-Textur und zeichnen diese. Dann prüfen Sie, ob alle Rasterfelder belegt sind und das Spiel nicht mehr gewinnbar ist. Wenn dies der Fall ist, wählen Sie die Textur ohne Gewinner und zeichnen diese. Wenn keine dieser Bedingungen zutrifft, prüfen Sie, welcher Spieler an der Reihe ist, wählen die richtige Ziehtextur und zeichnen diese. Wenn Sie Ihr Projekt zu diesem Zeitpunkt kompilieren und ausführen (durch Drücken von F5), sehen Sie, dass die Benutzeroberfläche anzeigt, dass O an der Reihe ist:
Zum Schluss erstellen Sie den Code, der die Rücksetztaste zeichnet. Das ist ziemlich einfach. Wenn es einen Gewinner gibt oder das Spiel nicht mehr gewinnbar ist, zeichnen Sie die Textur der Reset-Schaltfläche. Modifiziere den DrawResetButton
Methode, so dass es wie folgt lautet:
private void DrawResetButton () if (winner! = TicTacToePlayer.None ||! gewinnbar) spriteBatch.Draw (resetButton, resetButtonPosition, Color.White);
An diesem Punkt haben Sie den gesamten Code erstellt, der zum Zeichnen der Benutzeroberfläche und aller zugehörigen Komponenten erforderlich ist. Jetzt müssen Sie nur noch die Aktualisierung Ihres Spiels basierend auf den Berührungen der Spieler durchführen.
Wenn Sie das letzte Lernprogramm für XNA befolgt haben, wird der folgende Code bekannt sein. Die Handhabung von Berührungen auf dem Bildschirm ist ziemlich normal und es ist nur innerhalb des Berührungshandhabungscodes, dass Sie Ihre Spielelogik haben. Lassen Sie uns zunächst den grundlegenden Code für die Handhabung von Berührungen in die Aktualisieren
Methode. Finden Aktualisieren
in deiner Game1
klassifizieren und wie folgt lesen:
geschütztes überschreiben void Update (GameTime gameTime) if (GamePad.GetState (PlayerIndex.One) .Buttons.Back == ButtonState.Pressed) this.Exit (); TouchCollection touches = TouchPanel.GetState (); if (! Berühren von && Berührungen.Zahl> 0) Berühren = true; TouchLocation touch = touches.First (); HandleBoardTouch (berühren); HandleResetTouch (touch); else if (touches.Count == 0) Berühren = falsch; base.Update (gameTime);
Es gibt einige Dinge in dieser Methode, auf die Sie achten müssen. Zuerst wirst du ein neues bemerken berühren
Variable, die nicht existiert Diese Variable speichert, ob der Spieler die Tafel auf der vorherigen Seite berührt hat oder nicht Aktualisieren
aufrufen und verhindert, dass ein Finger mehrmals gespielt wird, ohne den Bildschirm zu verlassen. Hinzufügen berühren
als Instanzvariable oben in Ihrer Klassendeklaration.
bool berühren;
Sie werden auch bemerken, dass Sie zwei Methodenaufrufe innerhalb von durchführen Aktualisieren
Methode zu Methoden, die noch nicht existieren. Fügen Sie diese Methoden Ihrer Klassendeklaration direkt unter dem hinzu Aktualisieren
Methode:
private void HandleBoardTouch (TouchLocation touch) private void HandleResetTouch (TouchLocation touch)
Nun geh ich durch die Aktualisieren
Methode, die Sie sehen, dass Sie auf dem Bildschirm nach aktuellen Berührungen suchen. Wenn Berührungen vorhanden sind und der Player den Bildschirm zuvor nicht berührt hat, greifen Sie zur ersten Berührung und geben Sie die Methode an die Methoden weiter, die die Berührungen der Platine behandeln und die Berührungen zurücksetzen. Wenn der Player den Bildschirm nicht berührt und sie zuvor waren, aktualisieren Sie die berühren
Variable auf false.
Füllen Sie an dieser Stelle die aus HandleBoardTouch
und HandleResetTouch
Methoden. Diese entsprechen den Arbeitsablaufschritten 5 bzw. 6.
Wenn ein Benutzer den Bildschirm berührt, muss das Spiel ein paar Dinge tun:
Aktualisieren Sie die HandleBoardTouch
Lesen Sie wie folgt und behandeln Sie alle obigen Schritte:
private void HandleBoardTouch (TouchLocation touch) if (Gewinner == TicTacToePlayer.None) für (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;
Wie Sie sehen, folgt diese Methode der oben beschriebenen grundlegenden Gliederung. Wenn es keinen Gewinner gibt, durchläuft es jedes Rasterfeld, überprüft, ob sich die Berührung in diesem Feld befindet, überprüft, ob das Feld offen ist, und legt ein Stück dort ab. Wenn Sie nach einem Gewinner suchen und sicherstellen, dass das Spiel immer noch gewinnbar ist, können Sie andere Methoden verwenden. Lassen Sie uns diese Methoden jetzt ausreden. Unter der HandleBoardTouch
fügen Sie den folgenden Code hinzu:
private void CheckForWin (TicTacToePlayer-Player) private void CheckForWinnable ()
Lassen Sie diese Methoden zunächst leer und kompilieren Sie Ihr Spiel. Berühren Sie die Platine, indem Sie auf den Emulator klicken, und beobachten Sie, wie sich die Statusmeldung ändert und die abgespielten Teile angezeigt werden. Du bist jetzt auf dem Weg zu einem kompletten Spiel!
An diesem Punkt gelangen Sie zum eigentlichen Fleisch des Spiels, der Gewinnlogik. Wie zuvor diskutiert, tritt ein Gewinnzustand auf, wenn die Steine eines Spielers eine der Reihen, eine der Spalten oder eine der beiden Diagonalen besetzen. Das Spiel kann nicht gewonnen werden, wenn kein Gewinner bekannt ist und keine freien Plätze übrig sind. Für dieses Spiel verwenden wir ein mehrdimensionales Array, um den Zustand des Gitters zu speichern. C # bietet keine Kontrollmethoden für Zeilen, Spalten oder Diagonalen. Glücklicherweise unterstützt die Sprache eine fantastische Funktion, die als Erweiterungsmethoden bezeichnet wird, die Sie hier verwenden, um Ihren Code ein wenig sauberer zu machen.
Um die Erweiterungsmethoden zu erstellen, müssen Sie zuerst eine neue Klasse erstellen. Klicken Sie im Projektmappen-Explorer auf den Namen Ihres Projekts und klicken Sie auf „Hinzufügen> Klasse…“. Benennen Sie Ihre Klasse MultiDimensionalArrayExtensions und klicken Sie auf "Hinzufügen". Wenn Ihre neue Datei zum Bearbeiten geöffnet wird, ändern Sie sie so, dass Ihre Klassendeklaration folgendermaßen aussieht:
öffentliche statische Klasse MultiDimensionalArrayExtensions
Sie werden sehen, dass Sie die Modifikatoren hinzugefügt haben Öffentlichkeit
und statisch
zur Klassendeklaration. Dies ist zum Erstellen von Erweiterungsmethoden erforderlich. Nun werden wir ein paar Methoden entwickeln, die wir brauchen, von denen jede eine zurückgibt IEnumerable
zur einfachen Abfrage:
Ändern Sie Ihre Klasse erneut und fügen Sie die Methoden wie folgt hinzu:
öffentliche statische Klasse MultiDimensionalArrayExtensions public static IEnumerableReihe (dieses T [,] Array, int row) var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int i = columnLower; i <= columnUpper; i++) yield return array[row, i]; public static IEnumerable Säule (dieses T [,] Array, int Spalte) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); für (int i = rowLower; i <= rowUpper; i++) yield return array[i, column]; public static IEnumerable Diagonal (dieses T [,] - Array, DiagonalDirection-Richtung) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int row = 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 Alles (dieses T [,] -Array) var rowLower = array.GetLowerBound (0); var rowUpper = array.GetUpperBound (0); var columnLower = array.GetLowerBound (1); var columnUpper = array.GetUpperBound (1); for (int row = rowLower; row) <= rowUpper; row++) for (int column = columnLower; column <= columnUpper; column++) yield return array[row, column];
Sie können sehen, dass es bei diesen Methoden nicht viel gibt. Für jeden von ihnen wird ein bestimmter Teil des mehrdimensionalen Arrays iteriert und dieser Teil des Arrays wird als Teil eines zurückgegeben IEnumerable
. Der einzig wirklich knifflige Teil kann die Verwendung der sein Ausbeute
Stichwort. Eine Erläuterung des Verhaltens dieses Schlüsselworts liegt außerhalb des Umfangs dieses Artikels. Die C # -Referenz auf MSDN für das Fließschlüsselwort kann hilfreich sein, wenn Sie mehr erfahren möchten. Als Nebenbemerkung wird ein Großteil der Arbeit an diesen Erweiterungsmethoden einem Benutzerbeitrag zu StackOverflow entnommen, den Sie hier finden
Nun, da die erforderlichen Erweiterungsmethoden implementiert sind, sollte es ziemlich einfach sein, die Win-Logik zu implementieren. Gehen wir zurück zum CheckForWin
Methode und implementieren Sie es. Aktualisieren Sie die Methode wie folgt:
private void CheckForWin (TicTacToePlayer-Player) FunccheckWinner = b => b == Spieler; if (grid.Row (0) .All (checkWinner) || grid.Row (1) .All (checkWinner) || grid.Row (2) .All (checkWinner) || grid.Column (0) .All ( checkWinner) || grid.Column (1) .All (checkWinner) || grid.Column (2) .All (checkWinner) || grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownRight) .All (checkWinner) || grid.Diagonal (MultiDimensionalArrayExtensions.DiagonalDirection.DownLeft) .All (checkWinner)) winner = player;
In Anbetracht dessen, was Sie bereits von der Erstellung der Erweiterungsmethoden wissen, sollte dies ziemlich einfach zu entschlüsseln sein. Sie erstellen zuerst eine "Func": http: //msdn.microsoft.com/de-de/library/bb549151.aspx
Objekt, das als Delegat fungiert und die Verwendung einer Lambda-Anweisung (das b => b == Spieler
Teil) eine Abfrage IEnumerable
(wie diejenigen, die von der Erweiterungsmethode zurückgegeben wurden) und geben Sie a zurück bool
. Sie wenden das dann an Func
Objekt über jede Zeile, Spalte und Diagonale mit der IEnumerable.All
Methode. Wenn einer dieser Fälle zutrifft, weisen Sie das zu Gewinner
Instanzvariable für die Spieler
Parameter. Wenn keiner dieser Fälle zutrifft, passiert nichts.
Ändern Sie jetzt Ihre CheckForWinnable
Methode:
private void CheckForWinnable () if (Gewinner == TicTacToePlayer.None) FunccheckNone = b => b == TicTacToePlayer.None; if (! grid.All (). Any (checkNone)) winnable = false;
Diese Methode ist sehr ähnlich CheckForWin
. Zuerst prüfen Sie, ob das Spiel einen Gewinner hat. Wenn nicht, erstellen Sie eine Func
Objekt, das prüft, ob ein Element dem entspricht TicTacToePlayer
Keiner
. Sie wenden das dann an Func
gegen alle Leerzeichen im Raster und prüfen, ob eines der Leerzeichen frei ist. Ist dies nicht der Fall, kann das Spiel nicht mehr gewonnen werden, und Sie können die Instanzvariable umschalten gewinnbar
.
An diesem Punkt ist dein Spiel einsatzbereit. Sie können Ihr Projekt kompilieren und ausführen, indem Sie F5 drücken und mit dem Spielen beginnen (entweder von Ihnen selbst oder mit einem Partner). Wechseln Sie abwechselnd Teile auf das Brett, beobachten Sie, wie sich die Statusmeldung ändert, und sehen Sie, was passiert, wenn Sie gewinnen. Sobald Sie gewonnen oder unentschieden gespielt haben, klicken Sie auf die Schaltfläche zum Zurücksetzen und beobachten Sie, wie das Spiel in seinen ursprünglichen Zustand zurückkehrt.
An dieser Stelle gibt es verschiedene Möglichkeiten, die Sie tun können. Sie können einen Gewinnzähler implementieren, der angibt, wie oft jeder Spieler gewonnen hat. Sie können die Darstellung der Teile ändern oder eine coole Animation hinzufügen, wenn ein Gewinner bekannt gegeben wird. Sie könnten das Spiel thematisieren, um es ein wenig interessanter zu machen, indem Sie die Rebellenallianz gegen das galaktische Imperium antreten?
An diesem Punkt müssen Sie alles erweitern und entwickeln, was Sie möchten. Ich hoffe, Sie haben dieses Tutorial so gerne verfolgt, wie ich es geschrieben habe, und freuen uns auf Ihre Kommentare.