This article has been localized into German by the community.
In this article series, we're building a complete Snake game from scratch. It makes sense to start with the Introduction and then work your way through the articles one by one, to get the full understanding.
If you want to get the complete source code for the game at once, to get started modifying and learning from it right now, consider downloading all our samples!
Erstellen des Spielbereichs
Um unser SnakeWPF Spiel zu erstellen beginnen wir mit der Erstellung einer "Karte". Diese wird das begrenzte Gebiet sein, in welchem die Schlange sich aufhalten wird - eine Schlangengrube, sozusagen. Ich habe mich dazu entschieden, dass meine Schlangengrube wie ein Schachbrett aussehen soll. Es wird aus gleichgroßen Quadraten mit den selben Abmessungen wie der Körper der Schlange bestehen. Wir werden die Erstellung der Karte auf zwei Arten durchführen: Ein Teil davon wird in XAML umgesetzt, da es einfacher ist, während die sich wiederholenden Quadrate im Hintergrund durch Code-behind dynamisch gezeichnet werden sollen.
Spielbereich XAML
Also, lass uns mit dem XAML-Anteil anfangen. Ein simples Fenster mit einem Canvas Panel innerhalb eines Border Objekts, um ein abgegrenztes Gebiet zu erstellen:
<Window x:Class="WpfTutorialSamples.Games.SnakeWPFSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfTutorialSamples.Games"
mc:Ignorable="d"
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight">
<Border BorderBrush="Black" BorderThickness="5">
<Canvas Name="GameArea" ClipToBounds="True" Width="400" Height="400">
</Canvas>
</Border>
</Window>
Unser Spiel sieht jetzt so aus:
Wir verwenden einen "Canvas" als tatsächlichen Spielbereich, da es uns die volle Kontrolle über die Positionierung der hinzugefügten Objekte überlässt. Davon werden wir später Gebrauch machen. Jetzt allerdings müssen wir folgendes beachten:
- Für das Window-Objekt wurde weder Breite noch Höhe festgelegt - stattdessen definieren wir diese Werte für das Canvas-Objekt, da dies das Objekt ist, über das wir volle Kontrolle benötigen. Als nächstes stellen wir sicher, dass das Window-Objekt seine Größe entsprechend anpasst, indem wir die Eigenschaft SizeToContent auf WidthAndHeight ändern. Wenn wir stattdessen die Werte für Breite und Höhe im Window-Objekt festgelegt hätten, so würde der darin zur Verfügung stehende Platz davon abhängen, wie breit das Betriebssystem die Rahmen zeichnet, was durch Themes o. Ä. variieren kann.
- Wir setzen die Eigenschaft ClipToBounds des Canvas-Objekts auf "True". Das ist deshalb wichtig, da ansonsten neu hinzugefügte Objekte über die Grenzen des Canvas-Objekts hinausragen könnten.
Zeichnen des Hintergrunds durch Code-behind
Wie eingangs erwähnt, wünsche ich mir ein Schachbrettmuster als Hintergrund für meinen Spielbereich. Da ein Schachbrett aus vielen einzelnen Quadraten besteht, ist es einfacher, diese durch Code-behind zu erzeugen (oder ein Bild zu verwenden, was aber deutlich weniger dynamisch ist!). Das muss geschehen, sobald alle Objekte im Window-Objekt initialisiert/gerendert wurden und zu unserem Vorteil besitzt das Window-Objekt einen Event für solch einen Fall: Das ContentRendered-Event. Das fügen wir der Window-Objekt Deklaration hinzu:
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight" ContentRendered="Window_ContentRendered"
Jetzt wechseln wir zum Code-behind und legen los. Zu allererst benötigen wir eine festgelegte Größe, die wir verwenden um die Schlange, die Hintergrundquadrate usw. zu zeichnen. Das kann oben, in der Window-Klasse gemacht werden:
public partial class SnakeWPFSample : Window
{
const int SnakeSquareSize = 20;
.....
Jetzt, wird in unserem ContentRendered-Event die DrawGameArea()-Methode aufgerufen, welche uns den größten Teil der Arbeit abnehmen wird. Das sieht so aus:
private void Window_ContentRendered(object sender, EventArgs e)
{
DrawGameArea();
}
private void DrawGameArea()
{
bool doneDrawingBackground = false;
int nextX = 0, nextY = 0;
int rowCounter = 0;
bool nextIsOdd = false;
while(doneDrawingBackground == false)
{
Rectangle rect = new Rectangle
{
Width = SnakeSquareSize,
Height = SnakeSquareSize,
Fill = nextIsOdd ? Brushes.White : Brushes.Black
};
GameArea.Children.Add(rect);
Canvas.SetTop(rect, nextY);
Canvas.SetLeft(rect, nextX);
nextIsOdd = !nextIsOdd;
nextX += SnakeSquareSize;
if(nextX >= GameArea.ActualWidth)
{
nextX = 0;
nextY += SnakeSquareSize;
rowCounter++;
nextIsOdd = (rowCounter % 2 != 0);
}
if(nextY >= GameArea.ActualHeight)
doneDrawingBackground = true;
}
}
Wie bereits erwähnt, setzt dieser Artikel etwas mehr Vorwissen über C# voraus, als die anderen Artikel dieses Tutorials, daher erkläre ich nicht jede einzelne Zeile, beschreibe aber die Schritte im Groben: In der while-Schleife erstellen wir immer mehr Instanzen des Rectangle-Objekts und fügen diese dem Canvas hinzu (GameArea). Wir wählen als Füll-Farbe abwechselnd weiß und schwarz und es verwendet unsere SnakeSquareSize-Konstante sowohl als Breite als auch als Höhe (damit es quadratisch wird).
Hier ist das Ergebnis:
Zusammenfassung
In diesem Artikel haben wir die XAML definiert, welche nun den gesamten Spielinhalt beherbergt. Außerdem haben wir ein Schachbrettmuster auf den Spielbereich "gemalt", indem wir WPF Rectangle-Objekte in schwarz bzw. weiß hinzugefügt haben. Der nächste Schritt wird sein, die eigentliche Schlange und ihr Futter hinzuzufügen.