Как сделать паузу в игре pygame

Добавил пользователь Валентин П.
Обновлено: 19.09.2024

Может ли кто-нибудь дать мне ссылку на ресурсы, где я мог бы узнать pygame.

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

3 ответа

Я использую Raspberry Pi 3 для управления роботизированным транспортным средством. Я успешно подключил свой контроллер PS4 к RPi с помощью ds4drv . У меня есть следующий код, работающий и выводящий Button Pressed/Button Released при нажатии/отпускании кнопки на контроллере PS4 с помощью pygame .

Бесплатные электронные книги (PDF)

Пауза сделайте более или менее так:

EDIT:

У вас нет кода в классах, поэтому вы должны использовать PAUSED без self.

Рабочий код с приостановленным экраном и клавиатурой и с текстом "PAUSED"

EDIT:

Версия (более или менее) с классами

По какой-то причине пауза больше не работает в Xcode, когда я отлаживаю модульные тесты Objective-C++ для своего проекта. Кнопка выглядит активной, но ничего не происходит, когда я нажимаю на нее. Кто-нибудь сталкивался с подобной проблемой раньше? Xcode 8.2.1, macOS Сьерра-10.12.3

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

это довольно упрощенная версия.

Учебник по шимпанзе по умолчанию-довольно хорошее место для начала. В частности, вы должны посмотреть на их использование pygame.time.Clock.tick для ограничения частоты кадров.

Как только у вас есть игровой цикл, самый простой способ приостановить его-использовать "event.wait()", который останавливается и ждет, пока не произойдет событие. Вы просто используете это, чтобы дождаться, пока не будет нажата отмена паузы, и продолжить цикл событий.

Похожие вопросы:

Я пытаюсь проверить, двигалась ли мышь, когда левая кнопка мыши была опущена, а затем вернуть направление. Я попытался проверить положение мыши два раза в цикле 'while True', но это не сработало.

Я только недавно изучил библиотеку Python и Pygame. Я заметил, что рендеринг и основной цикл автоматически приостанавливаются, когда я нажимаю и удерживаю строку меню окна (панель с title/icon).

У меня проблема с pygame. Я настроил окно, которое случайным образом размещает круги по экрану очень быстро, просто для целей тестирования. Есть также три кнопки: воспроизведение/пауза.

Я использую Raspberry Pi 3 для управления роботизированным транспортным средством. Я успешно подключил свой контроллер PS4 к RPi с помощью ds4drv . У меня есть следующий код, работающий и выводящий.

По какой-то причине пауза больше не работает в Xcode, когда я отлаживаю модульные тесты Objective-C++ для своего проекта. Кнопка выглядит активной, но ничего не происходит, когда я нажимаю на нее.

Я пытался получить свой код, собирая, какая кнопка мыши нажата и ее положение, но всякий раз, когда я запускаю приведенный ниже код, окно pygame замерзает, а код shell/продолжает выводить начальное.

Итак, я создаю проект rpg в Pygame, и мне нужен класс кнопок с текстом. Пока что это мой код. Я попытался использовать некоторые примеры кода в интернете и на этом сайте, но не смог заставить их.

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

Вот основные функции, которые реализует код шаблона игровой программы :

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

window templ

Основное графическое окно игры

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

Основная поверхность

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

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

Объект, присвоенный переменной screen , называется поверхностью ( surface ). Метод display . set_mode всегда возвращает основную поверхность - это основное графическое окно программы. При каждом проходе игрового цикла происходит обновление основного графического окна программы.

В методе display.set_mode((600, 400)) первый параметр 600 - ширина, второй 400 – высота окна в пикселях. Двойные круглые скобки обязательны, поскольку метод set_mode() принимает значения не как два отдельных параметра, а как связанные значения в качестве параметра - кортеж.

Игровой цикл

Игры так устроены, что большая часть действий циклически потеряется: выполняется действие в игре, которое приводит к изменению состояния игры и, которое в свою очередь формирует новую стратегию поведения игрока. Далее все повторяется: действие, состояние, стратегия. Это и есть игровой цикл - базовое понятие в теории игр, на котором строится структура и логика игры.

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

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

