🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Учимся анимировать графику и изображения, обрабатывать столкновения, запоминать состояния и управлять персонажами. В конце статьи сделаем 10 мини-симуляторов и лайт-версий известных игр.
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Python – интерпретируемый язык, и по этой причине он не отличается высокой производительностью, которая необходима для сложных игр с гиперреалистичной графикой. Тем не менее есть несколько способов оптимизации, которые значительно ускоряют выполнение Python-кода, что позволяет писать на Питоне вполне приличные игры. Оптимизацию необязательно делать самостоятельно – в значительной степени эту задачу берут на себя специальные фреймворки и библиотеки. Фреймворков и библиотек для разработки игр на основе Python довольно много, вот самые популярные:

  • Pygame
  • PyKyra
  • Pyglet
  • Panda3D
  • Kivy
  • PyopenGL

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

Pygame не входит в стандартную поставку Python, для установки библиотеки выполните:

        pip install pygame
    

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

🐍🎓 Библиотека собеса по Python
Подтянуть свои знания по Python вы можете на нашем телеграм-канале «Библиотека собеса по Python»
🐍🧩 Библиотека задач по Python
Интересные задачи по Python для практики можно найти на нашем телеграм-канале «Библиотека задач по Python»

Окно и главный цикл приложения

Создание любого приложения на базе Pygame начинается с импорта и инициализации библиотеки. Затем нужно определить параметры окна, и по желанию – задать цвет (или изображение) фона:

        import pygame

# инициализируем библиотеку Pygame
pygame.init()

# определяем размеры окна
window_size = (300, 300)

# задаем название окна
pygame.display.set_caption("Синий фон")

# создаем окно
screen = pygame.display.set_mode(window_size)

# задаем цвет фона
background_color = (0, 0, 255)  # синий

# заполняем фон заданным цветом
screen.fill(background_color)

# обновляем экран для отображения изменений
pygame.display.flip()

# показываем окно, пока пользователь не нажмет кнопку "Закрыть"
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    

🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Цикл while True играет роль главного цикла программы – в нем происходит отслеживание событий приложения и действий пользователя. Функция pygame.quit() завершает работу приложения, и ее можно назвать противоположностью функции pygame.init(). Для завершения Python-процесса используется exit(), с той же целью можно использовать sys.exit(), но ее нужно импортировать в начале программы: import sys.

В качестве фона можно использовать изображение:

        import pygame

pygame.init()

window_size = (400, 400)
screen = pygame.display.set_mode(window_size)
pygame.display.set_caption("Peter the Piglet")

# загружаем изображение
background_image = pygame.image.load("background.png")

# подгоняем масштаб под размер окна
background_image = pygame.transform.scale(background_image, window_size)

# накладываем изображение на поверхность
screen.blit(background_image, (0, 0))

pygame.display.flip()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()

    
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

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

        import pygame

pygame.init()
pygame.display.set_caption('Измени цвет фона')
window_surface = pygame.display.set_mode((300, 300))
background = pygame.Surface((300, 300))
background.fill(pygame.Color('#000000'))

color_list = [
    pygame.Color('#FF0000'),  # красный
    pygame.Color('#00FF00'),  # зеленый
    pygame.Color('#0000FF'),  # синий
    pygame.Color('#FFFF00'),  # желтый
    pygame.Color('#00FFFF'),  # бирюзовый
    pygame.Color('#FF00FF'),  # пурпурный
    pygame.Color('#FFFFFF')   # белый
]

current_color_index = 0

button_font = pygame.font.SysFont('Verdana', 15) # используем шрифт Verdana
button_text_color = pygame.Color("black")
button_color = pygame.Color("gray")
button_rect = pygame.Rect(100, 115, 100, 50)
button_text = button_font.render('Нажми!', True, button_text_color)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if button_rect.collidepoint(event.pos):
                current_color_index = (current_color_index + 1) % len(color_list)
                background.fill(color_list[current_color_index])

        window_surface.blit(background, (0, 0))
        pygame.draw.rect(window_surface, button_color, button_rect)
        button_rect_center = button_text.get_rect(center=button_rect.center)
        window_surface.blit(button_text, button_rect_center)
        pygame.display.update()

    
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Как очевидно из приведенного выше примера, основной цикл Pygame приложения состоит из трех повторяющихся действий:

  • Обработка событий (нажатий клавиш или кнопок).
  • Обновление состояния.
  • Отрисовка состояния на экране.
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

