Найти тему
ZDG

Пишем Питона на Питоне #14: Шрифт

Предыдущие части: Остановите музыку, Включите звук, Жизни и модальные окна, Подсчёт очков, Главное меню, Геймплей, Есть ли у него душа, Организация ввода, View, Визуализация поля, Загрузка уровня, INI-файл, Пишем Питона на Питоне!

Код для этой части находится в ветке font на github. Вы можете смотреть там все файлы онлайн и также скачать зип-архив всей ветки.

Готовимся к выводу таблицы рекордов. Если игрок наберет достаточно очков, чтобы войти в топ-10, ему будет предложено ввести своё имя, и оно будет записано в таблицу рекордов. Необходимо ли это в игре про питона – вопрос, конечно, спорный, но мы в этом проекте не столько делаем игру, сколько обкатываем разные сценарии, которые возникают в процессе разработки игр.

В общем, для того, чтобы ввести, а затем показать имена, потребуется шрифтовая поддержка. Все надписи, которые есть сейчас, сделаны просто в виде картинок, потому что они определены заранее и не меняются. Но с именами так не прокатит.

Я сделаю свой шрифт следующим образом: это будет одна картинка, в которой нарисованы все нужные символы. Вместе с этой картинкой будет составлена таблица соответствия, чтобы знать, какой символ где находится. Вывод строки будет осуществляться так:

  1. Взять следующий символ из строки
  2. По таблице соответствия найти его координаты в картинке
  3. Скопировать из картинки прямоугольную область, в которой содержится нужный символ, на экран.

Стоит посвятить некоторое время обсуждению шрифта. Как известно, шрифты бывают пропорциональные и моноширинные. В пропорциональных знаки имеют разную ширину. И поэтому в таблице соответствий надо будет учитывать не только положение, но и ширину символа. В моноширинных шрифтах все символы (а точнее, занимаемое ими место) одной ширины. Значит, достаточно хранить только позицию символа.

Это, конечно, проще, но выбор падает на моноширинный шрифт не только по этой причине. Игровое поле состоит из одинаковых квадратиков, поэтому моноширинный шрифт будет лучше отвечать общему графическому стилю игры (притянуто за уши, но всё же).

Кроме того, так как наш питон гнётся под прямыми углами, то шрифт будет как бы имитировать самого питона: буквы будут по возможности состоять из "змеек", согнутых в разных местах.

Необходимо нарисовать цифры от 0 до 9, и латинские буквы от A до Z (будем использовать только заглавные). Остальное – пока отложим.

Некоторое время я потратил на шрифт и вот что получилось:

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

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

Теперь нужно создать структуру, которая описывает шрифты внутри картинки. Каждый шрифт образует один блок.

Я сделал класс FontParams со следующими свойствами:

  • start_x, start_y: координаты начала шрифтового блока внутри картинки
  • char_width, char_height: ширина и высота одного символа в блоке
  • char_spacing, line_spacing: межсимвольный и межстрочный интервалы. Эти свойства будут нужны при выводе текста на экран, а в картинке символы хранятся всегда вплотную друг к другу.
  • chars_in_line: сколько символов находится в блоке по горизонтали
  • map: карта соответствия символов

Карта представлена просто: в виде строки "ABCDEF...", где записаны все доступные символы в том же порядке, в каком они стоят в шрифтовом блоке.

Допустим, мне надо напечатать символ "R". С помощью стандартной функции поиска позиции символа в строке

map.index('R')

я нахожу, что в строке он находится по смещению, допустим, 27. Значит, в шрифтовом блоке он тоже стоит на позиции 27.

Далее, свойство chars_in_line сообщает, что в шрифтовом блоке помещается 10 символов по ширине. Переводим смещение 27 в координату строки и столбца:

x = 27 % 10 = 7
y = 27 // 10 = 2

Значит, буква "R" находится в строке 2 и столбце 7. Теперь найдём реальное смещение относительно начала блока:

pos_x = start_x + char_width * x
pos_y = start_y + char_height * y

Всё, теперь осталось только скопировать прямоугольную область картинки из этих координат на экран.

Эти доработки вошли в метод draw_teхt() в классе Graphics.

Так как есть несколько шрифтов, то в Graphics добавлен метод add_font_params(), который можно вызывать несколько раз и передавать туда объект класса FontParams с заполненными свойствами для каждого шрифта. Этот объект будет сохранён в словаре с ключом-идентификатором шрифта, который передаётся вместе с ним. После этого можно выбирать текущий шрифт с помощью метода set_font(), передавая туда идентификатор.

Добавление параметров шрифтов делается до начала основного цикла игры в main.py.

После этого я прошёлся по всем представлениям и заменил вывод картинок на вывод текстовых строк. Теперь игра выглядит так:

-2

В процессе были доработаны модели и представления меню, чтобы избавиться от ненужных зависимостей. В общем, в коде много чего доработано, убрано лишнее и т.д.

Также была перерисована картинка для заставки:

-3

В целом я недоволен шрифтом, он получился несоответствующим игре, как мне кажется, и моноширинность всё-таки не идёт на пользу. Но шрифт можно исправлять сколько угодно, главное, что теперь можно с ним работать.

Значит, в следующем выпуске сделам ввод имени игрока после игры и вывод таблицы рекордов. А потом будем делать анимацию яблок и глаза для питона.

Следующая часть: Таблица рекордов

Читайте также: