Анимация. Заполнение стены кирпичами
Lighting/Colors
Цель данного урока создать анимацию заполнения стены кирипичами. Для хранения текущего состояния стены будем использовать 2х мерный массив. В каждой ячейке этого массива будет храниться 1 или 0, 1 означает что в данной ячейке уже есть кирпич, а 0 значит что его нет. Также у нас будет текущий свободный кирпич который падает сверху.
Объявим переменные необходимые для представления текущего состояния нашей демо-сцены.
float BrickSize = 40; // размер в пикселях одного кирпича для отрисовки
int[,] wall; // 2х мерный массив стена кирпичей
int BrickX = 0; // позиция по X свободного кирпича
int BrickY = 0; // позиция по Y свободного кирпича
Инициализируем стартовые значения.
wall = new int[(int)(ClientRectangle.Width / BrickSize), (int)(ClientRectangle.Height / BrickSize)];
BrickX = Random.Next(wall.GetLength(0));
Создадим функцию проверки заполненности массива. Для этого пройдем по верхней строчке и проверим сущенствует ли хоть одна не заполненная ячейка.
bool AllFilled()
{
bool allFilled = true;
for (int i = 0; i < wall.GetLength(0); i++)
{
if (wall[i, 0] == 0)
{
allFilled = false;
break;
}
}
return allFilled;
}
Создадим функцию обновления сцены. Если мы уперлись в кирпич снизу, либо мы стоим в самой нижней позиции стены, то нужно пометить данный квадрат стены как заполненный кирпичом и перегенерировать позицию нового свободного кирпича. В остальных случаях мы просто двигаем текущий свободный кирпич вниз на 1 клетку.
public void UpdateScene()
{
if (BrickY == wall.GetLength(1) - 1 || wall[BrickX, BrickY + 1] == 1)
{
wall[BrickX, BrickY] = 1;
if (!AllFilled())
{
BrickY = 0;
do
{
BrickX = Random.Next(wall.GetLength(0));
} while (wall[BrickX, BrickY] == 1);
}
}
else
BrickY++;
}
Создадим функцию отрисовки сцены.
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.Clear(Color.White);
var gr = e.Graphics;
//отрисовка свободного кирпича
gr.FillRectangle(Brushes.Blue, BrickX * BrickSize, BrickY * BrickSize, BrickSize, BrickSize);
//отрисовка поля
for (int i = 0; i < wall.GetLength(0); i++)
for (int j = 0; j < wall.GetLength(1); j++)
{
if (wall[i, j] == 1)
gr.FillRectangle(Brushes.Blue, i * BrickSize, j * BrickSize, BrickSize, BrickSize);
}
Функция таймера:
private void Timer_Tick(object? sender, EventArgs e)
{
if (!AllFilled())
UpdateScene();
Invalidate();
if (AllFilled())
timer.Stop();
}
Вставив и запустив данный пример мы увидим следующую анимацию:

Исходный код данного примера вы можете найти здесь
Упражнения
- Сделать чтобы каждый кирпич в стене был разного цвета
- Сделать чтобы свободный кирпич двигался не дискретно, а плавно