Этот урок посвящен добавлению динамики в игру — созданию механизма управления змейкой с помощью клавиатуры. Для реализации динамических действий будем использовать таймер, позволяющий выполнять код через определённые интервалы времени.
Подготовка: Описание полей
Удалим поле FoodColor, так как для отображения фрукта теперь используется изображение. Определим перечисление Direction для хранения информации о направлении движения змейки:
public enum Direction
{
Left,
Right,
Up,
Down
}
Создадим поле для хранения текущего направления движения змейки:
public Direction CurrentDirection { get; set; } = Direction.Right; // Изначальное направление – вправо
Для работы с таймером определим поля:
private const int TimerInterval = 200; // Интервал срабатывания таймера в миллисекундах
private DispatcherTimer _timer;
Реализация таймера и функции движения
В обработчике события GameCanvas_Loaded инициализируем и настроим таймер:
_timer = new DispatcherTimer();
_timer.Tick += TimerTick;
_timer.Interval = TimeSpan.FromMilliseconds(TimerInterval);
_timer.Start();
Функция TimerTick, вызываемая при каждом срабатывании таймера:
private void TimerTick(object sender, EventArgs e)
{
Point newHeadPosition = CalculateNewHeadPosition();
// ... код для обновления позиции змейки на канвасе ...
}
Функция CalculateNewHeadPosition вычисляет новые координаты головы змейки:
private Point CalculateNewHeadPosition()
{
double left = Canvas.GetLeft(SnakeHead) / SnakeSquareSize;
double top = Canvas.GetTop(SnakeHead) / SnakeSquareSize;
Point headCurrentPosition = new Point(left, top);
Point newHeadPosition = new Point();
switch (CurrentDirection)
{
case Direction.Left:
newHeadPosition = new Point(headCurrentPosition.X - 1, headCurrentPosition.Y);
break;
case Direction.Right:
newHeadPosition = new Point(headCurrentPosition.X + 1, headCurrentPosition.Y);
break;
case Direction.Up:
newHeadPosition = new Point(headCurrentPosition.X, headCurrentPosition.Y - 1);
break;
case Direction.Down:
newHeadPosition = new Point(headCurrentPosition.X, headCurrentPosition.Y + 1);
break;
}
return newHeadPosition;
}
В TimerTick после вычисления новых координат обновим позицию головы змейки на канвасе:
Canvas.SetLeft(SnakeHead, newHeadPosition.X * SnakeSquareSize);
Canvas.SetTop(SnakeHead, newHeadPosition.Y * SnakeSquareSize);
Обработка нажатий клавиш
Добавим обработчик события KeyDown к окну приложения:
<Window ... KeyDown="Window_KeyDown"> ... </Window>
В обработчике Window_KeyDown проверим нажатую клавишу и изменим направление движения змейки:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
if (CurrentDirection != Direction.Down) CurrentDirection = Direction.Up;
break;
case Key.Down:
if (CurrentDirection != Direction.Up) CurrentDirection = Direction.Down;
break;
case Key.Left:
if (CurrentDirection != Direction.Right) CurrentDirection = Direction.Left;
break;
case Key.Right:
if (CurrentDirection != Direction.Left) CurrentDirection = Direction.Right;
break;
}
}
Теперь змейка будет двигаться в соответствии с нажатыми клавишами. Проверка на противоположное направление предотвращает мгновенное изменение направления на противоположное, что сделало бы игру неиграбельной.
В этом уроке реализовано базовое движение змейки с помощью таймера и обработчика нажатий клавиш. В следующих уроках добавим функциональность поедания фруктов, увеличения длины змейки и обработку столкновений.