На главную

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

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

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

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

Упражнения

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