Библиотека Pygame для Python: подробное руководство

Раздел: Python -> Библиотеки для игр

Основы работы с Pygame

Как установить библиотеку Pygame?

Для установки Pygame используется менеджер пакетов pip. Проще всего выполнить команду:

pip install pygame

библиотека pygame python (библиотека pygame для python)

Убедитесь, что Python и pip установлены корректно. После успешной установки можно импортировать библиотеку:

import pygame
pygame.init()

Это инициализирует все модули Pygame. Если инициализация прошла успешно, код завершится без ошибок.

Альтернативный способ - установка из исходного кода или использование виртуального окружения. Например, для работы с конкретной версией:

pip install pygame==2.5.2

Почему стоит устанавливать в виртуальное окружение?

Изоляция зависимостей помогает избежать конфликтов с другими проектами. Создайте окружение командой python -m venv myenv, активируйте его и установите pygame.

Частая ошибка: модуль не найден (ModuleNotFoundError). Причина - установка в другое окружение или отсутствие pip. Решение: проверьте, какой интерпретатор Python используется, и выполните установку в том же окружении, где запускается скрипт.

Как создать игровое окно?

Создание окна минимального размера 800x600 пикселей:

screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Моя игра')

Функция set_mode возвращает поверхность, на которой происходит вся отрисовка. Заголовок окна задается через set_caption.

Как сделать окно полноэкранным?

Используйте флаг pygame.FULLSCREEN:

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

Размер (0, 0) автоматически подстраивается под разрешение экрана. Другие флаги: pygame.RESIZABLE, pygame.NOFRAME.

Проблема: окно не закрывается или зависает. Для корректного завершения нужно в игровом цикле обрабатывать событие pygame.QUIT:

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

Как организовать основной игровой цикл?

Стандартный цикл с фиксированной частотой кадров (FPS):

clock = pygame.time.Clock()
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    # Логика обновления
    
    screen.fill((0, 0, 0))  # Очистка экрана
    # Отрисовка объектов
    pygame.display.flip()
    clock.tick(60)  # 60 FPS

clock.tick(60) ограничивает скорость цикла, чтобы игра не потребляла 100% процессора.

Можно ли обойтись без clock?

Да, но тогда игра будет выполняться с максимальной скоростью, что неудобно. Альтернатива - использование pygame.time.get_ticks() для ручного управления временем.

prev_time = pygame.time.get_ticks()
while running:
    now = pygame.time.get_ticks()
    delta = now - prev_time
    # Используйте delta для независимой от FPS логики
    prev_time = now

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

Как обрабатывать события клавиатуры и мыши?

Простейший способ - опрос состояния клавиш:

keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    # движение влево

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

for event in pygame.event.get():
    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_SPACE:
            # прыжок

Мышь:

if event.type == pygame.MOUSEBUTTONDOWN:
    x, y = event.pos
    if event.button == 1:  # левая кнопка

Как получить позицию мыши непрерывно?

Используйте pygame.mouse.get_pos():

mouse_x, mouse_y = pygame.mouse.get_pos()

Для скрытия курсора: pygame.mouse.set_visible(False).

Проблема: события дублируются или не обрабатываются. Убедитесь, что pygame.event.get() вызывается один раз за кадр, и события не обрабатываются повторно.

Как рисовать фигуры и текст?

Для рисования геометрических форм используются функции модуля pygame.draw:

# Прямоугольник (поверхность, цвет, rect, толщина)
pygame.draw.rect(screen, (255, 0, 0), (50, 50, 200, 100), 0)
# Круг
pygame.draw.circle(screen, (0, 255, 0), (400, 300), 50)
# Линия
pygame.draw.line(screen, (0, 0, 255), (0, 0), (800, 600), 5)

Текст рисуется через объект Font:

font = pygame.font.Font(None, 36)  # шрифт по умолчанию, размер 36
text_surface = font.render('Привет, мир!', True, (255, 255, 255))
screen.blit(text_surface, (100, 100))

Как использовать собственный шрифт?

Укажите путь к файлу .ttf:

font = pygame.font.Font('arial.ttf', 28)

Если шрифт не найден, Pygame использует системный шрифт по умолчанию.

Ошибка: текст не отображается. Причина - не вызывается blit после screen.fill или экран не обновляется (flip). Также может быть проблема с кириллицей: шрифт должен поддерживать Unicode.

Как работать со спрайтами и анимацией?

Спрайт - это объект, который содержит изображение и прямоугольник. Класс pygame.sprite.Sprite упрощает управление:

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill((0, 0, 255))
        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
        if keys[pygame.K_RIGHT]:
            self.rect.x += 5

Группа спрайтов обновляется и рисуется одной командой:

all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
# В цикле:
all_sprites.update()
screen.fill((0,0,0))
all_sprites.draw(screen)

Как сделать анимацию из нескольких кадров?

Загрузите список изображений и переключайте их по таймеру:

self.frames = [pygame.image.load(f'frame{i}.png') for i in range(4)]
self.current_frame = 0
self.image = self.frames[self.current_frame]
self.animation_speed = 10  # смена через 10 кадров
self.counter = 0
# В update:
self.counter += 1
if self.counter >= self.animation_speed:
    self.counter = 0
    self.current_frame = (self.current_frame + 1) % len(self.frames)
    self.image = self.frames[self.current_frame]

Проблема: спрайты двигаются рывками. Проверьте, что clock.tick установлен, и скорость движения делится равномерно на FPS (например, 300 пикселей в секунду => 5 пикселей за кадр при 60 FPS).

Как добавить звук?

Загрузите звуковой файл (WAV, MP3) и воспроизведите:

sound = pygame.mixer.Sound('laser.wav')
sound.play()
# Фоновая музыка:
pygame.mixer.music.load('background.mp3')
pygame.mixer.music.play(-1)  # бесконечно