Игровой цикл событий записывается с помощью оператора while. Он должен работать все время, пока пользователь играет в игру и может быть записан следующим образом:

Контроль скорости игры

Таким образом, команда clock.tick(FPS) выполняет автоматический контроль заданной частоты кадров.

Программная реализация контроля частоты кадров может быть записана следующим образом:

Обработка событий

Событие (англ. Event) – это один из объектов pygame. Все события в PyGame при их появлении добавляются в очередь событий. Каждый элемент в этой очереди является Event объектом. Для получения доступа к событиям используется метод pygame.event.get(), который возвращает список событий, произошедших с момента последнего вызова этого метода. Просматривая список событий, мы может обработать выход из программы

С помощью цикла for проходим по списку. Каждое возникающее событие последовательно извлекается из цепочки событий, и проверяется, является ли оно событием pygame.QUIT. Если есть событие QUIT в очереди событий, то выйдем из игрового цикла

Добавим код закрытия окна в наш

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

window 1

Обновление основной поверхности

Метод pygame.display.flip() обновляет содержимое основного окна игры. При обновлении используется механизм двойной буферизации. Экранная картинка сначала формируется в памяти компьютера, где она невидима, а затем методом display.flip () переносится на экран. В результате изменения появляются не постепенно, а сразу, что позволяет избежать возникновения на экране изображений нарисованных лишь наполовину и уменьшить мерцания экрана.

Аналогом метода pygame.display.flip() является метод update(), имеющий тоже назначение.

Здесь rectangle – это прямоугольная область, которую требуется перерисовать. По умолчанию, если параметр rectangle не указан

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

Примечание.

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

Выполним обновление содержимого основного игрового окна

Surface

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

Объект, присвоенный переменной screen , называется поверхностью ( surface ). Метод display . set _ mode всегда возвращает основную поверхность - это основное графическое окно программы. При каждом проходе игрового цикла происходит обновление основного графического окна программы

Функция Surface()

Эта функция pygame. Surface() используется для создания объекта surface - это дополнительная поверхность для размещения на ней изображений. Она принимает в качестве параметра кортеж с двумя значениями (ширина, высота) поверхности

Этот код создаст пустое изображение размером 100 x 100 пикселей. Цвет по умолчанию будет черным.

Функция fill()

Функция принимает объект color – цвет заливки поверхности, это кортеж RGB, например, BLUE = (0, 0, 255)

Поверхности можно делать прозрачными с помощью их метода set_alpha(). Аргумент меняется от 0 (полная прозрачность) до 255 (полная непрозрачность).

Функция blit()

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

В этом примере функция blit() отображает содержимое дополнительной поверхности mySurface на поверхности screen.

Метод pygame.display.flip()

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

Метод pygame.display.update()

Механизм двойной буферизации

Метод pygame.display.flip() обновляет содержимое основного окна игры. При обновлении используется механизм двойной буферизации. Экранная картинка сначала формируется в памяти компьютера, где она невидима, а затем методом display.flip() переносится на экран. В результате изменения появляются не постепенно, а сразу, что позволяет избежать возникновения на экране изображений нарисованных лишь наполовину и уменьшить мерцания экрана.

Класс Draw

Класс Draw имеет 9 методов рисования геометрических фигур, которые имеют следующие общие параметры:

Рисование прямоугольника:

Рисование круга:

Рисование треугольника/многоугольника:

Рисование линий

1. Рисование линии между точками start=(x,y) и end=(x1,y1)

2. Рисование тонкой сглаженной линии между точками start=(x,y) и end=(x1,y1),blend– коэффициент сглаживания линии

3. Рисование ломаной линии, pointlist = ((x1,y1),(x2,y2),(x3,y4)) – координаты точек связанных отрезков, сlosed = (True или False) указывает замыкать ли крайние точки.

Рисование эллипсов:

Рисование дуги:

Движение круга

Алгоритм движения можно записать следующим образом.

В игровом цикле:

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

здесь x += 1 и у += 1 означает, что координаты круга изменяются на 1 пиксель на каждом игровом цикле.

  • нарисовать круг в памяти компьютера в новых координатах

pygame.draw.circle(screen, blue, (x, y), r)

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

Отталкивание круга от границ окна

