This article has been localized into Chinese 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!
创建一个游戏区域
去创建我们的WPF贪吃蛇游戏,我们会先从创建地图开始,这将会是一个封闭的区域,蛇必须在里面移动——如果你愿意的话,可以说是一个蛇坑。我已经决定我的蛇坑应该看起来像一个棋盘,由大小相同的方块组成,和蛇身体大小是一样的。我们将会在两次迭代中创建地图:其中一些会布局在XAML中,因为这非常简单,而我们将会画背景正方形在后台代码中,因为它是重复和动态的
游戏区域XAML
所以,让我们用XAML开始——一个带有Canvas面板的简单的窗体,位于Border控件之内,去创建一个封闭的区域:
<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>
我们的游戏现在看起来像这样:
我们用一个Canvas面板作为实际的游戏区域,因为它允许我们去添加控件进去,在那里我们可以完全控制位置。我们稍后会用到它,但是现在,注意以下事情:
- 没有为窗体定义宽/高——相反的,我们为Canvas定义它们,因为这是我们需要完全控制的部分。接着我们通过设置窗体的 SizeToContent属性为WidthAndHeight来确保能够相应地调整其大小,如果我们为窗体定义宽/高,那么窗体可用大小将取决于操作系统为窗体使用了多少边框,这可能取决于主题等等。
- 我们为Canvas的ClipToBounds设置为True——这非常重要,因为否则我们所添加的控件将能够扩充到Canvas面板的边界之外
从后台代码画背景
如上所述,我想要一个游戏区域的棋盘背景。它由很多正方形组成,所以这些更容易在后台代码去添加(或者使用一个图片,但这不是动态的!)。我们需要在窗口内的所有控件初始化/渲染后立即执行此操作,幸运的是,Window窗体已经有该事件了:ContentRendered 事件。我们将会在Window窗体声明中订阅它:
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight" ContentRendered="Window_ContentRendered"
现在转到后台代码,然后我们开始吧。首先,我们需要去明确一个大小当我们画贪吃蛇,正方形背景等等。它能够在你Window类的顶部完成:
public partial class SnakeWPFSample : Window
{
const int SnakeSquareSize = 20;
.....
现在,在我们的ContentRendered事件中我们将会调用DrawGameArea() 方法,它将会完成所有困难的工作。看起来像这样:
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;
}
}
就像之前提到的,这些文章需要比本教程中其他文章更多的C#知识,所以我不会每一行都讲一遍,但是这里我们会做一个简要的描述:在While循环中,我们一直创建Rectangle 控件的实例然后添加进Canvas中(GameArea)。我们用白或者黑的Brush(画笔)填充它,然后使用我们的SnakeSquareSize常量作为宽度和高度,因为我们想要它变成一个正方形。在每次迭代,我们使用nextX和nextY去控制何时去移动到下一行(当我们到达正确的边界的时候)和何时停止(当同时到达底部和正确边界的时候)
这是结果:
小结
在这篇文章,我已经定义XAML用于托管所有的游戏内容,和我们已经“绘制”一个棋盘图案在游戏区域,通过添加WPF 黑和白的 Rectangle 控件进去。下一步将会开始添加实际的贪吃蛇,以及它将吃的食物。