Перейти к основному содержимому

5.02. Графика и игры

Разработчику Архитектору

Графика и игры

Графика

Turtle

Графический интерфейс в языке программирования Python может быть реализован различными способами — от простой черепашьей графики до полноценных 2D-приложений и сложных GUI-систем. Сначала поговорим о простой графике.

В жизни каждого специалиста возникают ситуации-конфузы. Так вот, после многих лет разработки на языках C#, Java, JavaScript, Python я встречаю некую «черепашью графику» в Python, причём в курсе программирования для детей. У меня конфуз - что за черепашья графика? Почему графика? Что имеется в виду? GUI? 2D/3D? Вектор/растр?

Потом ещё веселее - объекты в «черепашьей графике». Объектно-ориентированное программирование? Да? Или нет?

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

Так вот, черепашья графика (Turtle Graphics) - это визуальный способ программирования, при котором мы управляем виртуальной черепашкой, которая ползёт по экрану и рисует линии. Она как художник с карандашом: куда она ползёт — там остаётся след. Это простая 2D-графика, где учатся программировать через наглядные действия вроде «иди вперёд», «поверни налево», «подними карандаш» и т.д.

Название происходит от языка Logo, который был разработан в 1960-х годах для обучения детей программированию. В нём была физическая игрушечная черепаха на полу, которая двигалась по командам и рисовала мелом. Потом эта идея перешла в виртуальную черепашку на экране.

В Python модуль turtle — это современная реализация этой идеи. Он встроен в стандартную библиотеку, то есть не нужно ничего устанавливать — просто пишем:

import turtle

И начинаем рисовать.

Модуль turtle входит в стандартную библиотеку Python и предоставляет простую, но мощную систему для работы с двумерной графикой. Основная идея заключается в концепции «черепахи» — абстрактного исполнителя, перемещающегося по координатной плоскости и оставляющего за собой след. Через последовательность команд можно управлять направлением движения, положением, цветом линии и другими параметрами.

Задумка следующая - на экране появляется маленькая стрелочка (или черепашка, если включить соответствующую форму). У неё есть:

  • Позиция (x, y) — где она находится.
  • Направление — куда смотрит (например, вверх, вправо).
  • Ручка (pen) — опущена (рисует) или поднята (не рисует).
  • Цвет линии, цвет заливки, толщина линии, скорость движения.

Задача как раз в управлении «черепашкой» при помощи команд.

Команды там следующие:

  • forward(100) - Черепашка идёт вперёд на 100 пикселей;
  • backward(50) - Назад на 50 пикселей;
  • left(90) - Поворачивает налево на 90 градусов;
  • right(45) - Направо на 45°;
  • penup() - Поднимает ручку — больше не рисует;
  • pendown() - Опускает ручку — снова рисует;
  • goto(x, y) - Мгновенно перемещается в точку (x, y);
  • color("red") - Устанавливает цвет ручки и заливки;
  • pencolor("blue") - Только цвет линии;
  • fillcolor("yellow") - Цвет заливки фигур;
  • begin_fill() / end_fill() - Начинает и заканчивает заливку области;
  • speed(5) - Скорость от 1 (медленно) до 10 (быстро), 0 — мгновенно;
  • shape("turtle") - Меняет внешний вид: "arrow", "circle", "turtle" и др.

Пример: рисование квадрата.

image-2.png

Это как цикл for в C#, только вместо изменения переменной мы меняем состояние объекта.

Хотя это не GUI с кнопками, это графика в математическом смысле: работа с координатной плоскостью, углами, фигурами, цветами, траекториями. Экран является координатной плоскостью, где центр (0,0) - середина экрана, X вправо, Y вверх, как в базовой математике.

Так рисуют геометрические фигуры, используя циклы и функции, можно даже фракталы, узоры, анимации.

Здесь каждая черепашка — объект класса Turtle.

t1 = turtle.Turtle()
t2 = turtle.Turtle()

t1.color("red")
t2.color("blue")

t1.goto(-100, 0)
t2.goto(100, 0)

t1 и t2 образуют две независимые «кисти», которые могут двигаться параллельно, рисовать разными цветами, иметь разную скорость и выполнять разные программы. Это отличный способ показать детям (и напомнить взрослым), что объекты — это экземпляры класса с собственным состоянием и поведением.

Чтобы не писать 360 строк для круга, можно использовать цикл, и получить почти круг (технически это 360-угольник). Можно делать розетки, спирали, снежинки Коха — всё через повторение простых действий.

for _ in range(360):
t.forward(1)
t.left(1)

Пример - две черепахи навстречу.

t1 = turtle.Turtle()
t2 = turtle.Turtle()

t1.penup()
t1.goto(-200, 0)
t1.pendown()
t1.color("red")

t2.penup()
t2.goto(200, 0)
t2.pendown()
t2.color("blue")
t2.setheading(180) # смотрит влево

# Ползут навстречу
for _ in range(100):
t1.forward(2)
t2.forward(2)

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

В объектно-ориентированной парадигме turtle представляет собой класс Turtle, экземпляры которого обладают состоянием (позиция, угол поворота, цвет пера, видимость) и поведением (методы перемещения, рисования, изменения стиля). Каждая черепаха работает в рамках общего холста — экземпляра класса Screen, который управляет окном вывода, фоном и событиями.

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

Система координат в turtle — прямоугольная, с началом в центре окна. Положительное направление оси X — вправо, оси Y — вверх. Размеры окна задаются явно через метод setup(width, height) класса Screen. Координаты могут быть абсолютными (например, goto(x, y)) или относительными (например, forward(distance)).

Ориентация угла измеряется в градусах против часовой стрелки от положительного направления оси X. Поворот осуществляется командами left(angle) и right(angle).

Модуль поддерживает широкий спектр способов задания цветов:

  • Строковые имена: "red", "blue", "green" и др.
  • RGB-значения в формате кортежа (r, g, b), где каждое значение — число от 0 до 1 (или от 0 до 255 при активации режима colormode(255)).
  • HEX-коды: "#FF5733".

Для заливки фигур используется комбинация методов begin_fill() и end_fill(), которые фиксируют контур и применяют текущий цвет заполнения.

Анимация в turtle реализуется через последовательное изменение состояния черепахи с контролем скорости выполнения. Метод speed(n) позволяет установить скорость от 0 (мгновенно) до 10 (медленно). Для плавной анимации используются циклы с задержками, хотя сам модуль не является реалтайм-движком.

Обработка событий (например, нажатия клавиш, кликов мыши) осуществляется через регистрацию обработчиков:

def move_forward():
t.forward(10)

screen.onkey(move_forward, "Up")
screen.listen()

Здесь важно понимать, что turtle использует внутренний event loop, запускаемый вызовом screen.mainloop() — без него события не будут обрабатываться.

turtle — однопоточная система; длительные операции блокируют интерфейс, и этот модуль не предназначен для производительных графических задач. Использует Tkinter в качестве бэкенда, что делает его зависимым от наличия GUI-среды. Подходит для обучения, прототипирования и демонстрации алгоритмов, но не для промышленных приложений.

Play

Библиотека play — сторонняя библиотека, разработанная для упрощения создания 2D-игр и анимаций, особенно в образовательной среде. Она строится на основе Pygame Zero, но предлагает ещё более минималистичный API, ориентированный на начинающих. Установка проста:

pip install play

play следует императивной модели, в которой программа описывает поведение объектов в виде функций обратного вызова (update, draw). Главный цикл управления выполняется автоматически.

Центральным элементом являются спрайты — двухмерные объекты, обладающие позицией, размером, изображением и свойствами анимации. Спрайт создаётся как экземпляр класса play.new_image() или play.new_box():

ball = play.new_circle(color="red", x=0, y=0, radius=25)

Каждый спрайт имеет атрибуты:

  • x, y — координаты центра.
  • angle — угол поворота.
  • size — масштаб относительно исходного изображения.
  • image — если используется текстура.
  • visible — видимость объекта.

Движение реализуется путём изменения атрибутов спрайтов в функции update(), которая вызывается каждый кадр (обычно 60 раз в секунду):

@play.repeat_forever
def do():
ball.x += 1

Также доступны встроенные методы, такие как move(), point_towards(), rotate().

Обнаружение столкновений (коллизий) выполняется с помощью метода is_touching(other_sprite):

if ball.is_touching(paddle):
ball.color = "blue"

Этот метод проверяет пересечение границ спрайтов (bounding boxes), что достаточно для большинства простых случаев, но не учитывает прозрачные области изображений.

play предоставляет простой доступ к состоянию клавиш:

if play.key_is_pressed("w"):
paddle.y += 5

Поддерживаются буквенные, цифровые и специальные клавиши ("space", "up", "left" и т. д.). Нет необходимости вручную управлять event loop — библиотека делает это автоматически.

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

import play

# Создание объектов
paddle = play.new_box(color="green", x=0, y=-200, width=100, height=20)
ball = play.new_circle(color="red", x=0, y=200, radius=20)
score = play.new_text(words="Счёт: 0", x=0, y=250)

count = 0

@play.repeat_forever
def do():
global count

# Управление платформой
if play.key_is_pressed("left"):
paddle.x -= 5
if play.key_is_pressed("right"):
paddle.x += 5

# Движение шарика
ball.y -= 3

# Проверка коллизии
if ball.is_touching(paddle):
ball.y = 200 # Переместить шарик наверх
count += 1
score.words = f"Счёт: {count}"

# Перезапуск, если шарик упал
if ball.y < -250:
ball.y = 200
count = max(0, count - 1)
score.words = f"Счёт: {count}"

play.start_program()

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

Tkinter и GUI

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

Графический пользовательский интерфейс (Graphical User Interface) — это система, позволяющая пользователю взаимодействовать с программой через визуальные компоненты: окна, кнопки, списки, диаграммы и т.д. Реализация GUI в Python возможна благодаря нескольким основным библиотекам:

  • Tkinter — стандартная библиотека, интегрированная в Python, построенная на Tcl/Tk.
  • PyQt / PySide — привязки к фреймворку Qt, предоставляющие богатый набор виджетов.
  • Kivy — кроссплатформенная библиотека для мультитач-приложений и мобильных интерфейсов.
  • Dear PyGui, Flet, Eel — современные альтернативы с акцентом на производительность или web-подход.

Любое GUI-приложение следует событийно-ориентированной архитектуре:

  • Создаётся главное окно.
  • Добавляются виджеты (элементы управления).
  • Регистрируются обработчики событий (нажатие кнопки, ввод текста).
  • Запускается главный цикл (mainloop), который ожидает и распределяет события.

Пример на Tkinter

import tkinter as tk
from tkinter import messagebox

root = tk.Tk()
root.title("Пример GUI")
root.geometry("300x200")

label = tk.Label(root, text="Введите имя:")
label.pack(pady=10)

entry = tk.Entry(root)
entry.pack(pady=5)

def greet():
name = entry.get()
messagebox.showinfo("Приветствие", f"Привет, {name}!")

button = tk.Button(root, text="Приветствовать", command=greet)
button.pack(pady=10)

root.mainloop()

С развитием веб-технологий наблюдается рост популярности гибридных решений: например, использование Flask/FastAPI в качестве бэкенда и Electron-like обёрток (например, pywebview) для отображения интерфейса в браузере. Это позволяет применять современные фронтенд-фреймворки (React, Vue) вместе с Python.

Tkinter — это стандартный интерфейс языка Python к графической библиотеке Tk, построенной на основе Tcl (Tool Command Language). Он входит в состав стандартной библиотеки CPython и предоставляет доступ к кроссплатформенному набору средств для создания графических пользовательских интерфейсов (GUI). Tkinter не является самостоятельной реализацией GUI-системы, а представляет собой обёртку (binding) вокруг Tcl/Tk, что определяет как его особенности, так и ограничения.

В Python 3 Tkinter переименован в tkinter (с маленькой буквы), однако термин "Tkinter" закрепился как общее обозначение этой системы.

Архитектура Tkinter следует двухуровневой модели:

  • Python-уровень: код на Python, использующий классы и методы из модуля tkinter.
  • Tcl/Tk-уровень: низкоуровневый интерпретатор Tcl, в котором выполняются команды, генерируемые через Python API, и который отвечает за рендеринг виджетов и обработку событий.

Между этими уровнями существует мост (bridge), реализованный на уровне C в составе интерпретатора CPython. Этот мост обеспечивает:

  • Передачу вызовов от Python к Tcl.
  • Сериализацию аргументов в строковые команды Tcl.
  • Получение результатов выполнения и их преобразование обратно в Python-объекты.

Например, вызов:

button = tk.Button(root, text="OK")

…внутри преобразуется в TCL-команду вроде:

button .button1 -text "OK"

… которая выполняется в рамках внутреннего интерпретатора Tcl.

«Внутренний интерпретатор»? Из каких же тогда компонентов состоит Tkinter?

  1. Интерпретатор Tcl. Каждый экземпляр приложения Tkinter автоматически инициализирует встроенный интерпретатор Tcl. Этот интерпретатор управляет жизненным циклом GUI, хранит состояние всех виджетов, выполняет команды рисования, обрабатывает события операционной системы (через Tk).

Важно понимать, что все виджеты существуют в пространстве имён Tcl, а не в памяти Python. Python-объекты (например, tk.Button) являются лишь обёртками, ссылающимися на соответствующие Tcl-идентификаторы.

  1. Главное окно (Tk). Класс tk.Tk() создаёт главное окно приложения и инициирует запуск Tcl-интерпретатора. Это первый и обязательный шаг в любом Tkinter-приложении:
root = tk.Tk()

При создании экземпляра Tk происходит запуск внутреннего интерпретатора Tcl, создание корневого окна в графической подсистеме (X11, Windows GDI, macOS Aqua) и инициализация event loop.

Управление может быть передано только одному экземпляру Tk. Попытка создать второй приведёт к ошибке, если первый не был уничтожен.

  1. Виджеты (Widgets). Виджет — это графический элемент интерфейса: кнопка, метка, поле ввода и т.д. Каждый виджет в Tkinter является подклассом базового класса Widget. Все виджеты наследуются от BaseWidget. То есть, цепочка такова:
BaseWidget → Widget → Mixins → конкретный тип (например, Button, Label).

Виджеты принадлежат иерархии, где каждый виджет имеет родителя (обычно окно или контейнер). Идентифицируются уникальным строковым именем (например, .frame1.button2), которое используется в Tcl.

Пример создания виджета:

label = tk.Label(parent, text="Текст")

Здесь parent — другой виджет (например, Frame или Tk). При создании виджет регистрируется в Tcl-интерпретаторе под уникальным именем.

  1. Геометрические менеджеры (Geometry Managers). Размещение виджетов на экране осуществляется не через абсолютные координаты, а с помощью геометрических менеджеров — специальных систем управления компоновкой:

a) pack(). Располагает виджеты в рамках родительского контейнера в виде потока (сверху, снизу, слева, справа). Подходит для простых линейных интерфейсов.

widget.pack(side="top", fill="x", expand=True)

b) grid(). Организует виджеты в таблицу (строки и столбцы). Наиболее гибкий и часто используемый менеджер для сложных форм.

widget.grid(row=0, column=1, padx=5, pady=5)

c) place(). Позволяет задавать абсолютные или относительные координаты. Редко используется, так как нарушает адаптивность интерфейса.

widget.place(x=100, y=50)

Важно: внутри одного контейнера нельзя смешивать разные менеджеры.

  1. Событийная модель. Tkinter следует парадигме событийно-ориентированного программирования (event-driven programming). Система работает в цикле, ожидая внешних воздействий (движение мыши, нажатие клавиш, изменения размера окна и т.д.).

И основной цикл называется mainloop.

Вызов:

root.mainloop()

Он запускает бесконечный цикл, в котором:

  • ОС отправляет сообщения (события) в Tk.
  • Tk преобразует их в Tcl-события.
  • Tcl вызывает зарегистрированные обработчики.
  • Управление возвращается в Python, если обработчик задан как Python-функция.

Цикл блокирует выполнение последующего кода до закрытия окна.

События связываются с виджетами через метод bind():

widget.bind("<Button-1>", handler)

События обозначаются в угловых скобках: <KeyPress>, <Motion>, <Configure> и т.д. Обработчик получает объект события (Event), содержащий детали: координаты, клавишу, время и др.

Для кнопок и других элементов управления также используется параметр command:

button = tk.Button(root, text="Click", command=handler)

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

Библиотека tkinter.ttk (Themed Tk) предоставляет доступ к современным, стилизованным виджетам, использующим нативную тему операционной системы. Виджеты из ttk выглядят естественнее и интегрированнее:

from tkinter import ttk
button = ttk.Button(root, text="Современная кнопка")

ttk использует ту же архитектуру, но рендерит виджеты с использованием системных стилей (через engine themes). Однако не все виджеты имеют ttk-аналоги, и поведение может отличаться.

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

  • Метод after(ms, func) — отложенное выполнение функции в основном потоке.
  • Очереди (queue.Queue) для передачи данных между потоками.

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

def update_label():
if not q.empty():
value = q.get()
label.config(text=value)
root.after(100, update_label) # Повтор через 100 мс

Альтернативно — использование asyncio с интеграцией через async-tkinter-loop, но это требует сторонних библиотек.

Tkinter — это не независимая GUI-система, а тонкая прослойка между Python и Tcl/Tk. Его архитектура определяется историческими причинами: Tcl/Tk была одной из первых кроссплатформенных GUI-библиотек, и её интеграция в Python обеспечила быстрый доступ к графическим возможностям без необходимости переписывать всё на C.

Для сложных проектов рекомендуется рассмотреть PyQt/PySide или Kivy, но понимание устройства Tkinter помогает осознать фундаментальные принципы построения GUI-приложений в Python.

Разработка игр

Python не является основным языком в индустрии разработки игр. Его динамическая типизация, интерпретируемая природа и относительно низкая производительность делают его малопригодным для создания ресурсоёмких проектов — таких как AAA-игры или масштабные многопользовательские онлайн-платформы. Однако Python остаётся мощным инструментом в контексте обучения, прототипирования, скриптования игровой логики и реализации простых 2D-приложений.

Для этих целей существует ряд библиотек, позволяющих организовать графический вывод, обработку ввода, аудиосопровождение и базовую физику. Наиболее известной и долгоживущей из них является Pygame — кроссплатформенная библиотека, построенная на основе SDL (Simple DirectMedia Layer). Она предоставляет минимально необходимый набор средств для создания 2D-игр и используется преимущественно в образовательных целях, а также в инди-проектах небольшого масштаба.

Следует подчеркнуть: Python не предназначен для создания игровых движков уровня Unreal Engine или Unity. Тем не менее, он может эффективно применяться как средство обучения основам геймдева, анализа алгоритмов поведения персонажей, реализации ИИ в играх, а также как платформа для быстрого прототипирования механик.

Что касается других технологий, то Godot поддерживает язык GDScript, синтаксически близкий к Python, но это не Python. Начиная с версии 4.0, Godot также предлагает официальную поддержку Python через модуль GDExtension (на базе Cython), однако использование Python в Godot — скорее исключение, чем правило. Основная экосистема Godot ориентирована на GDScript, C# и C++. Таким образом, утверждение о том, что Godot «использует Python» — упрощение, не соответствующее действительности в полной мере.

В рамках данной главы мы сосредоточимся на Pygame — наиболее доступной и документированной библиотеке для разработки 2D-игр на чистом Python. Pygame — это набор модулей Python, предоставляющий доступ к низкоуровневым функциям мультимедиа через привязки к библиотеке SDL. Он позволяет работать с графикой, звуком, вводом с клавиатуры, мыши и геймпадов, а также обеспечивает базовые средства для обработки времени и столкновений.

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

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

  1. Окно и поверхности (Surfaces). Центральным понятием в Pygame является поверхность (Surface) — двумерный массив пикселей, представляющий собой область рисования. Каждое изображение, текст или графический элемент в Pygame является экземпляром pygame.Surface. Главное окно игры создаётся с помощью pygame.display.set_mode(), которое возвращает объект Surface, связанный с экраном. Все последующие операции рисования (blitting) выполняются на этой или других поверхностях.
import pygame
screen = pygame.display.set_mode((800, 600))

Поверхности могут быть прозрачными (с альфа-каналом), иметь цветовой ключ (colorkey) для маскирования фона, а также подвергаться трансформациям: масштабированию, повороту, отражению.

  1. Цикл игры (Game Loop). Игровой цикл — фундаментальная структура любой интерактивной программы. В Pygame он реализуется вручную и состоит из трёх этапов:
    • Обработка событий (Event Handling)
    • Обновление состояния игры (State Update)
    • Отрисовка (Rendering) Пример базового цикла:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False

# Обновление логики
update_game_state()

# Отрисовка
screen.fill((0, 0, 0))
draw_objects(screen)
pygame.display.flip()

Цикл выполняется с максимально возможной частотой, обычно ограниченной с помощью pygame.time.Clock, чтобы обеспечить стабильный FPS (например, 60 кадров в секунду).

  1. События (Events). Pygame использует систему очереди событий. Все внешние воздействия — нажатия клавиш, движения мыши, закрытие окна — помещаются в очередь и обрабатываются в цикле через pygame.event.get().

События являются объектами с атрибутами type (тип события) и, опционально, дополнительными данными (key, pos, button и т.д.). Это позволяет реализовать реактивную архитектуру, где игра реагирует на пользовательский ввод асинхронно.

for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.jump()
  1. Спрайты (Sprites). Спрайт в Pygame — это визуальный объект, обычно наследующий от класса pygame.sprite.Sprite. Спрайты объединяют графическое представление (Surface) и положение (Rect), а также могут содержать логику поведения.

Pygame предоставляет систему групп (pygame.sprite.Group) для эффективного управления коллекциями спрайтов: отрисовки, обновления, проверки столкновений.

class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((50, 50))
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = (400, 300)

def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.rect.x -= 5

Группировка спрайтов позволяет отделить логику от представления и упрощает управление сотнями объектов.

  1. Столкновения (Collisions). Pygame предоставляет несколько методов для обнаружения пересечений между прямоугольниками (pygame.Rect). Основные функции:
    • rect1.colliderect(rect2) — проверяет пересечение двух прямоугольников.
    • pygame.sprite.collide_rect(sprite1, sprite2) — то же, для спрайтов.
    • pygame.sprite.spritecollide(sprite, group, dokill) — проверяет столкновение спрайта с группой.

Для более сложных форм используются маски (pygame.mask.from_surface()), обеспечивающие пиксельно-точное обнаружение столкновений, хотя и с большими вычислительными затратами.

  1. Звуки и музыка. Pygame поддерживает воспроизведение аудиофайлов через модули pygame.mixer и pygame.mixer.music.
    • pygame.mixer.Sound — для коротких эффектов (выстрел, прыжок).
    • pygame.mixer.music — для фоновой музыки (поддерживает потоковое воспроизведение).
jump_sound = pygame.mixer.Sound("jump.wav")
jump_sound.play()

pygame.mixer.music.load("background.mp3")
pygame.mixer.music.play(-1) # зацикливание

Поддерживаются форматы WAV, MP3, OGG. Однако качество и стабильность воспроизведения зависят от платформы и бэкенда SDL.

Пример: реализация «Змейки». Это классический пример, демонстрирующий работу с циклом, вводом, отрисовкой и логикой столкновений.

Основные компоненты:

  • Состояние змейки: список координат её сегментов.
  • Направление движения: вектор (dx, dy).
  • Еда: случайно генерируемая позиция.
  • Условия завершения: выход за границы поля или самопересечение.

Полный код:

import pygame
import random

pygame.init()

white = (255, 255, 255)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)

width = 600
height = 400

screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Змейка')

clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15

font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)

def your_score(score):
value = score_font.render("Счёт: " + str(score), True, black)
screen.blit(value, [0, 0])

def our_snake(snake_block, snake_list):
for x in snake_list:
pygame.draw.rect(screen, green, [x[0], x[1], snake_block, snake_block])

def message(msg, color):
mesg = font_style.render(msg, True, color)
screen.blit(mesg, [width / 6, height / 3])

def gameLoop():
game_over = False
game_close = False

x1 = width / 2
y1 = height / 2

x1_change = 0
y1_change = 0

snake_list = []
length_of_snake = 1

foodx = round(random.randrange(0, width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, height - snake_block) / 10.0) * 10.0

while not game_over:

while game_close:
screen.fill(white)
message("Ты проиграл! C - продолжить, Q - выйти", red)
your_score(length_of_snake - 1)
pygame.display.update()

for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
game_over = True
game_close = False
if event.key == pygame.K_c:
gameLoop()

for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x1_change = -snake_block
y1_change = 0
elif event.key == pygame.K_RIGHT:
x1_change = snake_block
y1_change = 0
elif event.key == pygame.K_UP:
y1_change = -snake_block
x1_change = 0
elif event.key == pygame.K_DOWN:
y1_change = snake_block
x1_change = 0

if x1 >= width or x1 < 0 or y1 >= height or y1 < 0:
game_close = True

x1 += x1_change
y1 += y1_change

screen.fill(white)
pygame.draw.rect(screen, red, [foodx, foody, snake_block, snake_block])

snake_head = [x1, y1]
snake_list.append(snake_head)

if len(snake_list) > length_of_snake:
del snake_list[0]

for x in snake_list[:-1]:
if x == snake_head:
game_close = True

our_snake(snake_block, snake_list)
your_score(length_of_snake - 1)

pygame.display.update()

if x1 == foodx and y1 == foody:
foodx = round(random.randrange(0, width - snake_block) / 10.0) * 10.0
foody = round(random.randrange(0, height - snake_block) / 10.0) * 10.0
length_of_snake += 1

clock.tick(snake_speed)

pygame.quit()
quit()

gameLoop()

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

Для серьёзных проектов рекомендуется использовать специализированные игровые движки: Godot, Unity, Unreal. Однако для обучения, прототипирования или реализации простых 2D-игр Python с Pygame остаётся практичным и доступным выбором.