В PyGame используется э кранная система координат – это координатная система, заданная на экранной плоскости. Две ее оси параллельны сторонам экрана, ось OX направлена слева на право, OY – снизу вверх.

XOY

Запишем условия не выхода круга за границы игрового экрана. Введем переменные для скорости перемещения круга: dx, dy – количество пикселей, на которое смещается центр круга по оси x и оси y за один кадр

В этом случае код контроля движения круга внутри игрового окна можно записать следующим образом:

if y + r > H or y-r
dy = dy * -1
if x + r > W or x-r
dx = dx * -1

Полный листинг программы

Способы обработки событий клавиатуры и мыши

Есть два основных способа работы с клавиатурой, мышью.

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

Если вызывать метод pygame.event.get() в игровом цикле, то мы получим список событий для каждого кадра. Каждый элемент списка это объект типа Event, который имеет свойство type . Способ обработки этих событий зависит от типа самого события. Тип события можно проверить, прочитав поле event.type .

События клавиатуры могут иметь два типа

  • event.type == pygame.KEYDOWN – клавиша нажата;
  • event.type == pygame.KEYUP – клавиша отпущена.

Если вы нажали клавишу и отпустили, то в очередь событий будут записаны оба.

События мыши могут иметь четыре типа

  • event.type == pygame.MOUSEBUTTONDOWN – кнопка мыши нажата
  • event.type == pygame.MOUSEBUTTONUP – кнопка мыши отпущена
  • event.type == pygame.MOUSEMOTION –курсора мыши перемещается
  • event.type == pygame.MOUSEWHEEL – кручение колесика мыши.

Данный способ основан на работе с модулем клавиатуры и модулем мыши

Ознакомится с модулями можно здесь:

События клавиатуры

В качестве примера рассмотрим фрагмент программы, в котором при нажатии на курсорные клавиши будет перемещаться прямоугольник на экране

С помощью цикла for проходим по списку

Каждое возникающее событие последовательно извлекаем из цепочки событий, и сравниваем с типом события pygame.KEYDOWN , если тип события равен pygame.KEYDOWN , то у этого типа есть атрибут event.key . Теперь сравниваем этот атрибут со значениями курсорных клавиш K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN. Если получили совпадение с одной из клавиш, то задаем смещение прямоугольника с помощью переменных dx или dy .

Далее определяем новые координаты для рисования прямоугольника

и рисуем прямоугольник в блоке формирования кадра

Обработка событий клавиатуры помощью с модуля клавиатуры pygame.key

Проверить состояние клавиш можно с помощью функции

которая возвращает кортеж двоичных значений. Индекс каждого значения соответствует своей клавиатурной константе. Само значение равно 1, если клавиша нажата, и 0 – если не нажата.

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

Это четвёртая из пяти частей туториала, посвящённого созданию игр с помощью Python 3 и Pygame. В третьей части мы углубились в сердце Breakout и узнали, как обрабатывать события, познакомились с основным классом Breakout и увидели, как перемещать разные игровые объекты.

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

Распознавание коллизий

В играх объекты сталкиваются друг с другом, и Breakout не является исключением. В основном с объектами сталкивается мяч. В методе handle_ball_collisions() есть встроенная функция под названием intersect() , которая используется для проверки того, ударился ли мяч об объект, и того, где он столкнулся с объектом.Она возвращает 'left', 'right', 'top', 'bottom' или None, если мяч не столкнулся с объектом.

Столкновение мяча с ракеткой

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

Но если он ударяется о боковую часть ракетки, то отскакивает в противоположную сторону (влево или вправо) и продолжает движение вниз, пока не столкнётся с полом. В коде используется функция intersect().

Столкновение с полом

Когда ракетка пропускает мяч на пути вниз (или мяч ударяется об ракетку сбоку), то мяч продолжает падать и затем ударяется об пол. В этот момент игрок теряет жизнь и мяч создаётся заново, чтобы игра могла продолжаться. Игра завершается, когда у игрока заканчиваются жизни.

Столкновение с потолком и стенами

Когда мяч ударяется об стены или потолок, он просто отскакивает от них.

Столкновение с кирпичами

