Найти тему
ZDG

Пишу 5-килобайтный Тетрис. Часть 3: Тест "стакана"

В предыдущей части я сделал распаковку фигур в битовые строки и первичные графические методы.

Так как после распаковки строки фигуры и строки "стакана" представляют собой данные одного типа (16-битное число), то я переделаю функцию рисования. Она будет рисовать сразу целые строки.

Кроме того, я сделал функцию универсальной, чтобы можно было рисовать и "стакан", и фигуру. Ведь и то, и другое это массив строк.

Я передаю туда, во-первых, сам массив ("стакан" или фигуру), во-вторых, вертикальную позицию, с которой надо начать рисовать, и в-третьих, горизонтальный битовый сдвиг фигуры внутри строки.

Для "стакана" и позиция и сдвиг равны нулю, так как он статичен.

Теперь на каждом шаге игры я буду перерисовывать весь "стакан" с его содержимым. Рисование будет происходить так:

  1. Закрасить всё поле одним сплошным цветом (я взял желтый пока для того, чтобы видеть границы)
  2. Нарисовать строки стакана
  3. Нарисовать строки фигуры

Фигура рисуется отдельно, так как не является содержимым стакана. Это нужно для того, чтобы можно было проверять повороты и движения фигуры. Если бы она содержалась в стакане, то при проверке натыкалась бы сама на себя.

Глобальные переменные

Как известно, глобальные переменные – зло (на эту тему я ещё не писал), но в данном случае я аккуратно сделал несколько глобальных переменных исключительно ради сокращения кода:

  • figure – текущий номер фигуры
  • phase – текущая фаза поворота фигуры
  • fx – битовый сдвиг фигуры по x внутри строки
  • fy – вертикальная позиция в "стакане"
  • lp – для циклов со строками фигуры
  • lines – массив, где хранятся распакованные строки фигуры

Для поворотов мне всё-таки пришлось для каждой фигуры создать 4 фазы. Массив фигур стал длиной 28 элементов, но я не нашел способа, как вычислить правильное ограничение фазы для нестандартных фигур и при этом сократить размер кода.

Я сделал функцию для получения новой фигуры. Она случайным образом выбирает номер фигуры (кратный 4), присваивает начальные смещения и фазу и распаковывает фигуру в рабочий массив строк.

Для движения я назначил клавиатурные события на клавиши со стрелками:

  • влево: создает тестовый сдвиг влево
  • вправо: создает тестовый сдвиг вправо
  • вверх: создает тестовый поворот. Тестовая фаза увеличивается на 1. Если она становится 4, то обнуляется. После этого берется тестовая фигура из массива по адресу [номер текущей фигуры + тестовая фаза]. Тестовая фигура распаковывается в тестовый массив строк.
  • вниз: создает тестовое смещение вниз (фигура сдвигается вниз).

После этого тестовые строки фигуры с тестовыми сдвигами отдаются на проверку в функцию checkLines():

Каждая строка фигуры сравнивается побитно с соответствующей строкой "стакана" через логическое "И". Если в результате наложения битов получился ненулевой результат, значит кубики строки пересекаются с кубиками "стакана" и фигура не может встать в эту позицию. Я отбрасываю тестовые данные, и всё остается на своих местах.

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

Отдельно обрабатывается случай, когда фигура должна сместиться вниз, но упирается в препятствие. В этом случае она считается "приземлившейся", и её кубики переходят во владение стакана (путем битовой операции "ИЛИ" над строками. Теперь эти кубики будут рисоваться вместе со стаканом и мешать активной фигуре.

А я вместо приземлившейся фигуры запрашиваю новую, и начинается всё сначала.

Фигура пока не умеет падать сама, её надо двигать стрелкой вниз.

Рабочий код можно посмотреть живьем здесь.

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