Библиотека Pygame для 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 завершает программу.