Как сделать таймер в pygame

Обновлено: 03.07.2024

Я начал использовать pygame, и я хочу сделать простую игру. Одним из элементов, которые мне нужны, является таймер обратного отсчета. Как я могу сделать время обратного отсчета (например, 10 секунд) в PyGame?

3 Решение DanteVoronoi [2015-06-09 02:32:00]

3 sloth [2015-06-09 13:01:00]

Еще один простой способ - просто использовать систему событий pygame.

Вот простой пример:

1 skrx [2017-05-18 00:31:00]

pygame.time.Clock.tick возвращает время в миллисекундах со времени последнего вызова clock.tick (delta time, dt ), поэтому вы можете использовать его для увеличения или уменьшения переменной таймера.

0 John [2015-06-09 02:35:00]

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

В основном это переменная, которую 1 вычитается из каждого цикла. Затем мы используем time.sleep(1), чтобы подождать одну секунду.

Это на самом деле довольно просто. Спасибо Pygame за создание простой библиотеки!

TIMER_RESOLUTION constant. --> Время в pygame представлено в миллисекундах (1/1000 секунды). Большинство платформ имеют ограниченное временное разрешение около 10 миллисекунд. Это разрешение в миллисекундах указано в константе TIMER_RESOLUTION .

pygame.init() was called. Before pygame is initialized this will always be 0. --> Вернуть количество миллисекунд с момента pygame.init() . Перед инициализацией pygame всегда будет 0.

pygame.time.delay() function. --> Будет приостановлено на заданное количество миллисекунд. Эта функция отключает процесс, чтобы разделить процессор с другими программами. Программа, ожидающая даже несколько миллисекунд, потребляет очень мало процессорного времени. Он немного менее точен, чем pygame.time.delay() .

Это возвращает фактическое количество использованных миллисекунд.

pygame.time.wait() . --> Будет приостановлено на заданное количество миллисекунд. Эта функция будет использовать процессор (а не спать), чтобы сделать задержку более точной, чем pygame.time.wait() .

Это возвращает фактическое количество использованных миллисекунд.

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

Чтобы отключить таймер события,установите аргумент миллисекунд на 0.

Если один раз аргумент равен True,то отправьте таймер только один раз.

Новое в пигаме 2.0.0.dev3:после добавления аргумента.

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

Этот метод следует вызывать один раз на кадр.Он вычислит,сколько миллисекунд прошло с момента предыдущего вызова.

Clock.tick(40) once per frame, the program will never run at more than 40 frames per second. --> Если вы передадите необязательный аргумент частоты кадров, функция будет задерживать, чтобы игра продолжалась медленнее, чем заданное количество тиков в секунду. Это может использоваться для ограничения скорости выполнения игры. Позвонив Clock.tick(40) один раз за кадр, программа никогда не будет работать на более чем 40 кадров в секунду.

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

Этот метод следует вызывать один раз на кадр.Он вычислит,сколько миллисекунд прошло с момента предыдущего вызова.


Методы работы с Rect

pygame.Rect.copy Возвращает новый прямоугольник, имеющий ту же позицию и размер, что и оригинал.
pygame.Rect.move Возвращает новый прямоугольник, перемещаемый данным смещением. Аргументы x и y могут быть любым целочисленным значением, положительным или отрицательным.
pygame.Rect.move_ip То же, что и метод Rect.move (), но работает на месте.
pygame.Rect.inflate увеличивать или уменьшать размер прямоугольника, на месте
pygame.Rect.inflate_ip увеличивать или уменьшать размер прямоугольника, на месте
pygame.Rect.clamp перемещает прямоугольник внутри другого
pygame.Rect.clamp_ip перемещает прямоугольник внутри другого, на месте
pygame.Rect.clip обрезает прямоугольник внутри другого
pygame.Rect.union соединяет два прямоугольника в один
pygame.Rect.union_ip соединяет два прямоугольника в один, на месте
pygame.Rect.unionall объединение многих прямоугольников
pygame.Rect.unionall_ip объединение многих прямоугольников, на месте
pygame.Rect.fit изменить размер и переместить прямоугольник учмиывая соотношение сторон
pygame.Rect.normalize корректировать отрицательные размеры
pygame.Rect.contains проверить, находится ли один прямоугольник внутри другого
pygame.Rect.collidepoint проверить, находится ли точка внутри прямоугольника
pygame.Rect.colliderect тест, пересекаются ли два прямоугольника
pygame.Rect.collidelist проверить, пересекается ли хоть один прямоугольник в списке
pygame.Rect.collidelistall пересекаются ли все прямоугольники в списке
pygame.Rect.collidedict проверить, если один прямоугольник в словаре пересекается
pygame.Rect.collidedictall пересекаются ли все прямоугольники в словаре

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

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

