1. Подключение библиотеки Pygame и подготовка программы к работе

1.1. Библиотека как программный инструмент

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

1.2. Инструкция import pygame

Вначале необходимо установить библиотеку pygame для этого в терминале используйте специальную команду:

pip install pygame

Сниппет pip install pygame представляет собой команду для установки библиотеки Pygame в среде Python.

Команда pip install pygame используется в терминале для загрузки и установки всех необходимых файлов библиотеки Pygame из официального Python Package Index (PyPI) на локальный компьютер.

Подключение библиотеки в самом проекте выполняется инструкцией:

import pygame

Инструкция import относится к языку Python и служит для подключения внешнего модуля или пакета к текущей программе. После выполнения этой строки имя pygame становится доступным в коде. Это означает, что программа получает возможность обращаться к объектам библиотеки через точечную запись.

Например, после подключения становятся допустимыми обращения вида:

pygame.init()
pygame.quit()
pygame.display
pygame.event

Здесь необходимо сразу ввести ещё одно базовое понятие. Точечная запись в Python используется для обращения к содержимому объекта. Если программа пишет pygame.display, это означает обращение к компоненту display, который находится внутри библиотеки pygame.

1.3. Модуль как часть библиотеки

Библиотека Pygame не является одной функцией или одним классом. Она состоит из частей, каждая из которых отвечает за определённую область работы. Такая часть называется модулем.

Например:

  • pygame.display — модуль, связанный с окном и экраном;

  • pygame.event — модуль, связанный с обработкой событий;

  • pygame.time — модуль, связанный со временем;

  • pygame.key — модуль, связанный с клавиатурой;

  • pygame.mouse — модуль, связанный с мышью.

Следовательно, запись pygame.display.set_mode(...) означает вызов метода set_mode() у модуля display, который принадлежит библиотеке pygame.

1.4. Псевдоним библиотеки

В языке Python библиотеке можно назначить сокращённое имя:

import pygame as pg

Ключевое слово as означает «использовать другое имя». После этого в программе вместо pygame можно писать pg.

Например:

pg.init()
pg.quit()
pg.display.set_mode((600, 400))

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

2. Инициализация библиотеки

2.1. Назначение функции pygame.init()

После подключения библиотеки обычно выполняется следующая команда:

pygame.init()

Для её понимания необходимо ввести понятие инициализации. Инициализацией называется подготовка программного компонента к работе. Если библиотека подключена, это ещё не означает, что все её внутренние подсистемы уже приведены в рабочее состояние. Функция pygame.init() выполняет такую подготовку.

Иными словами, инструкция import pygame только подключает библиотеку, а функция pygame.init() переводит основные модули библиотеки в рабочий режим.

2.2. Возвращаемое значение функции pygame.init()

Функция pygame.init() не только выполняет действие, но и возвращает результат. Возвращаемым значением является кортеж из двух целых чисел.

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

Например:

(5, 0)

В случае pygame.init() первое число показывает, сколько модулей было инициализировано успешно, а второе — сколько модулей не удалось инициализировать.

Пример:

import pygame

result = pygame.init()
print(result)

pygame.quit()

Возможный результат выполнения:

(5, 0)

Или:

(6, 0)

Или:

(5, 1)

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

2.3. Разбор возвращаемого значения по элементам

Если результат сохранён в переменной result, то доступ к элементам кортежа осуществляется по индексу.

Индекс — это номер элемента последовательности, причём нумерация в Python начинается с нуля.

Следовательно:

  • result[0] — первый элемент кортежа;

  • result[1] — второй элемент кортежа.

Пример:

import pygame

result = pygame.init()

print("Результат pygame.init():", result)
print("Успешно:", result[0])
print("Неуспешно:", result[1])

pygame.quit()

Возможный результат выполнения:

Результат pygame.init(): (5, 0)
Успешно: 5
Неуспешно: 0

2.4. Функция pygame.quit()

Если pygame.init() переводит библиотеку в рабочее состояние, то функция pygame.quit() выполняет обратную задачу: завершает работу инициализированных модулей.

pygame.quit()

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

2.5. Минимальный шаблон начала и завершения программы

Таким образом, простейшая структура программы на Pygame имеет вид:

import pygame

pygame.init()

pygame.quit()

Пока в этой программе отсутствует окно, отсутствует обработка событий и отсутствует графика. Тем не менее именно эта структура является первым правильным каркасом программы.

3. Создание окна программы

3.1. Модуль pygame.display

Для создания окна используется модуль display. Как уже было установлено ранее, модуль — это часть библиотеки, отвечающая за определённую область работы. Модуль pygame.display отвечает за режим отображения, создание окна и взаимодействие с экранной поверхностью.

3.2. Метод pygame.display.set_mode()

Создание окна выполняется методом:

pygame.display.set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0)

Здесь впервые появляется понятие метода.

Метод — это функция, связанная с определённым объектом или модулем и вызываемая через точечную запись.

В простейшем виде используется следующая форма вызова:

screen = pygame.display.set_mode((600, 400))

Этот вызов выполняет одновременно два действия. Во-первых, он создаёт окно программы. Во-вторых, он возвращает специальный объект, который сохраняется в переменной screen.

3.3. Переменная screen

Переменная — это именованная область памяти, в которой хранится значение. В записи

screen = pygame.display.set_mode((600, 400))

левая часть, screen, является именем переменной, а правая часть — значением, которое в неё записывается.

Следовательно, после выполнения этой строки в переменной screen хранится объект, возвращённый методом set_mode().

3.4. Объект Surface

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

Проверка типа объекта:

import pygame

pygame.init()

screen = pygame.display.set_mode((600, 400))

print(type(screen))

pygame.quit()

Результат выполнения:

<class 'pygame.surface.Surface'>

Следовательно, screen хранит не «размер окна» и не «режим окна», а экранную поверхность, на которой выполняется графический вывод.

3.5. Представление объекта screen

Можно вывести и сам объект:

import pygame

pygame.init()

screen = pygame.display.set_mode((600, 400))

print(screen)

pygame.quit()

Возможный результат:

<Surface(600x400x32 SW)>

Здесь:

  • 600x400 — размеры поверхности;

  • 32 — глубина цвета;

  • SW — программный режим работы поверхности.

Эта запись подтверждает, что созданная поверхность имеет конкретный размер и технические характеристики.

4. Параметр size и экранная система координат

4.1. Размер окна

Первый параметр метода set_mode() называется size. Он определяет размеры окна и передаётся в виде кортежа из двух целых чисел:

(width, height)

где:

  • width — ширина;

  • height — высота.

Пример:

screen = pygame.display.set_mode((600, 400))

Здесь 600 — ширина окна, 400 — высота окна.

Другой пример:

screen = pygame.display.set_mode((1000, 700))

Увеличение размеров окна увеличивает рабочую область. Одновременно это увеличивает количество пикселей, которые приходится обрабатывать при полной перерисовке кадра.

4.2. Пиксель как единица экранного изображения

Пикселем называется минимальный элемент изображения на экране. Когда говорят, что окно имеет размер 600 на 400 пикселей, это означает, что поверхность содержит 600 позиций по горизонтали и 400 позиций по вертикали.

4.3. Экранная система координат

После введения понятия размера окна можно рассмотреть систему координат. В Pygame начало координат располагается в левом верхнем углу окна.

Следовательно:

  • точка (0, 0) — это верхний левый пиксель;

  • по оси X координаты увеличиваются вправо;

  • по оси Y координаты увеличиваются вниз.

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

5. Параметр flags метода set_mode()

5.1. Назначение параметра flags

После объяснения базового вызова set_mode((ширина, высота)) можно перейти к следующему параметру — flags.

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

Общий вид вызова:

screen = pygame.display.set_mode((600, 400), flags)

5.2. Константы и их объединение

Значения flags задаются специальными константами Pygame. Константа — это именованное постоянное значение. Например, pygame.RESIZABLE — это константа, обозначающая режим окна с изменяемым размером.

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

Пример:

screen = pygame.display.set_mode((800, 600), pygame.RESIZABLE | pygame.SCALED)

Здесь одновременно активированы два режима.

5.3. Флаг pygame.RESIZABLE

Флаг pygame.RESIZABLE разрешает пользователю изменять размер окна мышью.

screen = pygame.display.set_mode((600, 400), pygame.RESIZABLE)

Если программа создаёт такое окно, при изменении размеров возникают специальные события окна.

5.4. Флаг pygame.FULLSCREEN

Флаг pygame.FULLSCREEN открывает окно в полноэкранном режиме.

screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)

Размер (0, 0) в таком случае часто используется для автоматического выбора размеров текущего экрана.

5.5. Флаг pygame.NOFRAME

Флаг pygame.NOFRAME создаёт окно без рамки и стандартных кнопок управления.

screen = pygame.display.set_mode((600, 400), pygame.NOFRAME)

5.6. Флаг pygame.SCALED

Флаг pygame.SCALED используется для масштабирования изображения. Практический смысл этого режима состоит в том, что программа может рисовать на поверхности одного логического размера, а изображение будет показано в увеличенном масштабе.

screen = pygame.display.set_mode((320, 240), pygame.SCALED)

5.7. Флаг pygame.OPENGL

Флаг pygame.OPENGL используется в тех случаях, когда вывод строится через OpenGL.

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

Пример:

screen = pygame.display.set_mode((800, 600), pygame.OPENGL | pygame.DOUBLEBUF)

5.8. Флаг pygame.DOUBLEBUF

Флаг pygame.DOUBLEBUF связан с двойной буферизацией. Буферизацией называют организацию вывода через промежуточные области памяти. В простых двумерных учебных программах этот флаг обычно не требуется как самостоятельный инструмент, однако он часто используется совместно с OpenGL.

5.9. Флаги pygame.SHOWN и pygame.HIDDEN

Эти флаги позволяют создавать окно сразу видимым или скрытым.

Пример:

screen = pygame.display.set_mode((600, 400), pygame.HIDDEN)

5.10. Пример объединения флагов

screen = pygame.display.set_mode((800, 600), pygame.RESIZABLE | pygame.NOFRAME)

Такой вызов задаёт окно без рамки и одновременно включает режим изменения размера, если конкретная система допускает такую комбинацию.

6. Параметр depth

6.1. Понятие глубины цвета

Следующий параметр метода set_mode() называется depth. Он задаёт глубину цвета, то есть количество бит, используемых для представления цвета одного пикселя.

Пример:

screen = pygame.display.set_mode((600, 400), 0, 32)

Здесь число 32 означает глубину цвета 32 бита на пиксель.

6.2. Практическое значение параметра depth

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

Поэтому чаще используется запись:

screen = pygame.display.set_mode((600, 400))

без явного указания глубины цвета.

7. Параметр display

7.1. Выбор дисплея

Параметр display используется в системах с несколькими мониторами. Он позволяет указать номер дисплея, на котором должно быть создано окно.

Пример:

screen = pygame.display.set_mode((800, 600), display=1)

Это означает попытку создать окно на втором дисплее.

7.2. Метод pygame.display.get_desktop_sizes()

Для получения размеров подключённых дисплеев используется метод:

pygame.display.get_desktop_sizes()

Он возвращает список кортежей. Каждый кортеж содержит два числа: ширину и высоту соответствующего монитора.

Пример:

import pygame as pg

pg.init()

sizes = pg.display.get_desktop_sizes()
print(sizes)

pg.quit()

Возможные результаты:

[(1920, 1080)]

или

[(1920, 1080), (1280, 1024)]

или

[(2560, 1440), (1920, 1080), (1600, 900)]

7.3. Извлечение размеров конкретного монитора

Если список размеров сохранён в переменной sizes, то размеры первого монитора можно извлечь так:

width, height = sizes[0]

Здесь используется распаковка кортежа: первое значение присваивается переменной width, второе — переменной height.

7.4. Практические примеры

Создание окна под размер первого экрана:

sizes = pygame.display.get_desktop_sizes()
width, height = sizes[0]

screen = pygame.display.set_mode((width, height))

Выбор второго монитора:

screen = pygame.display.set_mode((800, 600), display=1)

8. Параметр vsync

8.1. Вертикальная синхронизация

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

Пример:

screen = pygame.display.set_mode((800, 600), pygame.OPENGL, vsync=1)

7.2. Практическое замечание

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

8. Необходимость главного цикла

8.1. Причина немедленного закрытия окна

Если программа создаёт окно, но после этого сразу достигает конца кода, выполнение завершается, и окно закрывается.

Например:

import pygame

pygame.init()
pygame.display.set_mode((600, 400))
pygame.quit()

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

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

8.2. Логическая переменная running

Чаще всего вводится переменная:

running = True

Здесь True — логическое значение истинности. В Python логические значения бывают двух видов:

  • True — истина;

  • False — ложь.

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

8.3. Цикл while

Для организации непрерывной работы окна используется цикл:

import pygame

pygame.init()
pygame.display.set_mode((600, 400))

running = True
while running:
  pass

Цикл while повторяет выполнение вложенных инструкций до тех пор, пока условие остаётся истинным. В данном случае условием является значение переменной running.

Следовательно, пока running == True, программа остаётся в цикле и не завершается.

9. События и очередь событий

9.1. Понятие события

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

  • пользователь нажал клавишу;

  • пользователь отпустил клавишу;

  • пользователь нажал кнопку мыши;

  • пользователь переместил мышь;

  • пользователь попытался закрыть окно.

9.2. Очередь событий

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

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

9.3. Получение списка событий

Для извлечения событий используется метод:

pygame.event.get()

Этот метод возвращает список текущих событий.

Здесь необходимо ввести ещё одно базовое понятие. Список в Python — это упорядоченная последовательность элементов, записанная в квадратных скобках. Метод pygame.event.get() возвращает именно такую последовательность объектов-событий.

10. Обработка событий в цикле

10.1. Цикл for

Если pygame.event.get() возвращает список событий, то программа должна перебрать этот список. Для этого используется цикл for.

Пример:

for event in pygame.event.get():

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

10.2. Атрибут event.type

Каждое событие содержит сведения о собственном виде. Для доступа к виду события используется атрибут type.

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

Следовательно, запись

event.type

означает обращение к типу текущего события.

10.3. Событие закрытия окна

Для закрытия окна используется специальный тип события:

pygame.QUIT

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

import pygame

pygame.init()
pygame.display.set_mode((600, 400))

running = True
while running:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False

pg.quit()

Условный оператор if выполняет вложенную инструкцию только при истинности условия. Здесь условием является равенство event.type и pygame.QUIT.

Когда running становится равным False, цикл while running: прекращается, и программа доходит до pygame.quit().

10.4. События клавиатуры

Событие pygame.KEYDOWN

Возникает в момент нажатия клавиши.

import pygame

pygame.init()
pygame.display.set_mode((600, 400))

running = True
while running:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    if event.type == pygame.KEYDOWN:    
        print("Клавиша нажата")

pg.quit()

Для определения конкретной клавиши используется атрибут event.key.

import pygame

pygame.init()
pygame.display.set_mode((600, 400))

running = True
while running:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    
    if event.type == pygame.KEYDOWN:    
        print("Клавиша нажата")
    
    if event.type == pygame.KEYDOWN:    
        if event.key == pygame.K_SPACE:        
          print("Нажат пробел")

pg.quit()

В данном примере:

  • event.key — код нажатой клавиши;

  • pygame.K_SPACE — константа, соответствующая клавише пробела.

Результат выполнения при нажатии пробела:

Нажат пробел

Событие pygame.KEYUP

Возникает в момент отпускания клавиши.

if event.type == pygame.KEYUP:    
  print("Клавишу отпустили")

Уточнение конкретной клавиши:

if event.type == pygame.KEYUP:    
  if event.key == pygame.K_SPACE:        
    print("Пробел отпущен")

Результат выполнения:

Пробел отпущен

10.5. События мыши

Событие pygame.MOUSEBUTTONDOWN

Возникает при нажатии кнопки мыши.

if event.type == pygame.MOUSEBUTTONDOWN:    
  print("Нажатие мыши:", event.pos)

Атрибуты события:

  • event.pos — координаты курсора в момент нажатия;

  • event.button — номер кнопки мыши.

Проверка левой кнопки:

if event.type == pygame.MOUSEBUTTONDOWN:    
  if event.button == 1:        
    print("Левая кнопка мыши:", event.pos)

Пример результата:

Левая кнопка мыши: (320, 180)

Событие pygame.MOUSEBUTTONUP

Возникает при отпускании кнопки мыши.

if event.type == pygame.MOUSEBUTTONUP:    
  print("Кнопка мыши отпущена:", event.pos)

Событие pygame.MOUSEMOTION

Возникает при движении мыши.

if event.type == pygame.MOUSEMOTION:    
  print("Движение мыши:", event.pos)

Дополнительные атрибуты:

  • event.rel — смещение курсора относительно предыдущего положения;

  • event.buttons — состояние кнопок мыши во время движения.

10.6. События окна

Событие pygame.VIDEORESIZE

Возникает при изменении размеров окна, если оно создано с флагом RESIZABLE.

if event.type == pygame.VIDEORESIZE:    
  print("Новый размер:", event.w, event.h)

Атрибуты:

  • event.w — новая ширина;

  • event.h — новая высота.

Пример результата:

Новый размер: 800 500

Событие pygame.WINDOWFOCUSGAINED и pygame.WINDOWFOCUSLOST

Возникают при получении и потере фокуса окном.

if event.type == pygame.WINDOWFOCUSGAINED:    
  print("Окно активно")

if event.type == pygame.WINDOWFOCUSLOST:    
  print("Окно не активно")

10.8. Пользовательские события

Для создания собственных событий используется:

MY_EVENT = pygame.event.custom_type()

Пример генерации события по таймеру:

pygame.time.set_timer(MY_EVENT, 1000)

Обработка:

if event.type == MY_EVENT:    
  print("Сработало пользовательское событие")

Результат выполнения (каждую секунду):

Сработало пользовательское событие

10.9. Метод pygame.event.poll()

Этот метод извлекает одно событие за один вызов.

event = pygame.event.poll()
print(event)

Если событий нет, возвращается специальное пустое событие.

10.10. Метод pygame.event.wait()

Существует два принципиально различных подхода к извлечению событий:

  1. Неблокирующий — с использованием pg.event.get(), когда программа самостоятельно опрашивает очередь событий.

  2. Блокирующий — с использованием pg.event.wait(), когда выполнение программы приостанавливается до появления события.

Метод pg.event.wait() предназначен для получения одного события из очереди с принудительным ожиданием, если очередь в данный момент пуста.

Формально его поведение можно описать следующим образом:

  • если в очереди уже присутствуют события, возвращается первое из них;

  • если очередь пуста, выполнение программы приостанавливается до тех пор, пока не появится новое событие;

  • после появления события оно извлекается из очереди и возвращается в виде объекта.

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

Результатом вызова:

event = pg.event.wait()

является объект, содержащий информацию о произошедшем событии.

Каждое событие обладает обязательным атрибутом:

event.type

который определяет тип события. Например:

  • pg.QUIT — попытка закрытия окна;

  • pg.MOUSEBUTTONDOWN — нажатие кнопки мыши;

  • pg.KEYDOWN — нажатие клавиши.

В зависимости от типа события объект может содержать дополнительные атрибуты. Например, для события нажатия мыши:

event.pos

— координаты курсора в момент нажатия.

Метод pg.event.wait() целесообразно использовать в ситуациях, где:

  • программа должна реагировать только на события;

  • отсутствует необходимость в непрерывном обновлении состояния;

  • требуется синхронное ожидание пользовательского ввода.

Пример использования:

import pygame

pygame.init()

screen = pygame.display.set_mode((400, 300))

running = True

while running:
    # Ожидание события (блокирующий вызов)
    event = pygame.event.wait()

    if event.type == pygame.QUIT:
        running = False

pygame.quit()

10.11. Прямой опрос устройств

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

keys = pygame.key.get_pressed()

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

Пример:

keys = pygame.key.get_pressed()

if keys[pygame.K_LEFT]:
    x -= 5

if keys[pygame.K_RIGHT]:
    x += 5

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

10.12. Полный пример обработки нескольких типов событий

import pygame as pg

pg.init()
screen = pg.display.set_mode((600, 400), pg.RESIZABLE)
clock = pg.time.Clock()

running = True
while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False

        elif event.type == pg.KEYDOWN:
            if event.key == pg.K_ESCAPE:
                running = False
            elif event.key == pg.K_SPACE:
                print("Нажат пробел")

        elif event.type == pg.MOUSEBUTTONDOWN:
            print("Клик мышью:", event.pos)

        elif event.type == pg.MOUSEMOTION:
            print("Координаты мыши:", event.pos)

        elif event.type == pg.VIDEORESIZE:
            print("Размер окна изменён:", event.w, event.h)

    screen.fill((30, 30, 30))
    pg.display.update()
    clock.tick(60)

pg.quit()

Здесь впервые используется объект clock, поэтому требуется его пояснение. pg.time.Clock() создаёт объект для управления частотой выполнения цикла. Метод clock.tick(60) ограничивает работу цикла примерно 60 повторениями в секунду.

11. Графические действия на поверхности screen

После того как установлено, что screen хранит объект Surface, можно рассмотреть основные действия, которые с ним выполняются.

11.1. Заполнение поверхности цветом

Для заполнения поверхности используется метод fill().

screen.fill((0, 0, 0))

Здесь (0, 0, 0) — кортеж из трёх чисел, задающий цвет. В данном случае это чёрный цвет.

11.2. Рисование прямоугольника

Для рисования прямоугольника используется функция:

pygame.draw.rect(screen, (255, 0, 0), (50, 50, 100, 60))

В этой записи:

  • screen — поверхность, на которой выполняется рисование;

  • (255, 0, 0) — красный цвет;

  • (50, 50, 100, 60) — прямоугольная область, где 50 и 50 задают координаты, а 100 и 60 — ширину и высоту.

11.3. Вывод изображения или текста

Для переноса готового изображения на поверхность используется метод blit().

screen.blit(image, (100, 100))

Здесь image — другая поверхность или изображение, а (100, 100) — координаты его размещения.

12. Обновление экрана

12.1. Необходимость обновления

Изменение содержимого поверхности screen ещё не означает немедленного появления результата на мониторе. После рисования программе необходимо сообщить системе, что изменения следует показать пользователю.

Для этого используются функции обновления экрана.

12.2. Функция pygame.display.update()

Функция pygame.display.update() может использоваться в трёх формах:

pygame.display.update()
pygame.display.update(rectangle)
pygame.display.update(rectangle_list)

Вызов без аргументов обновляет всё окно.

Пример:

pygame.display.update()

Вызов с одним прямоугольником обновляет только одну область.

Пример:

pygame.display.update((50, 50, 100, 80))

Вызов со списком прямоугольников обновляет несколько областей.

Пример:

pygame.display.update([(10, 10, 50, 50), (100, 100, 80, 60)])

12.3. Функция pygame.display.flip()

Вторая функция обновления:

pygame.display.flip()

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

12.4. Порядок действий в кадре

Правильная последовательность такова:

screen.fill((0, 0, 0))
pygame.draw.circle(screen, (255, 0, 0), (200, 150), 30)
pygame.display.update()

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

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

13. Полное и частичное обновление экрана

13.1. Полное обновление

Пример полного обновления всего окна:

import pygame as pg

pg.init()
screen = pg.display.set_mode((600, 400))
clock = pg.time.Clock()

x = 0
running = True
while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False

    screen.fill((255, 255, 255))
    pg.draw.rect(screen, (255, 0, 0), (x, 150, 60, 60))
    x += 3

    pg.display.update()
    clock.tick(60)

pg.quit()

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

13.2. Частичное обновление

Для частичного обновления используется класс Rect. Прямоугольник Rect описывает прямоугольную область экрана.

Пример:

import pygame as pg

pg.init()
screen = pg.display.set_mode((600, 400))
clock = pg.time.Clock()

x = 0
running = True
while running:
    old_rect = pg.Rect(x, 150, 60, 60)

    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False

    pg.draw.rect(screen, (0, 0, 0), old_rect)
    x += 3
    new_rect = pg.Rect(x, 150, 60, 60)
    pg.draw.rect(screen, (255, 0, 0), new_rect)

    pg.display.update([old_rect, new_rect])
    clock.tick(60)

pg.quit()

Здесь обновляются только две области: старая и новая позиции движущегося объекта.

14. Связь создания окна, событий и обновления экрана

Работа программы на Pygame строится в определённой последовательности:

  1. библиотека подключается и инициализируется;

  2. создаётся окно и экранная поверхность;

  3. запускается главный цикл;

  4. в цикле извлекаются и обрабатываются события;

  5. изменяется состояние объектов;

  6. выполняется рисование на поверхности;

  7. обновлённое изображение выводится на экран;

  8. при получении события закрытия цикл завершается, после чего вызывается quit().

Эта последовательность образует основной каркас любой программы на Pygame.

15. Пример

import pygame as pg

pg.init()
screen = pg.display.set_mode((600, 400), pg.RESIZABLE)
clock = pg.time.Clock()

x = 100
y = 150
running = True

while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False

        elif event.type == pg.KEYDOWN:
            if event.key == pg.K_LEFT:
                x -= 10
            elif event.key == pg.K_RIGHT:
                x += 10

        elif event.type == pg.MOUSEBUTTONDOWN:
            x, y = event.pos

    screen.fill((240, 240, 240))
    pg.draw.circle(screen, (255, 0, 0), (x, y), 30)

    pg.display.update()
    clock.tick(60)

pg.quit()

Логика программы следующая. Создаётся окно размером 600 на 400 пикселей. Вводятся координаты круга. В главном цикле программа получает события. При нажатии клавиш со стрелками изменяется горизонтальная координата круга. При щелчке мышью круг переносится в точку щелчка. После обработки событий экран очищается, круг рисуется в новой позиции, изображение обновляется, а частота цикла ограничивается 60 кадрами в секунду.

16. Практические задания

16.1. Создание первого окна

Написать программу, которая подключает Pygame, выполняет инициализацию библиотеки, создаёт окно размером 600 на 400 пикселей и остаётся активной до нажатия на кнопку закрытия окна. После завершения цикла должна быть вызвана функция pg.quit().

16.2. Исследование параметра size

Создать варианты программы с размерами окна 300×200, 800×600 и 1000×700. Определить, как изменение значений влияет на рабочую область. Письменно зафиксировать, что означает первый элемент кортежа, что означает второй, где находится точка (0, 0), в какую сторону возрастает X и в какую сторону возрастает Y.

16.3. Работа с переменной screen

Создать программу, в которой результат pg.display.set_mode((600, 400)) сохраняется в переменную screen, затем поверхность полностью закрашивается методом fill(), после чего экран обновляется.

16.4. Использование флага RESIZABLE

Создать окно 600×400 с флагом pg.RESIZABLE и реализовать вывод новых размеров окна в консоль при его изменении.

16.5. События KEYDOWN и KEYUP

Реализовать вывод в консоль сообщений о нажатии и отпускании пробела с использованием pg.KEYDOWN, pg.KEYUP и event.key.

16.6. Обработка мыши

Реализовать вывод координат при нажатии левой кнопки мыши и при её движении по окну.

16.7. Сравнение update() и flip()

Написать две программы: в первой использовать pg.display.update(), во второй — pg.display.flip(). Сравнить их с точки зрения результата и различий в применении.

16.8. Частичное обновление экрана

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

16.9. Проверка состояния клавиатуры через get_pressed()

Создать программу, в которой квадрат движется при удержании клавиш влево и вправо, используя pg.key.get_pressed().

16.10. Итоговая задача по каркасу Pygame

Написать программу, включающую создание окна 600×400, главный цикл, обработку закрытия окна, обработку клавиатуры и мыши, рисование объекта, обновление экрана и ограничение частоты кадров.