Уровень громкости: sound.set_volume(0.5), pygame.mixer.music.set_volume(0.3).

Как использовать несколько каналов?

По умолчанию 8 каналов. Можно выделить отдельный канал:

channel = pygame.mixer.Channel(1)
channel.play(sound)

Это позволяет управлять звуками индивидуально (пауза, остановка).

Ошибка: звук не воспроизводится. Возможные причины: файл отсутствует, не поддерживается формат (лучше использовать WAV или OGG), или не инициализирован микшер: pygame.mixer.init() (выполняется автоматически при pygame.init()).

Как обнаружить столкновения объектов?

Для прямоугольников используйте colliderect:

if player.rect.colliderect(enemy.rect):
    # столкновение

Для группы спрайтов:

hits = pygame.sprite.spritecollide(player, enemies, True)  # True - удалить попавших

Как проверить столкновение кругов?

Вычислите расстояние между центрами:

dx = x1 - x2
dy = y1 - y2
distance = (dx**2 + dy**2)**0.5
if distance < radius1 + radius2:
    # столкновение

Или используйте pygame.math.Vector2 для удобства.

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

Расширенные примеры использования Pygame

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

Пример
import pygame
import random

pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
font = pygame.font.Font(None, 36)

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((50, 50))
        self.image.fill((0, 128, 255))
        self.rect = self.image.get_rect(center=(400, 500))
        self.speed = 5
    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] and self.rect.left > 0:
            self.rect.x -= self.speed
        if keys[pygame.K_RIGHT] and self.rect.right < 800:
            self.rect.x += self.speed

class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((10, 20))
        self.image.fill((255, 255, 0))
        self.rect = self.image.get_rect(center=(x, y))
        self.speed = -10
    def update(self):
        self.rect.y += self.speed
        if self.rect.bottom < 0:
            self.kill()

class Enemy(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((40, 40))
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect(
            center=(random.randint(20, 780), random.randint(-100, -40)))
        self.speed = random.randint(2, 5)
    def update(self):
        self.rect.y += self.speed
        if self.rect.top > 600:
            self.kill()

all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

# Таймер появления врагов
enemy_timer = 0
running = True
score = 0

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                bullet = Bullet(player.rect.centerx, player.rect.top)
                all_sprites.add(bullet)
                bullets.add(bullet)
    
    # Создание врагов
    enemy_timer += 1
    if enemy_timer > 30:
        enemy = Enemy()
        all_sprites.add(enemy)
        enemies.add(enemy)
        enemy_timer = 0
    
    # Столкновения пуль с врагами
    hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
    for hit in hits:
        score += 10
    
    # Столкновение игрока с врагами
    if pygame.sprite.spritecollide(player, enemies, False):
        running = False  # Игра окончена
    
    all_sprites.update()
    
    screen.fill((0, 0, 0))
    all_sprites.draw(screen)
    
    # Отображение счета
    score_text = font.render(f'Score: {score}', True, (255, 255, 255))
    screen.blit(score_text, (10, 10))
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Результат: окно 800x600, в котором игрок (синий квадрат) управляется стрелками, стреляет пробелом (жёлтые снаряды). Сверху появляются красные враги. При попадании враг исчезает, добавляется 10 очков. При столкновении с игроком игра завершается.

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

Пример
class AnimatedSprite(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.images = []
        for i in range(4):
            img = pygame.image.load(f'walk{i}.png')
            self.images.append(img)
        self.index = 0
        self.image = self.images[self.index]
        self.rect = self.image.get_rect(center=(x, y))
        self.counter = 0
        self.speed = 8  # кадров анимации до смены
    def update(self):
        self.counter += 1
        if self.counter >= self.speed:
            self.counter = 0
            self.index = (self.index + 1) % len(self.images)
            self.image = self.images[self.index]
Результат: циклическая смена кадров, создающая эффект ходьбы. Если файлы не найдены, возникнет ошибка. Для проверки можно создать простые поверхности вручную.

Пример работы со звуком и таймером.

Пример
import pygame

pygame.init()
pygame.mixer.init()
sound_click = pygame.mixer.Sound('click.wav')

clock = pygame.time.Clock()
last_shot = 0
cooldown = 500  # миллисекунды

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                now = pygame.time.get_ticks()
                if now - last_shot >= cooldown:
                    sound_click.play()
                    last_shot = now
                    print('Shot fired')
    clock.tick(60)
pygame.quit()
Вывод в консоль: 'Shot fired' каждые 500 мс при нажатии пробела. Звук click.wav воспроизводится с задержкой.

Дополнительный пример: создание текстового меню.

Пример
import pygame

pygame.init()
screen = pygame.display.set_mode((400, 300))
font = pygame.font.Font(None, 48)

items = ['Start Game', 'Options', 'Exit']
selected = 0

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP:
                selected = (selected - 1) % len(items)
            if event.key == pygame.K_DOWN:
                selected = (selected + 1) % len(items)
            if event.key == pygame.K_RETURN:
                print(f'Selected: {items[selected]}')
                if items[selected] == 'Exit':
                    running = False
    
    screen.fill((30, 30, 30))
    for i, item in enumerate(items):
        color = (255, 255, 0) if i == selected else (200, 200, 200)
        text = font.render(item, True, color)
        text_rect = text.get_rect(center=(200, 80 + i * 60))
        screen.blit(text, text_rect)
    pygame.display.flip()
    clock.tick(30)

pygame.quit()
Результат: окно с тремя пунктами меню. Клавишами вверх/вниз переключается выделение, Enter выводит в консоль выбранный пункт. Exit завершает программу.

Библиотека Pygame для Python - comments

En
библиотека pygame python (python)