Функция get в модуле pygame.event возвращает последнее событие, ожидающее в очереди и удаляет его из очереди.

Объект event

Модуль pygame.event для обработки очереди событий

pygame.event.pump Если вы не используете другие функции событий в своей игре, вы должны вызвать pygame.event.pump (), чтобы позволить pygame обрабатывать внутренние действия
pygame.event.get получает события из очереди
pygame.event.poll получить одно событие из очереди
pygame.event.wait ждёт одиночного события из очереди
pygame.event.peek проверить, ждут ли очереди события определённого типа
pygame.event.clear удалить все события из очереди
pygame.event.event_name возвращает имя для типа события. Строка находится в стиле WordCap
pygame.event.set_blocked проверяет, какие события не разрешены в очереди
pygame.event.set_allowed проверяет, какие события разрешены в очереди
pygame.event.get_blocked проверить, заблокирован ли тип события из очереди
pygame.event.set_grab проверяет совместное использование устройств ввода с другими приложениями
pygame.event.get_grab проверить, работает ли программа на устройствах ввода данных
pygame.event.post поместить новое событие в очередь
pygame.event.Event создать новый объект события
pygame.event.EventType Объект Python, представляющий событие SDL. Экземпляры пользовательских событий создаются с вызовом функции Event. Тип EventType не может быть напрямую вызван. Экземпляры EventType поддерживают назначение и удаление атрибутов.

Существует множество способов доступа к очереди событий. Просто проверять существование событий, захватывать их непосредственно из стека.

Модуль pygame.mouse для работы с мышью

pygame.mouse.get_pressed получить состояние кнопок мыши
pygame.mouse.get_pos получить позицию курсора мыши
pygame.mouse.get_rel получить количество движений мыши
pygame.mouse.set_pos установить позицию курсора мыши
pygame.mouse.set_visible скрыть или показать курсор мыши
pygame.mouse.get_focused проверяет, принимает ли дисплей ввод мыши
pygame.mouse.set_cursor установить изображение для курсора мыши
pygame.mouse.get_cursor получить изображение для курсора мыши

Функции мыши можно использовать для получения текущего состояния устройства мышь. Эти функции также могут изменять курсор мыши.

Когда режим отображения (display) установлен, очередь событий начнет принимать события мыши. Кнопки мыши генерируют события pygame.MOUSEBUTTONDOWN и pygame.MOUSEBUTTONUP , когда они нажимаются и отпускаются. Эти события содержат атрибут кнопки, указывающий, какая кнопка была нажата. Колесо мыши будет генерировать pygame.MOUSEBUTTONDOWN и pygame.MOUSEBUTTONUP события при прокрутке.

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

Пример. Нарисовать курсор под текущей позицией мыши.

Определить какая кнопка была нажата на мышке можно используя значение event.button:

Координаты курсора при нажатии кнопки мыши находятся в event.pos .

Пример. Перемещать картинку курсором мыши.

Клавиатура

Модуль pygame.key

Этот модуль содержит функции для работы с клавиатурой.Очередь событий получает события pygame.KEYDOWN и pygame.KEYUP при нажатии и отпускании клавиш клавиатуры.

Оба события имеют ключевой атрибут, который представляет собой целочисленный идентификатор, представляющий каждую клавишу на клавиатуре.Событие pygame.KEYDOWN имеет дополнительные атрибуты: unicode и scancode. unicode представляет собой одну символьную строку, которая соответствует введённому символу. Scancode представляет собой код для конкретной платформы.

Получить код клавиши:


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

Направленное движение с помощью клавиш

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

Создать картинку, например:

Проверить очередь событий:

Проверить, является ли полученное событие нажатием на клавиши со стрелками:

Если — да, то получмить код нажатой клавиши и сформировать новые координаты для картинки:

И нарисовать картинку в новом месте:

Объект Surface

pygame.Surface — объект pygame для представления изображений


Наложение поверхностей, прозрачность.

Управление временем

Модуль pygame.time содержит объект Clock, который можно использовать для отслеживания
времени. Чтобы создать объект типа: время, вызывается конструктор pygame.time.Clock:
clock = pygame.time.Clock()

Когда создан объект clock, можно вызвать его функцию tick один раз за кадр,
которая возвращает время, прошедшее со времени предыдущего вызова в миллисекундах:
time_passed = clock.tick ()

Функция tick может использовать необязательный параметр для установления максимальной частоты кадров. Этот параметр нужен, если игра запущена на рабочем компьютере и необходимо контролировать, чтобы она не использовала всю его вычислительная мощность на 100%:

time_passed = clock.tick (30)

Звуки

Для управления звуком используется модуль pygame.mixer . Он отвечает за любые действия со звуками.

Загружаем звуковой файл в формате *.wav

sound = pygame.mixer.Sound("sound.wav")
(загружаем до игрового цикла, т.к. это очень долгая операция)

Столкновения (collisions)

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

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

Эти команды (импорт модуля, вызовы функций, цикл) создают своего рода скелет, или каркас, программного кода. Выполнив его, вы получите "пустую" игру. Далее на этот скелет "подвешивается мясо", т. е. объявляются объекты и программируется логика игры.

Первое, что нужно сделать, это импортировать модуль pygame. После этого можно вывести на экран главное графическое окно игры с помощью функции set_mode() модуля display, входящего в состав библиотеки pygame:

Если выполнить этот код, то появится окно размером 600x400 пикселей и сразу закроется (в Linux, в Windows может зависнуть).

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

Флаги предназначены для переключения на аппаратное ускорение, полноэкранный режим, отключения рамки окна и др. Например, команда pygame. display . set_mode ( ( 640 , 560 ) , pygame. RESIZABLE ) делает окно изменяемым в размерах.

Выражение вида pygame.RESIZABLE (вместо RESIZABLE может быть любое другое слово большими буквами) обозначает обращение к той или иной константе, определенной в модуле pygame. Часто можно встретить код, в котором перед константами не пишется имя модуля (вместо, например, pygame.QUIT пишут просто QUIT). В этом случае в начале программы надо импортировать не только pygame, но и содержимое модуля locals через from … import:

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

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

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

Функции update() и flip() модуля display обновляют содержимое окна игры. Это значит, что каждому пикселю заново устанавливается цвет. Представьте, что на зеленом фоне движется красный круг. За один кадр круг смещается на 5 пикселей. От кадра к кадру картинка целого окна изменяется незначительно, но в памяти окно будет перерисовываться полностью. Если частота составляет 60 кадров в секунду (FPS=60), то за секунду в памяти компьютера произойдет 60 обновлений множества значений, соответствующих экранным пикселям, что дает по большей части бессмысленную нагрузку на вычислительные мощности.

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

Функция flip() решает проблему иным способом. Она дает выигрыш, если в set_mod() были переданы определенные флаги (аппаратное ускорение + полноэкранный режим – pygame.HWSERFACE|pygame.FULLSCREEN, двойная буферизация – pygame.DOUBLEBUFF, использование OpenGL – pygame.OPENGL). Возможно, все флаги можно комбинировать вместе (через |). При этом, согласно документации, аппаратное ускорение работает только в полноэкранном режиме.

Вернемся к нашим трем строчкам кода. Почему окно сразу закрывается? Очевидно потому, что программа заканчивается после выполнения этих выражений. Ни init(), ни set_mode() не предполагают входа в "режим циклического ожидания событий". В tkinter для этого используется метод mainloop() экземпляра Tk(). В pygame же требуется собственноручно создать бесконечный цикл, заставляющий программу зависнуть. Основная причина в том, что только программист знает, какая часть его кода должна циклически обрабатываться, а какая – нет. Например, код, создающий классы, объекты и функции не "кладут" в цикл.

Итак, создадим в программе бесконечный цикл:

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

Как сделать так, чтобы программа закрывалась при клике на крестик окна, а также при нажатии Alt+F4? Pygame должен воспринимать такие действия как определенный тип событий.

Добавим в цикл магии:

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

Рассмотрим выражение pygame.event.get(). Модуль event библиотеки pygame содержит функцию get(), которая забирает список событий из очереди, в которую записываются все произошедшие события. То, что возвращает get() – это список. Забранные события удаляются из очереди, то есть второй раз они уже забираться не будут, а в очередь продолжают записываться новые события.

Цикл for просто перебирает схваченный на данный момент (в текущей итерации цикла) список событий. Каждое событие он присваивает переменной i или любой другой. Чтобы было понятней, перепишем программу таким образом:

На экране вы увидите примерно такое:

Вверху будет множество пустых квадратных скобок, которые соответствуют пустым спискам events, создаваемым на каждой итерации цикла while. И только когда окно закрывается, генерируются два события. Свойство type второго имеет значение 256, что совпадает со значением константы QUIT.

В pygame событие – это объект класса Event. А если это объект, то у него есть атрибуты (свойства и методы). В данном случае мы отслеживаем только те события, у которых значение свойства type совпадает со значением константы QUIT модуля pygame. Это значение присваивается type тогда, когда происходят события нажатия на крестик или Alt+F4. Когда эти события происходят, то в данном случае мы хотим, чтобы выполнилась функция quit() модуля pygame, которая завершает его работу.

Теперь почему возникает ошибка. Функция pygame.quit() отключает (деинициализирует) pygame, но не завершает работу программы. Таким образом, после выполнения этой функции отключаются модули библиотеки pygame, но выхода из цикла и программы не происходит. Программа продолжает работу и переходит к следующей итерации цикла while (или продолжает выполнять тело данной итерации, если оно еще не закончилось).

В данном случае происходит переход к следующей итерации цикла while. И здесь выполнить функцию get() модуля event оказывается уже невозможным. Возникает исключение и программа завершается. По-сути программу завершает не функция pygame.quit(), а выброшенное, но не обработанное, исключение.

Данную проблему можно решить разными способами. Часто используют функцию exit() модуля sys. В этом случае код выглядит примерно так:

Сначала отключается pygame, потом происходит выход из программы. Такой вариант вероятно следует считать наиболее безопасным завершением. Команда pygame.quit() не обязательна. Если завершается программа, то отключится и pygame.

Другой вариант – не допустить следующей итерации цикла. Для этого потребуется дополнительная переменная:

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

Нередко код основной ветки программы помещают в функцию, например, main(). Она выполняется, если файл запускается как скрипт, а не импортируется как модуль. В этом случае для завершения программы проще использовать оператор return, который осуществляет выход из функции.

Теперь зададимся вопросом, с какой скоростью крутится цикл while? С большой, зависящей от мощности компьютера. Но в данном случае такая скорость не есть необходимость, она даже вредна, так как бессмысленно расходует ресурсы. Человек дает команды и воспринимает изменения куда медленнее.

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

Поэтому в главном цикле следует выполнять задержку. Делают это либо вызовом функции delay() модуля time библиотеки pygame, либо создают объект часов и устанавливают ему частоту кадров. Первый способ проще, второй – более профессиональный.

Функция delay() принимает количество миллисекунд (1000 мс = 1 с). Если передано значение 20, то за секунду экран обновится 50 раз. Другими словами, частота составит 50 кадров в секунду.

Методу tick() класса Clock передается непосредственно желаемое количество кадров в секунду. Задержку он вычисляет сам. То есть если внутри цикла указано tick(60) – это не значит, что задержка будет 60 миллисекунд или произойдет 60 обновлений экрана за одну итерацию цикла. Это значит, что на каждой итерации цикла секунда делится на 60 и уже на вычисленную величину выполняется задержка.

Нередко частоту кадров выносят в отдельную константоподобную переменную:

В итоге каркас игры на Pygame должен выглядеть примерно так:

Практическая работа

В модуле pygame.display есть функция set_caption(). Ей передается строка, которую она устанавливает в качестве заголовка окна. Сделайте так, чтобы каждую секунду заголовок окна изменялся.

Курс с примерами решений практических работ:
android-приложение, pdf-версия

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