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

Как писать игры на Python с Pygame

Команда Timeweb Cloud
Команда Timeweb Cloud
Наши инженеры, технические писатели, редакторы и маркетологи
18 апреля 2022 г.
4289
12 минут чтения
Средний рейтинг статьи: 3

New Documentation

Этот туториал поможет вам сделать заготовку для простой игры, в которой вы будете перемещать своего персонажа, чтобы избежать столкновения с препятствиями. Вы будете использовать Pygame — набор модулей Python, предназначенных для написания видеоигр. Pygame добавляет функциональность поверх превосходной библиотеки SDL. В последней версии используется Pygame SDL2.

Как Писать Игры На Python С Pygame

Установка библиотеки

Pygame состоит из нескольких модулей с функциями для рисования графики, воспроизведения звуков, обработки ввода с помощью мыши и других вещей, которые вам понадобятся при разработке своей первой игры на Python 3

Для начала работы с библиотекой необходимо добавить ее в локальную среду разработки. На Python Pygame-установка выполняется через pip:

 python -m pip install -U pygame --user

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

python -m pygame.examples.aliens

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

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

Игровой цикл

Игровой цикл — это место, где все игровые события происходят, обновляются и отображаются на экране. Как только первоначальная настройка и инициализация переменных завершены, начинается игровой цикл, в котором программа продолжает повторяться снова и снова, пока не произойдет событие типа QUIT.

Ниже приведен тип цикла Game, который мы будем использовать в нашей программе Pygame.

while True:
      # Code
      pygame.display.update()

Изменения в игре не вступают в силу до тех пор, пока не будет выполнена команда display.update(). Поскольку в играх всё безостановочно меняется, функция обновления находится в игровом цикле и тоже выполняется постоянно.

Выход из игрового цикла

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

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

Мы вызываем pygame.quit() и sys.exit(), чтобы закрыть окно Pygame и завершить скрипт Python соответственно. Простое использование sys.exit() может привести к зависанию IDE.

Игровые события

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

Вы можете узнать, какие события произошли, вызвав функцию pygame.event.get(). Она возвращает список объектов pygame.event.Event. Для краткости будем называть это объектами событий.

Одним из многих атрибутов (или свойств), которыми обладают объекты событий, является тип — type. Атрибут type сообщает, какое событие представляет объект.

В примере выше использован event.type == QUIT. Он помогает определить, должна игра быть закрыта или нет. Пока пользователь не закроет игру (говоря языком Pygame, не вызовет событие ‘QUIT’), она будет работать в бесконечном цикле.

Игровой экран

Для игры нужно создать окно фиксированного размера, внутри которого будут происходить все события. Ширина и высота этого окна в пикселях передаются в функцию pygame set mode в виде кортежа.

DISPLAYSURF = pygame.display.set_mode((300,300))

Пиксель — наименьшая возможная область на экране. Не существует половины пикселя или четверти пикселя. Поэтому ширина и высота должны быть целыми числами.

Кадровая частота

Если не задать ограничение на частоту кадров, компьютер будет выполнять игровой цикл столько раз, сколько может в течение секунды. Чтобы ограничить его, используйте метод ‘tick(fps)’, где fps — целое число. Метод ‘tick(fps)’ принадлежит классу ‘pygame.time.Clock’ и должен использоваться с объектом этого класса.

FPS = pygame.time.Clock()
FPS.tick(60)

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

Цвета

Pygame использует систему цветов RGB (Red, Green, Blue). Значения для каждого цвета находятся в диапазоне от 0 до 255, всего 256 значений. Сочетание этих трех цветов используется для создания всех цветов, которые вы видите на компьютерах или на любом устройстве с экраном.

Чтобы использовать цвета в Pygame, создают объекты Color, используя значения RGB. Значения RGB должны быть в формате кортежа с тремя значениями для каждого основного цвета.

BLACK = pygame.Color(0, 0, 0)
WHITE = pygame.Color(255, 255, 255)
GREY = pygame.Color(128, 128, 128)
RED = pygame.Color(255, 0, 0)

В работе с цветами есть одна особенность. Например, если вы нарисуете квадрат и зададите ему зеленый цвет, то по умолчанию зелеными станут только границы. Для полной заливки объектов используйте метод ‘fill’. Это сделает квадрат полностью зеленым.

Создание игры

Теперь пришло время заняться самым интересным — разработать первую игру.

Вот так выглядит полный код проекта, который получится у вас после прохождения этого туториала.

# Импортируем библиотеки
import pygame, sys
from pygame.locals import *
import random

# Инициализируем Pygame
pygame.init()

# Ограничиваем количество кадров в секунду
FPS = 60
FramePerSec = pygame.time.Clock()

# Задаем цвет
WHITE = (255, 255, 255)

# Задаем размеры игрового экрана
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 600 

# Отрисовываем экран и заливаем его белым цветом
DISPLAYSURF = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT)))
DISPLAYSURF.fill(WHITE)
pygame.display.set_caption("Game")

# Определяем класс игрока
class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__() 
        self.image = pygame.image.load("Player.png")
        self.rect = self.image.get_rect()
        self.rect.center = (160, 520) 

    def update(self):
        pressed_keys = pygame.key.get_pressed()            
        if self.rect.left > 0:
              if pressed_keys[K_LEFT]:
                  self.rect.move_ip(-5, 0)
        if self.rect.right < SCREEN_WIDTH:        
              if pressed_keys[K_RIGHT]:
                  self.rect.move_ip(5, 0) 

    def draw(self, surface):
        surface.blit(self.image, self.rect)     

# Определяем класс врага
class Enemy(pygame.sprite.Sprite):
      def __init__(self):
        super().__init__() 
        self.image = pygame.image.load("Enemy.png")
        self.rect = self.image.get_rect()
        self.rect.center=(random.randint(40,SCREEN_WIDTH-40),0) 

      def move(self):
        self.rect.move_ip(0,10)
        if (self.rect.bottom > 600):
            self.rect.top = 0
            self.rect.center = (random.randint(30, 370), 0) 

      def draw(self, surface):
        surface.blit(self.image, self.rect)          

# Создаем персонажей
P1 = Player()
E1 = Enemy()

# Определяем игровой цикл
while True:     
    for event in pygame.event.get():              
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    P1.update()
    E1.move()     

    DISPLAYSURF.fill(WHITE)
    P1.draw(DISPLAYSURF)
    E1.draw(DISPLAYSURF)         

    pygame.display.update()
    FramePerSec.tick(FPS)

Теперь давайте разбирать, какие Pygame Python-команды здесь используются.

Инициализация игры

Создание игры на Python с Pygame начинается с импорта библиотеки. Откройте файл в любой IDE или редакторе кода и добавьте две строки:

import pygame
from pygame.locals import *

Первой строкой вы импортировали модуль Pygame Python 3. Второй строкой вы импортировали все переменные из pygame.locals. 

Можно обойтись без второго импорта. Но он заметно сокращает количество кода. Например, событие выхода из игры без импорта переменных из pygame.locals придется записывать так: ‘pygame.locals.QUIT’. С импортом же синтаксис гораздо короче — для добавления события достаточно написать ‘QUIT’. 

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

 import random

В начале файла должна быть ещё одна важная строка:

pygame.init()

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

Определение персонажей

В проекте используется объектно-ориентированный подход. Это позволяет создавать классы, которые становятся основой для разных персонажей. Например, у вас будет один класс врагов (препятствий в игре), а по мере прохождения раундов они будут видоизменяться и получать дополнительные способности.

Сначала определим класс игрока:

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__() 
        self.image = pygame.image.load("Player.png")
        self.rect = self.image.get_rect()
        self.rect.center = (160, 520)

Функция image.load() принимает на вход файл изображения. Чтобы определить границы спрайта игрока, достаточно вызвать функцию get_rect(). Она автоматически создаст прямоугольник того же размера, что и изображение. Это будет полезно в дальнейшей разработке, когда вы, например, будете реализовывать логику столкновения объектов. Последняя строка self.rect.center определяет начальную позицию персонажа на игровом поле.

def update(self):
    pressed_keys = pygame.key.get_pressed()  
    if self.rect.left > 0:
          if pressed_keys[K_LEFT]:
              self.rect.move_ip(-5, 0)
    if self.rect.left > 0:       
          if pressed_keys[K_RIGHT]:
              self.rect.move_ip(5, 0)

Метод update управляет движением игрока. При его вызове выполняется проверка, нажаты ли клавиши.  

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

Метод move_ip() принимает два параметра. Первый параметр — это расстояние в пикселях, на которое необходимо переместить объект по горизонтали. Второй параметр — расстояние, на которое необходимо переместить объект по вертикали.

Операторы if self.rect.left > 0 и if self.rect.left > 0 гарантируют, что игрок не выйдет за пределы игрового поля.

def draw(self, surface):
    surface.blit(self.image, self.rect)     

Функция blit() принимает параметры. Первый — объект для отрисовки, а второй — его спрайт. Поскольку вы используете изображение, то передаете self.image в качестве объекта для отрисовки. 

Класс врага устроен очень похоже. Единственное отличие — использование генератора случайных чисел:

self.rect.center=(random.randint(40,SCREEN_WIDTH-40),0) 

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

Игровой цикл

И самая важная часть — игровой цикл:

while True:     
    for event in pygame.event.get():              
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    P1.update()
    E1.move()     

    DISPLAYSURF.fill(WHITE)
    P1.draw(DISPLAYSURF)
    E1.draw(DISPLAYSURF)

    pygame.display.update()
    FramePerSec.tick(FPS)

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

Сначала вызываются функции update для классов Enemy и Player. Далее цикл обновляет экран с помощью DISPLAY.fill(WHITE). Наконец, вызывается функция draw для отрисовки объектов на экране.

Наконец, команда pygame.display.update() обновляет экран, выводя все изменения, которые произошли до этого момента. Функция tick() гарантирует, что количество кадров в секунду при этом не превышает установленного ранее значения FPS.

Заключение

Игра готова. Она пока не настолько хороша, чтобы арендовать сервер для хостинга на timeweb.cloud и ждать наплыва игроков. Но это ваша первая игра на Питон и теперь вы знаете, как сделать ее лучше. Например, как добавить персонажу движение вверх и вниз или изменить логику появления препятствий.

Возможностей для совершенствования проекта очень много. Например, можно сделать двумерную игру трехмерной, используя Pygame raycast. Да, на Pygame не получится разработать клона Cyberpunk 2077, но свою версию Wolfenstein 3D сделать реально. 

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

Зарегистрируйтесь и начните пользоваться
сервисами Timeweb Cloud прямо сейчас

15 лет опыта
Сосредоточьтесь на своей работе: об остальном позаботимся мы
165 000 клиентов
Нам доверяют частные лица и компании, от небольших фирм до корпораций
Поддержка 24/7
100+ специалистов поддержки, готовых помочь в чате, тикете и по телефону