Создаём интерфейс игры на Python с помощью pygame
easy

Создаём интерфейс игры на Python с помощью pygame

Используем мощь библиотек для создания игр

Для Python есть много библиотек, с помощью которых можно создавать графические интерфейсы. Сегодня поговорим об одной особенной — pygame. Это не просто визуальная оболочка, а полноценный инструмент для разработки игр. Если вы давно хотели написать игру, но пока не накопили денег на собственную студию — берите.

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

Что даёт pygame

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

Вот две ключевые возможности библиотеки pygame, на которых мы будем строить всё остальное:

  1. Создание окна игры, в котором можно показывать что угодно. Без этого для работы у нас будет только код, а там сложно что-то нарисовать.
  2. Поиск входных действий игрока для правильного отображения кадров. Например, pygame проверяет положение курсора мыши или нажатие кнопок клавиатуры. Обычно Python тоже умеет принимать ввод через оператор input(), но на время ввода выполнение остального кода замораживается.

Эти два пункта — главные, но ещё pygame делает многие другие вещи удобнее: можно подключать звуки, находить коллизии, добавлять таймеры.

Крутые современные игры на одной pygame не сделаешь, потому что их создают при помощи множества других инструментов. У таких игр свой движок, редактор уровней, обработка освещения, саунд-дизайн и много других разных технологий под отдельные задачи. А ещё большая команда, которая всем этим занимается.

Устанавливаем и подключаем pygame

Для установки библиотеки используем команду:

pip install pygame

Если пишете код в текстовом редакторе, нужно зайти в командную строку, открыть нужную папку и выполнить команду:

Устанавливаем и подключаем pygame

Если работаете в IDE, то есть редакторе кода, команду можно выполнить во встроенном терминале:

Устанавливаем и подключаем pygame

Теперь нужно подключить библиотеку и принудительно включить все модули, потому что некоторые из них по умолчанию выключены. Это можно сделать с помощью такого кода:

# импортируем библиотеку pygame
import pygame
# инициализируем все модули pygame
pygame.init()

Если после этого запустить код, в консоли вывода должно появиться такое сообщение:

Hello from the pygame community. https://www.pygame.org/contribute.html

Создаём экран

Все игровые действия происходят в окне игры, или display surface. Это будет наш главный экран. Для его создания нужно объявить переменную и положить в неё два метода: display и set_mode(). Внутрь set_mode() можно положить кортеж с шириной и высотой экрана. Но, чтобы было понятнее, положим их сначала в переменные:

# объявляем ширину и высоту экрана
width = 800
height = 400

# создаём экран игры
screen = pygame.display.set_mode((width, height))

Можно не использовать переменные и написать так: pygame.display.set_mode((800, 400)). Но если в будущем нам понадобятся границы экрана где-то в другом месте кода, нужно будет продублировать эти значения. А при изменении менять во всех местах, где они указаны. С переменными удобнее — мы просто будем везде использовать width и height. Если будет нужно поменять эти значения, напишем новые в одном месте — там, где объявили переменные.

Сейчас можно попробовать запустить код, и на один кадр появится экран игры. Это очень мало, поэтому, скорее всего, вы ничего не заметите. Так происходит потому, что Python доходит до конца кода и перестаёт его выполнять — поэтому и окно тоже исчезает.

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

# объявляем переменную-флаг для цикла игры
game = True

# запускаем бесконечный цикл
while game:
   # получаем список возможных действий игрока
   for event in pygame.event.get():
       # если пользователь нажал на крестик закрытия окна…
       if event.type == pygame.QUIT:
           # …останавливаем цикл
           pygame.quit()

   # обновляем экран игры
   pygame.display.update()

Теперь можно запустить код и посмотреть на готовый экран. Пока на нём ничего нет:

Создаём интерфейс игры на Python с помощью pygame

При выходе Python выдаёт ошибку. Так происходит потому, что в момент закрытия окна мы перестаём создавать экран. И когда программа доходит до последней строчки кода pygame.display.update(), то не может её выполнить, отсюда и ошибка.

Мы будем писать чистый код, чтобы в будущем ошибки не накопились и не вызвали какую-то непонятную поломку. Поэтому сразу после добавления pygame мы подключим встроенный модуль, который позволяет корректно завершить любой запущенный код:

from sys import exit

Осталось описать правильное завершение работы в том же фрагменте кода, где мы уже прописали закрытие окна, — просто добавляем ещё одну строку exit():

# запускаем бесконечный цикл
while game:
   # получаем список возможных действий игрока
   for event in pygame.event.get():
       # если пользователь нажал на крестик закрытия окна…
       if event.type == pygame.QUIT:
           # …останавливаем цикл
           pygame.quit()
           # добавляем корректное завершение работы
           exit()

Теперь окно будет закрываться без ошибок.

Задаём название игры и частоту кадров

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

# даём название окну игры
pygame.display.set_caption("Detective CODE Game")

Теперь добавим ещё один важный параметр — частоту кадров в секунду, или fps (frame per second). Это то, как быстро сменяются кадры в нашей игре. Если в кино частота кадров  обычно одинаковая (24 кадра в секунду), то для игры этот параметр может различаться в зависимости от мощности компьютера или конкретной сцены. 

Если запустить на старом слабом компьютере современную игру последнего поколения на высших настройках, то в лучшем случае мы получим частоту 1–2 fps. Возможно и обратное: если запустить старую игру на мощном компьютере, частота обновления кадров может доходить до нескольких сотен в секунду (и иногда в это тоже невозможно играть). 

Оба варианта вызовут проблемы при анимации. Допустим, по нашей задумке персонаж игры меняет положение в каждом новом кадре на 10 пикселей. Тогда получится так:

  • при скорости 1 fps персонаж перемещается на 10 пикселей в секунду;
  • при скорости 100 fps персонаж перемещается на 1000 пикселей в секунду.

Ограничить потолок скорости просто: нужно просто сказать компьютеру не работать быстрее заданного числа fps. Но если компьютер слабый и не тянет больше 10–15 кадров в секунду, его нельзя заставить отображать анимацию быстрее. Поэтому для игр указывают системные требования для запуска и нормальной работы.

Сегодня стандартная игровая частота кадров — 60 fps, так что мы зададим это число как максимальный показатель. Для этого понадобится добавить несколько строк кода до основного цикла:

# устанавливаем количество кадров в секунду
fps = 60
# создаём объект таймера
clock = pygame.time.Clock()

Обратите внимание, что метод Clock() пишется с большой буквы — это важно.

Теперь в самом конце цикла добавляем такое:

# добавляем к таймеру количество fps для частоты обновления основного цикла
clock.tick(fps)

Наша игра запускается, у неё есть название и частота обновления кадров. Но пока что всё, что в ней есть, — чёрный экран. Добавим немного цвета.

Добавляем изображения

Все видимые объекты в pygame называются поверхностями. Их два вида:

  • Основная, или display surface. Это наше окно игры. Основная поверхность может быть только одна, и она всегда видима.
  • Рабочие поверхности, regular surface или просто surface. Это отдельные изображения, которые мы показываем на главном экране. Их может быть сколько угодно, и они видимы только при размещении на основной поверхности.

Создаём интерфейс игры на Python с помощью pygame

Создать рабочую поверхность можно двумя способами: нарисовать в pygame или загрузить заранее подготовленную картинку. Попробуем оба способа.

Чтобы нарисовать новую прямоугольную поверхность, нужно задать её размеры, сохранить в новую переменную с этими размерами и залить цветом. Для этого пишем до запуска цикла:

# создаём новую поверхность
# 1 — задаём размеры:
width_ts = 200
height_ts = 200
# 2 — создаём поверхность по размерам
test_surface = pygame.Surface((width_ts, height_ts))
# 3 — добавляем цвет
test_surface.fill('White')

Теперь нужно разместить новую поверхность на основной. Необязательно использовать главный экран, можно нарисовать одну дополнительную поверхность на другой (её можно назвать родительской). Для этого у родительской поверхности вызываем метод blit(), в который передаём переменную с нужной поверхностью и координаты её левого верхнего угла.

На координатах остановимся подробнее. Координатная сетка в pygame совпадает с экраном игры и измеряется в пикселях. Начало находится в левом верхнем углу. Первая координата — горизонтальная, она увеличивается с перемещением вправо. Вторая координата отвечает за точку по вертикали и увеличивается сверху вниз.

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

# размещаем новую поверхность на нашем экране
screen.blit(test_surface, (0, 0))

Запускаем:

Создаём интерфейс игры на Python с помощью pygame

Переместим белый квадрат на середину экрана:

# размещаем новую поверхность на нашем экране
screen.blit(test_surface, (300, 100))

Мы сдвинули левый верхний угол (начало новой поверхности) на 300 пикселей влево и на 100 вниз. Проверяем, что получилось:

Создаём интерфейс игры на Python с помощью pygame

Теперь попробуем второй способ создания изображения и сделаем фон. Сначала подготовим картинку одного размера с игровым окном и положим её в папку с основным скриптом. Теперь картинку можно сохранить в переменную через метод load(), если в скобках указать имя файла:

# загружаем в переменную картинку из папки с нашим файлом
back = pygame.image.load('code_game_back.jpg')

Размещаем её на основном экране так же, как мы сделали это с предыдущим изображением:

# размещаем новую поверхность на нашем экране
screen.blit(back, (0, 0))

Смотрим на результат:

Создаём интерфейс игры на Python с помощью pygame

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

Что дальше

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

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

import pygame
from sys import exit

pygame.init()

# объявляем ширину и высоту экрана
width = 800
height = 400

# создаём экран игры
screen = pygame.display.set_mode((width, height))

# устанавливаем количество кадров в секунду
fps = 60
# создаём объект таймера
clock = pygame.time.Clock()

# создаём новую поверхность
# 1 — задаём размеры:
width_ts = 200
height_ts = 200
# 2 — создаём поверхность по размерам
test_surface = pygame.Surface((width_ts, height_ts))
# 3 — добавляем цвет
test_surface.fill('White')

# загружаем в переменную картинку из папки с нашим файлом
back = pygame.image.load('code_game_back.jpg')

# даём название окну игры
pygame.display.set_caption("Detective CODE Game")

# объявляем переменную-флаг для цикла игры
game = True

# запускаем бесконечный цикл
while game:
   # получаем список возможных действий игрока
   for event in pygame.event.get():
       # если пользователь нажал на крестик закрытия окна…
       if event.type == pygame.QUIT:
           # …останавливаем цикл
           pygame.quit()
           # добавляем корректное завершение работы
           exit()

   # размещаем новую поверхность на нашем экране — белый квадрат
   screen.blit(test_surface, (300, 100))

   # размещаем новую поверхность на нашем экране — подготовленный jpeg
   screen.blit(back, (0, 0))

   # обновляем экран игры
   pygame.display.update()
   # добавляем к таймеру количество fps для частоты обновления основного цикла
   clock.tick(fps)

Редактор:

Инна Долога

Обложка:

Алексей Сухов

Корректор:

Ирина Михеева

Вёрстка:

Маша Климентьева

Соцсети:

Юлия Зубарева

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию Получите ИТ-профессию
Еще по теме
easy