Когда мяч ударяется об кирпич, это является основным событием игры Breakout — кирпич исчезает, игрок получает очко, мяч отражается назад и происходят ещё несколько событий (звуковой эффект, а иногда и спецэффект), которые я рассмотрю позже.

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

Программирование игрового меню

В большинстве игр есть какой-нибудь UI. В Breakout есть простое меню с двумя кнопками, 'PLAY' и 'QUIT'. Меню отображается в начале игры и пропадает, когда игрок нажимает на 'PLAY'. Давайте посмотрим, как реализуются кнопки и меню, а также как они интегрируются в игру.

Создание кнопок

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

Кнопка реализуется как прямоугольник с фоновым цветом и текст, отображаемый поверх него. Также кнопка получает функцию on_click (по умолчанию являющуюся пустой лямбда-функцией), которая вызывается при нажатии кнопки.

Кнопка обрабатывает собственные события мыши и изменяет своё внутреннее состояние на основании этих событий. Когда кнопка находится в нажатом состоянии и получает событие MOUSEBUTTONUP , это означает, что игрок нажал на кнопку, и вызывается функция on_click() .

Свойство back_color , используемое для отрисовки фонового прямоугольника, всегда возвращает цвет, соответствующий текущему состоянию кнопки, чтобы игроку было ясно, что кнопка активна:

Создание меню

Функция create_menu() создаёт меню с двумя кнопками с текстом 'PLAY' и 'QUIT'. Она имеет две встроенные функции, on_play() и on_quit() , которые она передаёт соответствующей кнопке. Каждая кнопка добавляется в список objects (для отрисовки), а также в поле menu_buttons .

При нажатии кнопки PLAY вызывается функция on_play(), удаляющая кнопки из списка objects , чтобы они больше не отрисовывались. Кроме того, значения булевых полей, которые запускают начало игры — is_game_running и start_level — становятся равными True.

При нажатии кнопки QUIT is_game_running принимает значение False (фактически ставя игру на паузу), а game_over присваивается значение True, что приводит к срабатыванию последовательности завершения игры.

Отображение и сокрытие игрового меню

Отображение и сокрытие меню выполняются неявным образом. Когда кнопки находятся в списке objects , меню видимо; когда они удаляются, оно скрывается. Всё очень просто.

Можно создать встроенное меню с собственной поверхностью, которое рендерит свои подкомпоненты (кнопки и другие объекты), а затем просто добавлять/удалять эти компоненты меню, но для такого простого меню это не требуется.

Подводим итог

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

В последней части серии мы рассмотрим завершение игры, отслеживание очков и жизней, звуковые эффекты и музыку.

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

В настоящее время я создаю игру, в которой событие происходит каждые 800 миллисекунд в pygame, используя следующий код:

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

Однако проблема возникает, когда игра ставится на паузу. В том же цикле while для основной игровой логики есть отдельный цикл while меньшего размера, который запускается, если игра приостановлена.

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

Как я могу предотвратить это, чтобы время оставалось прежним? Мне нужно изменить способ приостановки игры?

Как вы делаете паузу?

@DrevanTonder Как я уже сказал, с циклом while внутри основного цикла while. Если нажать кнопку паузы, цикл while будет выполняться, пока проигрыватель не возобновит работу.

Используйте счетчик. Просто переменная с целым числом, которое начинается с 0 и увеличивает его только тогда, когда игра не приостановлена. Используйте это как источник истины, а не напрямую API, основанный на времени. Как только счетчик вырастет до .8 * your_frame_rate , сбросьте его на 0 и создайте врага.

Можете ли вы подтвердить, что время появления врага сброшено? Думаю, это поможет мне сформулировать ответ.

@Ethanol. Время основано на событии, которое происходит каждые 800 мс в системе событий. Расстояние между каждым спрайтом и, следовательно, время между каждым событием остается постоянным до момента приостановки. При возобновлении после паузы расстояние между спрайтами и, следовательно, время больше, чем обычно для первого созданного спрайта. Затем он возвращается в нормальное состояние. Это может быть тот факт, что событие все еще происходит, даже когда оно приостановлено, поэтому, если вы сделаете паузу непосредственно перед событием, а затем возобновите сразу после события, действующее время будет добавлено для создания эффекта. Хотя это всего лишь моя теория

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

Читайте также: