TOC

This article is currently in the process of being translated into Russian (~71% done).

Создание игры: WPF змейка:
Chapter introduction:

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!

Continuous movement with DispatcherTimer

В предыдущих статьях мы создали симпатичное игровое поле для нашей Змейки и описали в коде ее создание и движение. Однако, как уже упоминалось, код, описывающий движение должен вызываться вновь и вновь для отображения изменений пока игра не завершится. Другими словами нам понадобится таймер.

В общих словах в программировании таймеры обычно используются как механизм, позволяющий засекать точные промежутки времени для повторяющихся действий. То есть срабатывание таймера (tick) происходит через определенный интервал времени и в результате выполняется определенный код. Это именно то, что нам нужно для поддержания нашей Змейки в движении, поэтому мы добавим DispatcherTimer в наше Окно:

public partial class SnakeWPFSample : Window        
{        
    private System.Windows.Threading.DispatcherTimer gameTickTimer = new System.Windows.Threading.DispatcherTimer();  
    ....

Теперь нам потребуется подписаться на одно-единственное событие - Tick. И сделаем мы это в конструкторе нашего окна:

public SnakeWPFSample()  
{  
    InitializeComponent();  
    gameTickTimer.Tick += GameTickTimer_Tick;      
}

А тут реализация выполнения события:

private void GameTickTimer_Tick(object sender, EventArgs e)  
{  
    MoveSnake();  
}

Итак, при каждом срабатывании таймера вызывается событие Tick, которое вызывает метод MoveSnake(), реализованный ранее. Чтобы насладиться результатами проделанной работы и увидеть движущуюся змейку нам нужно всего лишь создать, инициализировать части змейки и запустить таймер. Создадим метод StartNewGame() и будем использовать его как для начала первой игры, так и для начала новой игры после смерти игрока. Начнем с базовой версии. Потом я добавлю функциональности, а теперь - заставим змейку двигаться!

Первым делом добавим еще набор констант, необходимых для начала новой игры:

public partial class SnakeWPFSample : Window  
{  
    const int SnakeSquareSize = 20;  
    const int SnakeStartLength = 3;  
    const int SnakeStartSpeed = 400;  
    const int SnakeSpeedThreshold = 100;  
    ......

На этом этапе используются только три первые константы, отвечающие за размер, длину и начальную скорость Змейки. SnakeSpeedThreshold понадобится позже, а сейчас, как обещали, добавим простую реализацию метода StartNewGame():

private void StartNewGame()  
{  
    snakeLength = SnakeStartLength;  
    snakeDirection = SnakeDirection.Right;  
    snakeParts.Add(new SnakePart() { Position = new Point(SnakeSquareSize * 5, SnakeSquareSize * 5) });  
    gameTickTimer.Interval = TimeSpan.FromMilliseconds(SnakeStartSpeed);  

    // Draw the snake  
    DrawSnake();  

    // Go!      
    gameTickTimer.IsEnabled = true;  
}

Мы начали с установки snakeLength и snakeDirection в начальные значения. Затем мы добавили одну часть змейки в snakeParts List (другие позже), задавая ей прекрасную начальную позицию для движения вправо - мы еще раз используем константу SnakeSquareSize для вычисления подходящей позиции. С этого места мы можем рисовать змейку вызывая метод DrawSnake() и включая таймер, который начинает движение змейки.

Наконец мы почти подошли к месту, когда можно откинуться и насладиться самой первой версией того, что вполне выглядит игрой - действительно, все, что осталось сделать это вызвать метод StartNewGame(). Это действительно необходимо сделать, и сейчас, когда все остальное готово мы вернемся немного назад и воспользуемся событием ContentRendered из Window, которое мы добавляли в первых статьях. Просто добавьте вызов метода StartNewGame() и мы окончательно готовы к сборке и запуску:

private void Window_ContentRendered(object sender, EventArgs e)  
{  
    DrawGameArea();  
    StartNewGame();  
}

Если вы сделали все, как описано, то вы сможете начать игру и увидеть как змейка после создания сразу начнет двигаться:

Notice how the snake appears from out of nothing, as a single square, and then grows to a length of three squares. That happens because we only add one part to the snakeParts list, but each time the MoveSnake() method is called by the timer, a new part is added (to make it grow), while only removing tail-parts if the current length is about to exceed the desired length of the snake, which starts at 3 (decided by the SnakeStartLength constant).

Summary

We now have a moving snake, which is really awesome! But as you can see from the animated image above, there are still things to be done - there's no food for the snake to eat, and when the snake hits the wall, nothing happens. We'll work on these aspects in the next articles.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!