Баннер мобильный (3) Пройти тест

Как создать простую игру «Змейка» на Python и Pygame

Пошаговый процесс создания игры на Python с примерами и готовым кодом

Инструкция

21 ноября 2024

Поделиться

Скопировано
Как создать простую игру «Змейка» на Python и Pygame

Содержание

    Игра «Змейка» существует уже почти 50 лет. За это время программисты успели разработать множество модификаций для разных платформ. В этой статье подробно разбираем процесс создания игры на Python с помощью библиотеки Pygame.

    История

    Прообраз классической «Змейки» появился в 1976 году в виде игры Blockade для аркадных автоматов. В нее могли играть сразу два пользователя, каждому из которых надо было передвигать по игровому полю длинную фигуру, похожую на змею. Фигура отставляла за собой шлейф, в который другому игроку нельзя было врезаться. Если все же врезаться, то игра начиналась снова, а проигрывал тот, кто первым совершит шесть столкновений с противником.

    Интерфейс игры Blockade-змейка в 1976
    Так выглядел интерфейс первой «Змейки». Источник

    После этого разработчики начали выпускать свои версии «Змеек» и сформировали отдельный жанр игр, в котором змея передвигается по полю и собирает объекты. За более чем 50 лет на свет вышли «Змейки» с разными правилами и режимами игры. В одних версиях направление змеи меняется каждый раз, когда она собирает объект, в других игроку приходится управлять сразу двумя змейками и следить, чтобы они не соприкасались друг с другом.

    Инструменты

    Разрабатывать игру будем на Python с помощью открытого набора модулей Pygame, который построен на мультимедийной библиотеке Simple DirectMedia Layer (SDL). Pygame содержит в себе все необходимые модули для разработки игр на Python, включая работу с графикой, воспроизведение звука, управление с клавиатуры, взаимодействие с вибрацией и акселерометром. Готовые игры можно собирать под разные платформы, включая мобильный Android. Код Pygame открыт и опубликован на GitHub, поэтому более опытные разработчики могут присоединиться к развитию проекта.

    Из дополнительных инструментов понадобится редактор кода на Python. Чаще всего разработчики выбирают бесплатный редактор Visual Studio Code от Microsoft или полноценную среду разработки Pycharm от JetBrains.

    Visual Studio Code — полностью бесплатный редактор кода, доступный для Windows, macOS и Linux. Специальную версию VS Code можно запускать в браузере. Вначале компания позиционировала редактор в качестве инструмента для веб-разработки. После релиза магазина расширений появилась возможность адаптировать VS Code практически под любые современные технологии. Редактор поддерживает подсветку синтаксиса, запуск кода и отладку. Скачать установочный файл можно на официальном сайте проекта.

    PyCharm — полноценная среда разработки на языке Python. Включает в себя все необходимые инструменты для создания, отладки и тестирования приложений. Возможности среды можно расширять плагинами. Если с помощью VS Code можно писать код на нескольких языках, то в PyCharm есть полноценная поддержка только Python, а для других языков JetBrains выпускает отдельные среды. PyCharm доступна на Windows, macOS и Linux. Пользователи могут выбрать между бесплатным и ограниченным выпуском Community Edition или полноценным Professional с ежемесячной подпиской. Для проекта «Змейки» хватит бесплатной версии.

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

    Сперва надо убедиться, что на компьютере установлен язык программирования Python 3. Для этого в терминале следует ввести команду python3 —version. В случае успеха система выведет номер установленной версии.

    Установка Python 3

    Если в терминале появится ошибка или сообщение о том, что команда python3 не найдена, то Python надо будет установить. Для macOS и Linux это можно сделать с помощью одной команды в том же окне терминала.

    macOS

    На macOS установить Python можно из репозитория Homebrew. Сам Homebrew можно установить по инструкции с официального сайта. После этого в терминале следует ввести команду brew install python3 и дождаться завершения операции. В конце можно еще раз ввести python3 —version и убедиться, что установка прошла успешно.

    Linux

    В Linux установка Python производится с помощью команды sudo apt install python3. Этого хватит для автоматического скачивания актуальной версии.

    Windows

    В Windows язык программирования Python доступен в фирменном магазине приложений Microsoft Store. Для установки надо перейти по ссылке на страницу пакета и нажать кнопку «Получить», а затем — «Установить». Для корректной работы следует перезагрузить компьютер.

    Библиотека Pygame устанавливается из репозитория PyPI с помощью пакетного менеджера Pip. Он загружается вместе с Python, поэтому для установки Pygame достаточно выполнить в терминале команду pip install pygame.

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

    Дизайн

    В больших студиях над играми работает множество отделов: сценаристы, режиссеры, дизайнеры, программисты, художники, тестировщики и другие высококвалифицированные специалисты. Мы разрабатываем проект в одиночку, поэтому задачи целой студии ложатся на наши плечи. Перед тем как начинать писать код, надо определиться с дизайном нашей «Змейки».

    Сейчас есть огромное количество вариантов этой классической игры, но мы повторим тот, который был популярен на заре зарождения жанра. Экраны тогда были монохромными, и разработчики не могли использовать обилие цветов. Мы тоже возьмем ограниченную палитру в зеленых оттенках, которая хорошо знакома по игровой консоли Game Boy от Nintendo. Всего в проекте будем использовать четыре цвета. Их коды в форматах RGB и Hex указаны на изображении.

    Цвета для дизайна «Змейки»

    Правила

    В этом проекте мы разработаем классическую версию «Змейки», поэтому надо сразу обозначить правила игры:

    • игрок управляет змеей, которая собирает объекты на поле;
    • повороты змеи возможны на 90 градусов;
    • при каждом запуске змейка появляется в случайном месте игрового поля;
    • каждый собранный объект увеличивает длину змейки на один блок;
    • столкновение змеи со своим телом или границей игрового поля приводит к проигрышу;
    • игроку надо как можно дольше продержаться и собрать как можно больше объектов.

    Управление реализуем с помощью клавиш WASD. Такая схема управления уже успела стать стандартом в разработке игр, поэтому пользователям не надо будет привыкать к специфическим кнопкам. 

    Разработка

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

    Шаг 1 — создаем новый проект и импортируем библиотеки

    Для начал необходимо создать новый проект в редакторе кода. Будем рассматривать все на примере PyCharm, но все операции в таком же порядке можно проделать и в VS Code. 

    Для начала запускаем среду разработки и выбираем пункт меню File → New Project. В открывшемся меню указываем имя проекта и задаем директорию хранения файлов. В нашем случае проект называется snake, а все файлы хранятся в стандартной папке. Остальные пункты меню можно оставить по умолчанию.

    Создание проекта игры в Python

    В созданном проекте переходим к файлу main.py: если в проекте его нет, то создаем. В самом начале файла импортируем все необходимые для работы библиотеки:

    • Pygame — для доступа к основным модулям Pygame;
    • Randrange — для выбора случайного числа из заданного диапазона.
    # Импортируем библиотеки
    import pygame as pg
    from random import randrange

    Шаг 2 — задаем константы и инициализируем объекты

    Некоторые переменные будут постоянными во всем проекте — константами. К ним будут относиться размер окна в пикселях и частота кадров (frame per second, FPS). Зададим их сразу после импорта библиотек. Важно отметить, что среди разработчиков Python константы принято писать заглавными буквами, а если в названии содержится больше одного слова, то отделять их следует символом нижнего подчеркивания. К примеру, некоторые названия констант могут выглядеть как HEIGHT или MAIN_COLOR.

    В проекте «Змейки» на Python будут следующие константы:

    • WINDOW — размер окна, равный 1000 пикселей;
    • FPS — частота кадров, равная 60 кадрам в секунду.
    # Константы
    WINDOW = 1000
    FPS = 60

    Теперь можно проинициализировать объекты игры. Сперва создадим объект экрана с помощью вызова функции set_mode модуля display. Функция set_mode принимает три аргумента: размер окна, флаги дополнительных параметров и глубину цвета. Последние два аргумента можно опустить и задать позже. В нашем случае создадим окно размером 1000×1000 пикселей. У нас уже есть константа размера окна, поэтому просто умножим ее на два: [WINDOW] * 2. Также сразу же инициализируем объект, который поможет нам задать частоту обновления экрана.

    # Инициализация объектов
    gameScreen = pg.display.set_mode([WINDOW] * 2)
    clock = pg.time.Clock()

    Шаг 3 — создаем окно игры

    Мы сделали все необходимое для того, чтобы нарисовать на экране компьютера окно нашей «Змейки». Перед этим важно отметить, что игры на Pygame работают в рамках бесконечного цикла, который существует до тех пор, пока пользователь его не закроет. В этом цикле находятся уже другие циклы и условия, предназначенные для реализации управления, обновления экрана и отрисовки объектов.

    Создадим такой цикл while True, сразу же в нем установим ограничение частоты кадров, использовав константу FPS:

    # Главный цикл игры
    while True:
        # Частота обновления экрана
        clock.tick(FPS)

    Теперь мы хотим получать события и обрабатывать их. Создадим для этого цикл for. В нем будем отслеживать действия пользователя и реагировать на них. Сразу же пропишем обнаружение закрытия окна с помощью условия if event.type == pg.QUIT — если объект Pygame закрывается, то мы закрываем игровое окно. 

    После этого воспользуемся функцией fill() и закрасим ранее созданный экран самым светлым цветом из палитры. Это позволит поверх разместить более темную змейку и объекты, которые она будет собирать. Цвет укажем в RGB-формате. В конце добавим функцию обновления экрана flip().

    # Цикл обработки событий
        for event in pg.event.get():
            if event.type == pg.QUIT:
                exit()
            gameScreen.fill((155, 188, 15))
            pg.display.flip()

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

    Окно для игры «Змейка» на Python

    Шаг 4 — создаем змейку

    Наша змейка должна как-то передвигаться по игровому полю, для этого ей понадобятся координаты. В коде уже есть константа WINDOWS, обозначающая размер одной стороны окна; значит теперь мы сможем задать константу TILE_SIZE для размера стороны одной плитки сетки и после задать сразу всю сетку. Далее с помощью кортежа поместим в константу RANGE разметку всего поля. Так мы сможем задавать змейке координаты для передвижения и спауна объектов.

    Координаты и размеры шага для игры «Змейка» на Python
    TILE_SIZE = 50
    RANGE = (TILE_SIZE // 2, WINDOW - TILE_SIZE // 2, TILE_SIZE)

    Теперь создадим функцию, которая определяет координаты случайной плитки на игровом поле. Вспомним из школы, что координаты на плоскости задаются с помощью двух значений — по оси X и Y. Поэтому наша функция должна находить два таких значения, основываясь на данных о разметке поля.

    Обозначим лямбда-функцию get_random_position() и с помощью константы RANGE получим координаты X и Y. Префиксная запись символа звездочки (*) перед RANGE означает, что мы хотим передать в функцию randrange() все элементы кортежа. Мы не знаем, сколько их там хранится, можем заранее посчитать и сохранить количество в отдельную переменную, а можем просто воспользоваться префиксной записью перед константой и доверить это дело Python.

    # Функция для определения координат (X:Y) случайной позиции на игровом поле
    get_random_position = lambda: [randrange(*RANGE), randrange(*RANGE)]

    Убедимся, что get_random_position() каждый раз дает нам случайные координаты. Вызовем функцию и посмотрим на вывод:

    > [825, 175]
    > [925, 925]
    > [725, 825]
    > [25, 175]
    > [325, 625]

    Теперь у нас есть все необходимое для того, чтобы задать параметры змейки и нарисовать ее на экране. Для начала создадим переменную snake, в которой определим голову змеи с помощью экземпляра класса Rect(), который в Pygame отвечает за обозначение прямоугольных областей. В качестве параметров в конструктор класса следует передать координаты X и Y, высоту и ширину. Сразу после зададим случайную позицию головы змеи на сетке игрового поля с помощью функции get_random_position().

    Теперь нам надо создать переменные для хранения длины змеи и всех ее сегментов. Для этого создадим переменную length со значением 1 и список segments, в который поместим первый сегмент.

    # Параметры змейки
    snake = pg.rect.Rect([0, 0, TILE_SIZE - 2, TILE_SIZE - 2])
    snake.center = get_random_position()
    length = 1
    segments = [snake.copy()]

    Перейдем в цикл обработки событий и отобразим змейку на экране. В качестве цвета возьмем второй зеленый оттенок из определенной ранее палитры. Зададим его в RGB-формате.

    [pg.draw.rect(gameScreen, (120, 149, 12), segment) for segment in segments]

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

    Варианты появления змейки в случайном месте на игровом поле

    Шаг 5 — управляем змейкой

    Для управления змейкой реализуем классическую для игр схему WASD. Такая раскладка для перемещения персонажем успела стать стандартной, поэтому пользователю будет привычно играть в нашу «Змейку». Клавиши WASD обозначают:

    • W — движение вперед;
    • A — движение влево;
    • S — движение назад;
    • D — движение вправо.

    Для начала перейдем к части кода, в которой до этого задавали параметры змейки, и добавим новую переменную snake_dir. В ней будем хранить координаты головы змеи. Зададим значение (0, 0).

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

    # Обработка нажатий WASD
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_w:
                    snake_dir = (0, -TILE_SIZE)
                if event.key == pg.K_s:
                    snake_dir = (0, TILE_SIZE)
                if event.key == pg.K_a:
                    snake_dir = (-TILE_SIZE, 0)
                if event.key == pg.K_d:
                    snake_dir = (TILE_SIZE, 0)

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

    # Управляем змейкой
            snake.move_ip(snake_dir)
            segments.append(snake.copy())
            segments = segments[-length:]

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

    Также можно заметить, что змейка передвигается по игровому полю слишком быстро. Исправим это, добавив код для контроля скорости. Сперва перейдем в раздел параметров переменной и создадим переменные времени и задержки между шагами змейки:

    time = 0
    time_step = 110

    После этого модифицируем часть кода с управлением:

    # Управляем змейкой
            time_now = pg.time.get_ticks()
            if time_now - time > time_step:
                time = time_now
                snake.move_ip(snake_dir)
                segments.append(snake.copy())
                segments = segments[-length:]

    Шаг 6 — добавляем еду для змейки

    У нас уже есть змейка, и мы даже можем ей управлять. Теперь на игровом поле должны появляться объекты еды, которые змейка будет собирать и увеличиваться. Сам объект еды идентичен по размерам с головой змеи и также появляется в случайном месте экрана. Поэтому создадим переменную food с копией головы змеи и назначим ей случайную точку для появления с помощью функции get_random_position():

    # Параметры объектов еды
    food = snake.copy()
    food.center = get_random_position()

    Отобразим еду на экране так же, как это делали со змеей. В качестве цвета возьмем самый темный из обозначенной палитры:

    # Рисуем объект еды
    pg.draw.rect(gameScreen, (15, 56, 15), food)

    При запуске кода хорошо видно, что голова змеи и еда всегда появляются в случайных местах на игровом поле:

    Варианты появления еды для змейки на игровом поле

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

    # Поедание
    if snake.center == food.center:
      food.center = get_random_position()
      length += 1

    Шаг 7 — определяем столкновения

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

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

    # Столкновение с границами
            if snake.left < 0 or snake.right > WINDOW or snake.top < 0 or snake.bottom > WINDOW:
                snake.center, food.center = get_random_position(), get_random_position()
                length, snake_dir = 1, (0, 0)
                segments = [snake.copy()]

    Также змейка может столкнуться со своим телом. В этом случае игра тоже должна завершиться. Для этого создадим переменную snake_collision, в которой будем определять, пересекается ли хоть один прямоугольник тела змеи с ее головой. Воспользуемся готовой функцией collidelist() класса Rect из Pygame. А после добавим переменную в условие проверки столкновения с границами:

    # Столкновение с границами и телом змейки
            snake_collision = pg.Rect.collidelist(snake, segments[:-1]) != -1
            if snake.left < 0 or snake.right > WINDOW or snake.top < 0 or snake.bottom > WINDOW or snake_collision:
                snake.center, food.center = get_random_position(), get_random_position()
                length, snake_dir = 1, (0, 0)
                segments = [snake.copy()]

    В итоге у нас получилась классическая игра «Змейка» на Python и Pygame. Мы научились рисовать объекты на экране, менять их параметры, управлять ими с помощью клавиатуры и обрабатывать события в игровом цикле.

    Весь код игры с комментариями занимает всего 78 строк:

    # Импортируем библиотеки
    import pygame as pg
    from random import randrange
    
    # Константы
    WINDOW = 1000
    FPS = 60
    TILE_SIZE = 50
    RANGE = (TILE_SIZE // 2, WINDOW - TILE_SIZE // 2, TILE_SIZE)
    
    # Функция для определения координат (X:Y) случайной позиции на игровом поле
    get_random_position = lambda: [randrange(*RANGE), randrange(*RANGE)]
    
    # Параметры змейки
    snake = pg.rect.Rect([0, 0, TILE_SIZE - 2, TILE_SIZE - 2])
    snake.center = get_random_position()
    length = 1
    segments = [snake.copy()]
    snake_dir = (0, 0)
    
    # Параметры времени и задержки
    time = 0
    time_step = 110
    
    # Параметры объектов еды
    food = snake.copy()
    food.center = get_random_position()
    
    # Инициализация объектов
    gameScreen = pg.display.set_mode([WINDOW] * 2)
    clock = pg.time.Clock()
    
    # Главный цикл игры
    while True:
      # Частота обновления экрана
      clock.tick(FPS)
    
      # Цикл обработки событий
      for event in pg.event.get():
          if event.type == pg.QUIT:
              exit()
          # Обработка нажатий WASD
          if event.type == pg.KEYDOWN:
              if event.key == pg.K_w:
                  snake_dir = (0, -TILE_SIZE)
              if event.key == pg.K_s:
                  snake_dir = (0, TILE_SIZE)
              if event.key == pg.K_a:
                  snake_dir = (-TILE_SIZE, 0)
              if event.key == pg.K_d:
                  snake_dir = (TILE_SIZE, 0)
    
          gameScreen.fill((155, 188, 15))
    
          # Столкновение с границами и телом змейки
          snake_collision = pg.Rect.collidelist(snake, segments[:-1]) != -1
          if snake.left < 0 or snake.right > WINDOW or snake.top < 0 or snake.bottom > WINDOW or snake_collision:
              snake.center, food.center = get_random_position(), get_random_position()
              length, snake_dir = 1, (0, 0)
              segments = [snake.copy()]
          # Поедание
          if snake.center == food.center:
              food.center = get_random_position()
              length += 1
          # Рисуем объект еды
          pg.draw.rect(gameScreen, (15, 56, 15), food)
          # Рисуем змейку
          [pg.draw.rect(gameScreen, (120, 149, 12), segment) for segment in segments]
    
          # Управляем змейкой
          time_now = pg.time.get_ticks()
          if time_now - time > time_step:
              time = time_now
              snake.move_ip(snake_dir)
              segments.append(snake.copy())
              segments = segments[-length:]
    
          pg.display.flip()

    Что дальше

    Игру «Змейка» на Python можно продолжать улучшать и модифицировать. К примеру, в проект можно добавить следующее:

    • В игре не хватает главного меню, меню проигрыша и отображения счета. Все это можно добавить с помощью модуля pygame.font, предназначенного для работы с текстом и шрифтами. Содержимое переменной length, в которой храним длину змейки, можно выводить в углу игрового поля и обнулять при проигрыше.
    • Наша «Змейка» получилась безмолвной, и ее надо оживить звуками. Сделать это можно с помощью модуля pygame.mixer, добавив фоновую музыку, звуковые эффекты при поворотах, поедании объектов и столкновении. Так игра будет более живой и увлекательной.
    • В старых играх, а особенно в аркадных автоматах, была возможность сохранять лучшие результаты, чтобы всегда можно было понять, кого из игроков можно считать абсолютным чемпионом. В нашу «Змейку» тоже можно добавить таблицу рекордов. Для этого надо разобраться с принципами хранения данных и сортировки. К примеру, в меню можно добавить отдельное всплывающее окно с пятью лучшими результатами и имена игроков.
    • Обычная змейка довольно быстро надоедает, поэтому можно добавить несколько новых режимов. К примеру, змейка может менять направление движения каждый раз, когда съедает блок еды. А еще ей можно увеличивать скорость или добавить жизни, дающие право на ошибку.
    • Одному играть тоже скучно, поэтому можно сделать игровое поле больше и добавить на него сразу двух змеек. Управление первой настроить на клавиши WASD, а второй — на стрелки. Тогда за одним компьютером в игру смогут играть сразу два пользователя. Только важно сделать змеек разных цветов, иначе игроки будут путаться.

    Инструкция

    Поделиться

    Скопировано
    1 комментарий
    Комментарии
    • Роман

      Что это за функция move_ip для движения? Откуда она взялась? Здесь самое сложное - это передвигать звенья, и эта тайна скрыта именно в этой функции, которая упомянута, но не определена... А так очень хороший туториал, спасибо