This article has been localized into Russian 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!
Создание игрового поля
Создание нашей игры мы начнём с рисования карты. Она будет представлять из себя ограниченную область, внутри которой и будет двигаться наша змейка - скажем так, "змеиную яму". Я решил оформить её в виде шахматной доски, состоящей из одинаковых квадратов, размер которых будет совпадать с размером тела змейки. Создание карты мы выполним в два этапа: кое-что будет определено в XAML, так как это просто, в то время как отрисовку квадратов мы выполним с помощью кода, так как это более динамичный процесс.
XAML игрового поля
Что же, давайте начнем с XAML - простого Window с панелью 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 в качестве игрового поля поскольку она позволит нам не просто добавлять элементы управления к ней, но и расположить все элементы на свои позиции. Мы используем это позже, а теперь обратите внимание на следующее:
- В Window не определяются ни ширина ни высота-они будут определены в Canvas, поскольку это те параметры, которыми мы должны возможность полностью управлять. Затем мы удостоверимся что Window изменит свой размер в соответствии с содержимым установив SizeToContent свойство как WidthAndHeight. Если бы мы вместо этого определили ширину/ высоту для Window, доступное пространство внутри него будет зависеть от размера границы окон, установленного в операционной системе , который может зависеть от темы и т.д.
- Мы устанавливаем свойство ClipToBounds как True для Canvas - это важно, поскольку в противном случае элементы управления, которые мы добавляем могут вылазить за границы панели Canvas .
Отрисовка заднего фона из Code-behind
Как упоминал ранее, я хочу сделать задний фон в в виде шахматного поля. Оно состоит из множества квадратов, так что более простым путем будет добавить их в Code-behind (или использовать изображение, но в такой вариант будем менее динамичным!). Нам требуется сделать это в момент инициализации/рендеринга всех элементов управления внутри Window . И, к счастью, Window обладает событием на этот случай: это событие ContentRendered. Мы подпишемся на него при объявлении Window в XAML:
Title="SnakeWPF - Score: 0" SizeToContent="WidthAndHeight" ContentRendered="Window_ContentRendered"
А теперь перейдем к Code-behind и начнем. Прежде всего нам требуется с размером отрисовываемой змеи, квадратиков заднего фона и т.д. Это может быть выполнено с помощью свойств класса нашего 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). Мы закрашиваем их с помощью кисти белого либо черного цвета, а ширина и высота определяются нашей постоянной SnakeSquareSize поскольку мы хотим что бы ячейки были квадратными. В каждой итерации мы используем nextX и nextY что бы определять момент перехода на следующую строку (достижение правой границы поля) а затем и момент остановки (когда мы достигли нижней строки И правой границы поля одновременно)
И вот результат:
Заключение
В этой статье мы описали XAML код, создав поле для хранения всего игрового контента, а также нарисовали клетчатый узор на игровом поле, создавая чёрные и белые WPF Rectangle контролы. Следующим шагом мы начнём добавлять саму змейку, и еду для неё.