C# WPF Игра: Остановка и UI — Урок 5

Отслеживание проигрыша

Проигрыш наступает в нескольких ситуациях:

  1. Змейка выходит за пределы окна.
  2. Змейка съедает себя.

Выход змейки за пределы окна отслеживается в функции Tick:

// ... предыдущий код ...

if (NewHead.X < 0 || NewHead.Y < 0 ||
    NewHead.X >= GameCanvas.ActualWidth / SnakeSquareSize ||
    NewHead.Y >= GameCanvas.ActualHeight / SnakeSquareSize)
{
    Timer.Stop();
    return;
}

// ... последующий код ...

Здесь проверяются координаты головы змейки (NewHead.X, NewHead.Y) относительно границ канваса. При выходе за границы таймер останавливается (Timer.Stop()), и функция завершается (return).

Самопоедание змейки отслеживается, только если змейка состоит из четырёх и более квадратов:

// ... предыдущий код ...

if (Snake.Count >= 4)
{
    // ... код проверки на самопоедание ...
}

// ... последующий код ...

Проверка на самопоедание реализована с помощью вложенных циклов:

for (int i = 0; i < Snake.Count; i++)
{
    Point currentPosition = new Point(Canvas.GetLeft(Snake[i]), Canvas.GetTop(Snake[i]));
    for (int j = i + 2; j < Snake.Count; j++)
    {
        Point nextPosition = new Point(Canvas.GetLeft(Snake[j]), Canvas.GetTop(Snake[j]));
        if (currentPosition == nextPosition)
        {
            EndGame();
            return;
        }
    }
}

Внешний цикл перебирает элементы змейки. Внутренний цикл проверяет каждый элемент, начиная с третьего, на совпадение координат с текущим. Соседние элементы не проверяются. При совпадении координат вызывается функция EndGame(), которая останавливает игру и возвращает управление.

Функция EndGame() останавливает таймер:

private void EndGame()
{
    Timer.Stop();
    return;
}

Добавление пользовательского интерфейса

Для отображения счёта добавляется TextBlock в XAML:

<TextBlock x_Name="ScoreTextBlock" Text="Score: 0" Foreground="White" 
           HorizontalAlignment="Left" Margin="10" VerticalAlignment="Top"/>

Обновление счёта происходит в функции EatFood():

private int score = 0;
// ...
private void EatFood()
{
    score++;
    ScoreTextBlock.Text = $"Score: {score}";
    // ...
}

Для кнопки перезапуска добавляется Button в XAML:

<Button x_Name="RestartButton" Content="Restart" HorizontalAlignment="Center" 
        VerticalAlignment="Center" Visibility="Collapsed" Click="RestartButton_Click"/>

Обработка нажатия кнопки RestartButton:

private void RestartButton_Click(object sender, RoutedEventArgs e)
{
    score = 0;
    ScoreTextBlock.Text = "Score: 0";
    GameCanvas.Children.Clear();
    Snake.Clear();
    RestartButton.Visibility = Visibility.Collapsed;
    InitializeGame();
}

Функция InitializeGame() содержит код инициализации игры, вызываемый при запуске и перезапуске.

Кнопка «Старт» добавляется следующим образом:

<Button x_Name="StartGameButton" Content="Start" HorizontalAlignment="Center" 
        VerticalAlignment="Center" Click="StartGameButton_Click"/>

Обработка нажатия кнопки «Старт»:

private void StartGameButton_Click(object sender, RoutedEventArgs e)
{
    InitializeGame();
    StartGameButton.Visibility = Visibility.Collapsed;
}

Создана игра «Змейка» с отслеживанием проигрыша и пользовательским интерфейсом, включающим отображение счёта и кнопки «Старт» и «Перезапуск». Игра запускается нажатием кнопки «Старт», после проигрыша появляется кнопка «Перезапуск» для начала новой игры.

Что будем искать? Например,программа