Текст и счёт на экране

Очки, жизни, таймер — игре нужно показывать цифры и текст. Шрифты в Pygame рендерят строку в картинку, которую мы рисуем как обычный спрайт.
Суть: текст в Pygame — это картинка. Шрифт через font.render превращает строку в Surface, которую рисуют через blit. Меняется счёт — пересоздаём картинку текста.

Любая игра показывает информацию: счёт, число жизней, время, надпись «Game Over». В Pygame нет привычного «вывести текст» как в консоли — здесь текст это картинка. Мы берём шрифт, говорим ему «нарисуй вот эту строку этим цветом», и получаем Surface — такую же поверхность, как загруженный спрайт. Её рисуем на экране через blit.

Сначала создаём объект шрифта: pygame.font.Font(None, 48) — None означает стандартный системный шрифт, 48 — размер. Затем рендерим: font.render("Счёт: 100", True, (255,255,255)). Второй аргумент True включает сглаживание (antialiasing) — буквы получаются гладкими, а не зубчатыми. Результат — картинка текста, которую можно blit-нуть в любую точку.

Важный момент: текст меняется (счёт растёт), поэтому картинку нужно пересоздавать заново каждый раз, когда значение изменилось. Рендерить каждый кадр можно, но если значение не поменялось — лучше переиспользовать старую картинку, это экономит ресурсы.

Как работает под капотом

Шрифт превращает строку в набор пикселей-букв на прозрачной поверхности. Дальше это обычный blit, как со спрайтом:

   "Счёт: 100"
        |  font.render(text, True, color)
        v
   [картинка текста]  (Surface с буквами)
        |  screen.blit(img, (x, y))
        v
   текст на экране

   счёт изменился -> render заново -> новая картинка

В pygame (читаем):

pygame.font.init()
font = pygame.font.Font(None, 48)   # системный шрифт, размер 48

score = 0
# в цикле, когда рисуем:
text_img = font.render(f"Счёт: {score}", True, (255, 255, 255))
screen.blit(text_img, (20, 20))

# выровнять по центру:
rect = text_img.get_rect(center=(400, 50))
screen.blit(text_img, rect)

Форматирование строки счёта — обычный Python, проверяемый без графики. Соберём строки HUD (счёт, жизни, время). Попробуй сам:

def hud_lines(score, lives, seconds):
    return [
        f"Счёт: {score}",
        f"Жизни: {'<3 ' * lives}".strip(),
        f"Время: {int(seconds // 60)}:{int(seconds % 60):02d}",
    ]

for line in hud_lines(score=1250, lives=3, seconds=95):
    print(line)

Кастомные шрифты и кеширование текста

Системный шрифт (Font(None, 48)) хорош для прототипа, но выглядит казённо. Свой характер игре придаёт шрифт из файла: pygame.font.Font("pixel.ttf", 32) загружает любой TTF, например пиксельный для ретро-аркады. Шрифт — часть стиля игры наравне с цветами и спрайтами, и подобрать его стоит так же тщательно. Один удачный шрифт мгновенно делает интерфейс «своим», а не дефолтным.

Про производительность: рендер текста — операция не бесплатная, она каждый раз заново рисует все буквы. Если счёт меняется редко, глупо рендерить его 60 раз в секунду. Профессиональный приём — кешировать картинку текста и пересоздавать её только тогда, когда значение изменилось: if score != last_score: text_img = font.render(...). Для статичных надписей вроде «Пауза» рендери один раз при старте. Эти мелочи незаметны на простой игре, но входят в привычку и держат FPS высоким, когда интерфейс разрастётся до десятков надписей.

Текст в игре — это не только счёт, но и весь её «голос»: подсказки, диалоги, названия уровней, экраны победы и поражения. Поэтому стоит сразу сделать удобную функцию-помощник, например draw_text(surface, text, pos, size, color), которая рендерит строку и рисует её в нужном месте с нужным выравниванием. Один раз написал — и весь остальной код пишет текст одной короткой строкой, без повторения возни со шрифтом и get_rect. Это та же идея переиспользования, что и со словарём ассетов или константами цветов: вынеси рутину в одно место и пользуйся ей везде. Аккуратная работа с текстом делает интерфейс игры опрятным, а код — компактным и приятным для чтения.

Частые ошибки

  • Забыть font.init() (или общий pygame.init()) — шрифт не создастся.
  • Рендерить текст до создания строки счёта — увидишь старое значение.
  • Передать число вместо строки в render — нужна строка, оборачивай в str() или f-строку.

Best practices

  • Создавай объект Font один раз, переиспользуй каждый кадр.
  • Для выравнивания используй get_rect(center=...) — текст встанет ровно.
  • Если значение не меняется, не рендери его заново каждый кадр.

Итог: текст это картинка из шрифта. render превращает строку в Surface, blit рисует её. Меняется число — пересоздаём картинку.

Проверьте себя
1. Чем по сути является текст, выведенный через font.render?
AСтрокой в консоли
BКартинкой-поверхностью (Surface), которую рисуют через blit
CЧислом
DЗвуком
2. Когда нужно заново вызвать font.render для счёта?
AКаждый пиксель
BКогда значение счёта изменилось
CНикогда
DТолько при закрытии игры