GUI для PyGame

Pygame позволяет легко и быстро интегрировать в проект многие нужные вещи – шрифты, звук, обработку событий, – однако не имеет встроенных виджетов для создания кнопок, лейблов, индикаторов выполнения и других подобных элементов интерфейса. Эту проблему разработчик должен решать либо самостоятельно (нарисовать прямоугольник, назначить ему функцию кнопки), либо с помощью дополнительных GUI-библиотек. Таких библиотек несколько, к самым популярным относятся:

Вот простой пример использования Pygame GUI – зеленые нули и единицы падают вниз в стиле «Матрицы»:

        import pygame
import pygame_gui
import random

window_size = (800, 600)
window = pygame.display.set_mode(window_size)
pygame.display.set_caption('Матрица Lite')
pygame.init()
gui_manager = pygame_gui.UIManager(window_size)

font = pygame.font.SysFont('Consolas', 20)
text_color = pygame.Color('green')
text_symbols = ['0', '1']
text_pos = [(random.randint(0, window_size[0]), 0) for i in range(50)]
text_speed = [(0, random.randint(1, 5)) for i in range(50)]
text_surface_list = []

button_size = (100, 50)
button_pos = (350, 250)
button_text = 'Матрица!'

button = pygame_gui.elements.UIButton(
    relative_rect=pygame.Rect(button_pos, button_size),
    text=button_text,
    manager=gui_manager
)

while True:
    time_delta = pygame.time.Clock().tick(60) 

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

        if event.type == pygame_gui.UI_BUTTON_PRESSED:
            text_surface_list = []
            for i in range(50):
                text_symbol = random.choice(text_symbols)
                text_surface = font.render(text_symbol, True, text_color)
                text_surface_list.append(text_surface)

        gui_manager.process_events(event)

    gui_manager.update(time_delta)

    window.fill(pygame.Color('black'))

    for i in range(50):
        text_pos[i] = (text_pos[i][0], text_pos[i][1] + text_speed[i][1])
        if text_pos[i][1] > window_size[1]:
            text_pos[i] = (random.randint(0, window_size[0]), -20)
        if len(text_surface_list) > i:
            window.blit(text_surface_list[i], text_pos[i])

    gui_manager.draw_ui(window)
    pygame.display.update()

    
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Рисование

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

        import pygame
import math

pygame.init()
screen_width = 640
screen_height = 480
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Геометрические фигуры")

black = (0, 0, 0)
white = (255, 255, 255)
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
pink = (255, 192, 203)

# рисуем прямоугольник
rect_x = 50
rect_y = 50
rect_width = 100
rect_height = 50
pygame.draw.rect(screen, red, (rect_x, rect_y, rect_width, rect_height))

# рисуем круг
circle_x = 200
circle_y = 75
circle_radius = 30
pygame.draw.circle(screen, green, (circle_x, circle_y), circle_radius)

# рисуем треугольник
triangle_x = 350
triangle_y = 50
triangle_width = 100
triangle_height = 100
triangle_points = [(triangle_x, triangle_y), (triangle_x + triangle_width, triangle_y),
                   (triangle_x + triangle_width / 2, triangle_y + triangle_height)]
pygame.draw.polygon(screen, blue, triangle_points)

# рисуем пятиугольник
pent_x = 500
pent_y = 100
radius = 40
sides = 5
pent_points = []
for i in range(sides):
    angle_deg = 360 * i / sides
    angle_rad = math.radians(angle_deg)
    x = pent_x + radius * math.sin(angle_rad)
    y = pent_y - radius * math.cos(angle_rad)
    pent_points.append((x, y))
pygame.draw.polygon(screen, white, pent_points)

# рисуем эллипс
ellipse_x = 100
ellipse_y = 275
ellipse_width = 150
ellipse_height = 60
pygame.draw.ellipse(screen, red, (ellipse_x, ellipse_y, ellipse_width, ellipse_height))

# горизонтальная линия
horiz_line_y = 400
pygame.draw.line(screen, blue, (50, horiz_line_y), (590, horiz_line_y), 5)

# вертикальная линия
vert_line_x = 320
pygame.draw.line(screen, green, (vert_line_x, 50), (vert_line_x, 430), 5)

# рисуем желтую звезду
yellow_star_points = [(260 - 50, 250 - 70), (310 - 50, 250 - 70), (325 - 50, 200 - 70),
                      (340 - 50, 250 - 70), (390 - 50, 250 - 70), (350 - 50, 290 - 70),
                      (365 - 50, 340 - 70), (325 - 50, 305 - 70), (285 - 50, 340 - 70),
                      (300 - 50, 290 - 70)]
pygame.draw.polygon(screen, yellow, yellow_star_points)

# рисуем окружность с квадратом внутри
circle2_x = 490
circle2_y = 350
circle2_radius = 80
pygame.draw.circle(screen, white, (circle2_x, circle2_y), circle2_radius)
square_side = 60
square_x = circle2_x - square_side / 2
square_y = circle2_y - square_side / 2
pygame.draw.rect(screen, pink, (square_x, square_y, square_side, square_side))

pygame.display.update()

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

    
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame

Анимация и обработка событий

Выше, в примере с падающими символами в «Матрице», уже был показан принцип простейшей имитации движения, который заключается в последовательном изменении координат объекта и обновлении экрана с установленной частотой кадра pygame.time.Clock().tick(60). Усложним задачу – сделаем простую анимацию с падающими розовыми «звездами». Приложение будет поддерживать обработку двух событий:

  • При клике мышью по экрану анимация останавливается.
  • При нажатии клавиши Enter – возобновляется.

Кроме того, добавим счетчик упавших звезд. Готовый код выглядит так:

        import pygame
import random

pygame.init()

screen_width = 640
screen_height = 480
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Звезды падают вниз")

black = (0, 0, 0)
white = (255, 255, 255)
pink = (255, 192, 203)

font = pygame.font.SysFont("Verdana", 15)

star_list = []
for i in range(50):
    x = random.randrange(screen_width)
    y = random.randrange(-200, -50)
    speed = random.randrange(1, 5)
    star_list.append([x, y, speed])
score = 0

freeze = False # флаг для определения момента остановки

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
        if event.type == pygame.MOUSEBUTTONDOWN: # останавливаем падение звезд по клику
            freeze = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN: # возобновляем движение вниз, если нажат Enter
                freeze = False

    if not freeze: # если флаг не активен,
        # звезды падают вниз
        for star in star_list:
            star[1] += star[2]
            if star[1] > screen_height:
                star[0] = random.randrange(screen_width)
                star[1] = random.randrange(-200, -50)
                score += 1

    # рисуем звезды, выводим результаты подсчета
    screen.fill(black)
    for star in star_list:
        pygame.draw.circle(screen, pink, (star[0], star[1]), 3)
    score_text = font.render("Упало звезд: " + str(score), True, white)
    screen.blit(score_text, (10, 10))

    pygame.display.update()

    # устанавливаем частоту обновления экрана
    pygame.time.Clock().tick(60)

    
🐍 Самоучитель по Python для начинающих. Часть 21: Основы разработки игр на Pygame
***

Отлично! Вы освоили основы Pygame и создали свою первую интерактивную анимацию.

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

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

  • Научитесь создавать покадровую анимацию для персонажей.
  • Реализуете обнаружение столкновений — основу любой игровой механики.
  • Добавите полноценное управление персонажем с клавиатуры.
  • Напишете 10 полноценных мини-игр, включая «Лабиринт», «Змейку» и «Memory», чтобы создать свое первое игровое портфолио.

МЕРОПРИЯТИЯ

Над какой игрой трудитесь? Расскажите в комментариях!

 
 

ВАКАНСИИ

Добавить вакансию
Go-разработчик
по итогам собеседования
Senior Go / Kubernetes Engineer
от 3000 USD до 7000 USD
Middle/Senior C++ HFT разработчик
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

LIVE >

Подпишись

на push-уведомления