В предыдущей части я сделал распаковку фигур в битовые строки и первичные графические методы.
Так как после распаковки строки фигуры и строки "стакана" представляют собой данные одного типа (16-битное число), то я переделаю функцию рисования. Она будет рисовать сразу целые строки.
Кроме того, я сделал функцию универсальной, чтобы можно было рисовать и "стакан", и фигуру. Ведь и то, и другое это массив строк.
Я передаю туда, во-первых, сам массив ("стакан" или фигуру), во-вторых, вертикальную позицию, с которой надо начать рисовать, и в-третьих, горизонтальный битовый сдвиг фигуры внутри строки.
Для "стакана" и позиция и сдвиг равны нулю, так как он статичен.
Теперь на каждом шаге игры я буду перерисовывать весь "стакан" с его содержимым. Рисование будет происходить так:
- Закрасить всё поле одним сплошным цветом (я взял желтый пока для того, чтобы видеть границы)
- Нарисовать строки стакана
- Нарисовать строки фигуры
Фигура рисуется отдельно, так как не является содержимым стакана. Это нужно для того, чтобы можно было проверять повороты и движения фигуры. Если бы она содержалась в стакане, то при проверке натыкалась бы сама на себя.
Глобальные переменные
Как известно, глобальные переменные – зло (на эту тему я ещё не писал), но в данном случае я аккуратно сделал несколько глобальных переменных исключительно ради сокращения кода:
- figure – текущий номер фигуры
- phase – текущая фаза поворота фигуры
- fx – битовый сдвиг фигуры по x внутри строки
- fy – вертикальная позиция в "стакане"
- lp – для циклов со строками фигуры
- lines – массив, где хранятся распакованные строки фигуры
Для поворотов мне всё-таки пришлось для каждой фигуры создать 4 фазы. Массив фигур стал длиной 28 элементов, но я не нашел способа, как вычислить правильное ограничение фазы для нестандартных фигур и при этом сократить размер кода.
Я сделал функцию для получения новой фигуры. Она случайным образом выбирает номер фигуры (кратный 4), присваивает начальные смещения и фазу и распаковывает фигуру в рабочий массив строк.
Для движения я назначил клавиатурные события на клавиши со стрелками:
- влево: создает тестовый сдвиг влево
- вправо: создает тестовый сдвиг вправо
- вверх: создает тестовый поворот. Тестовая фаза увеличивается на 1. Если она становится 4, то обнуляется. После этого берется тестовая фигура из массива по адресу [номер текущей фигуры + тестовая фаза]. Тестовая фигура распаковывается в тестовый массив строк.
- вниз: создает тестовое смещение вниз (фигура сдвигается вниз).
После этого тестовые строки фигуры с тестовыми сдвигами отдаются на проверку в функцию checkLines():
Каждая строка фигуры сравнивается побитно с соответствующей строкой "стакана" через логическое "И". Если в результате наложения битов получился ненулевой результат, значит кубики строки пересекаются с кубиками "стакана" и фигура не может встать в эту позицию. Я отбрасываю тестовые данные, и всё остается на своих местах.
Если же получился нулевой результат, то пространство свободно, и можно переписать тестовые сдвиги и строки в рабочие.
Отдельно обрабатывается случай, когда фигура должна сместиться вниз, но упирается в препятствие. В этом случае она считается "приземлившейся", и её кубики переходят во владение стакана (путем битовой операции "ИЛИ" над строками. Теперь эти кубики будут рисоваться вместе со стаканом и мешать активной фигуре.
А я вместо приземлившейся фигуры запрашиваю новую, и начинается всё сначала.
Фигура пока не умеет падать сама, её надо двигать стрелкой вниз.
Рабочий код можно посмотреть живьем здесь.
Мне осталось сделать автоматическое падение фигуры, очистку заполненных линий и условие окончания и рестарта игры.