Тетрис (анимация)

На основании предыдущего урока давайте сделаем упрощенную анимацию по мотивам игры Тетрис.  Для этого давайте научимся проверять нижнуюю линиюю на заполненность и удалять  ее.

Сделаем кубики разноцветными

В предыдущем уроке было заадние сделать кубики разноцветными, надеюсь вы справились самостоятельно. Давайте выполним это задание здесь. Для того чтобы кодировать цвет давайте введем новые правила представления сцены в массиве wall. Пустое место будем кодировать -1, а наличие шарика будем кодировать индексом цвета из массива brushes.

Введем массив кистей (цветов)

// возможные цвета наших кубиков
Brush[] brushes = [
    Brushes.LimeGreen,
    Brushes.DeepPink,
    Brushes.Blue, 
    Brushes.Chocolate, 
    Brushes.Orange
];

 

Обратите внимание: можно придумать разные способы представления цветов кубиков в данной демо-сцене. В этом уроке я использую для кодирования цвет тот же самый массив wall, предполагая негалсное условие, что если в ячейки массива находится -1 - значит это пустое место, если находится любое не отрицательное число, значит это индекс кисти из массива кистей brushes. Но можно использовать и другие представления цветов, допустим можно завести отдельный массив цветов (например colors[,] такого же размера как и wall), чтобы не смешивать свойства наличия кубика в клетке и его цвета. Тогда wall будет кодировать только наличие или отсутствие блока в клетке, а массив цветов будет кодировать цвет блока. Выбор наиболее удобного и оптимального способа представления  данных зависит от программиста и выбирается исходя из целесообразности конкретной решаемой задачи.

Проверим  что кубики стали разноцветными, запустим и убедимся:

Сделаем кубики объемными

Для того чтобы кубики стали выглядеть более красиво, давайте отрисуем псевдо затемнения для создания эффекта объема.

 

Запустим и проверим

Как мы видим после полного заполнения поля выставляется флаг состояние конец игры gameOver и анимация прекращается. Нажав кнопку R можем сбросить демо-сцену.

Удаление нижней линии

Теперь давайте сделаем удаление нижней линии если она заполнена. Чтобы сделать анимацию бесконечной и приблизиться к игре Тетрис. Удаление нижней линии происходит когда она полностью заполнена, давайте объявим функцию проверки линии на заполненность

bool IsLineFilled(int lineIdx)
{
    bool filled = true;
    for (int i = 0; i < wall.GetLength(0); i++)
    {
        if (wall[i, lineIdx] == 0)
        {
            filled = false;
            break;
        }
    }
    return filled;
}

Теперь напишем функцию которая сместит все строки на одну вниз, а первую строчку сделает пустой (заполнит нулями)

private void RemoveBottomLine()
{
    //shift all rows
    for (int i = wall.GetLength(1) - 1; i > 0; i--)
    {
        for (int j = 0; j < wall.GetLength(0); j++)
        {
            wall[j, i] = wall[j, i - 1];
        }
    }

    //clear first line
    for (int i = 0; i < wall.GetLength(0); i++)
    {
        wall[i, 0] = 0;
    }
}

Добавим проверку и удаление нижней линии в игровой цикл:

private void Form1_Paint(object? sender, PaintEventArgs e)
{
    e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    if (!gameOver) // если игра не окончена
        UpdateScene();  // обновить сцену

    e.Graphics.Clear(Color.Black);
    var gr = e.Graphics;

    DrawBlock(gr, BrickX, BrickY, colorIdx); // рисуем игровой блок

    DrawBlocks(gr); // рисуем статичные блоки

    if (IsLineFilled(wall.GetLength(1) - 1))  // если нижняя линия заполнена
        RemoveBottomLine();  // удалить нижнуюю линию

    if (IsLineFilled(0)) // если заполнена верхняя линия
        gameOver = true; // выставить флаг состояние конец игры
}

Запустим и убедимся что нижняя линия будет удаляться

Полный код можете посмотреть здесь

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