Анимация. Заполнение стены кирпичами

 

 

Объявим переменные необходимые для представления текущего состояния нашей демо-сцены.

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();
    
 }     

Вставив и запустив данный пример мы увидим следующую анимацию:

 

 

Исходный код данного примера вы можете найти здесь

Упражнения

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