Как сделать квадрат в pygame
Вместо этого в pygame есть функция init(), которая импортирует весь инструментарий pygame, другими словами, инициализирует все модули библиотеки.
После этого можно вывести на экран главное графическое окно игры с помощью функции set_mode() модуля display, входящего в состав библиотеки pygame:
import pygame
Если выполнить этот код, то появится окно размером 600x400 пикселей и сразу закроется.
Функция set_mode() принимает три аргумента – размер в виде кортежа из двух целых чисел, флаги и глубину цвета. Их можно не указывать. В этом случае окно займет весь экран, цветовая глубина будет соответствовать системной. Обычно указывают только первый аргумент – размер окна.
Флаги предназначены для переключения на аппаратное ускорение, полноэкранный режим, отключения рамки окна и др. Например, команда pygame.display.set_mode((640, 560), pygame.RESIZABLE) делает окно изменяемым в размерах.
Выражение вида pygame.RESIZABLE (вместо RESIZABLE может быть любое другое слово большими буквами) обозначает обращение к той или иной константе, определенной в модуле pygame. Часто можно встретить код, в котором перед константами не пишется имя модуля (вместо, например, pygame.QUIT пишут просто QUIT). В этом случае в начале программы надо импортировать не только pygame, но и содержимое модуля locals через from … import:
import pygame
from pygame.locals 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 же требуется собственноручно создать бесконечный цикл, заставляющий программу зависнуть. Основная причина в том, что только программист знает, какая часть его кода должна циклически обрабатываться, а какая – нет. Например, код, создающий классы, объекты и функции не "кладут" в цикл.
Итак, создадим в программе бесконечный цикл:
import pygame
while 1:
Pass
После такого окно уже не закроется, а программа благополучно зависнет насовсем. Многократные клики по крестику не помогут. Только принудительная остановка программы через среду разработки или Ctrl+С, если запускали через терминал.
Как сделать так, чтобы программа закрывалась при клике на крестик окна, а также при нажатии Alt+F4? Pygame должен воспринимать такие действия как определенный тип событий.
Добавим в цикл магии:
while 1:
for i in pygame.event.get():
if i.type == pygame.QUIT:
При выходе будет генерироваться ошибка, пока забудем про нее. Сейчас достаточно того, что окно успешно закрывается.
Рассмотрим выражение pygame.event.get(). Модуль event библиотеки pygame содержит функцию get(), которая забирает список событий из очереди, в которую записываются все произошедшие события. То, что возвращает get() – это список. Забранные события удаляются из очереди, то есть второй раз они уже забираться не будут, а в очередь продолжают записываться новые события.
Цикл for просто перебирает схваченный на данный момент (в текущей итерации цикла) список событий. Каждое событие он присваивает переменной i или любой другой. Чтобы было понятней, можно записать так:
while 1:
for event in events:
if event.type == pygame.QUIT:
В pygame событие – это объект класса Event. А если это объект, то у него есть атрибуты (свойства и методы). В данном случае мы отслеживаем только те события, у которых значение свойства type совпадает со значением константы QUIT модуля pygame. Это значение присваивается type тогда, когда происходят события нажатия на крестик или Alt+F4. Когда эти события происходят, то в данном случае мы хотим, чтобы выполнилась функция quit() модуля pygame, которая завершает его работу.
Теперь почему возникает ошибка. Функция pygame.quit() отключает (деинициализирует) pygame, но не завершает работу программы. Таким образом, после выполнения этой функции отключаются модули библиотеки pygame, но выхода из цикла и программы не происходит. Программа продолжает работу и переходит к следующей итерации цикла while (или продолжает выполнять тело данной итерации, если оно еще не закончилось).
В данном случае происходит переход к следующей итерации цикла while. И здесь выполнить функцию get() модуля event оказывается уже невозможным. Возникает исключение и программа завершается. По-сути программу завершает не функция pygame.quit(), а выброшенное, но не обработанное, исключение.
Данную проблему можно решить как минимум двумя способами. Часто используют функцию exit() модуля sys. В этом случае код выглядит примерно так:
import pygame
import sys
while 1:
for i in pygame.event.get():
if i.type == pygame.QUIT:
Сначала отключается pygame, потом происходит выход из программы. Такой вариант вероятно следует считать наиболее безопасным завершением. Мы же в целях упрощения кода в дальнейшем будем использовать функции exit() самого Python (без sys). Команда pygame.quit() не обязательна. Если завершается программа, то отключится и pygame.
Второй вариант – не допустить следующей итерации цикла. Для этого потребуется переменная:
while play:
for i in pygame.event.get():
if i.type == pygame.QUIT:
В этом случае завершится текущая итерация цикла, но новая уже не начнется. Если в основной ветке ниже по течению нет другого кода, программа завершит свою работу.
Нередко код основной ветки программы помещают в функцию, например, main(). Она выполняется, если файл запускается как скрипт, а не импортируется как модуль. В этом случае для завершения программы проще использовать оператор return, который осуществляет выход из функции.
import pygame
def main():
while True:
for i in pygame.event.get():
if i.type == pygame.QUIT:
return
if __name__ == "__main__":
Перейдем к следующему вопросу. С какой скоростью крутится цикл while? С большой, зависящей от мощностей компьютера. Но в данном случае такая скорость не есть необходимость, она даже вредна, так как бессмысленно расходует ресурсы. Человек дает команды и воспринимает изменения куда медленнее.
Для обновления экрана в динамической игре часто используют 60 кадров в секунду, а в статической, типа пазла, достаточно будет 30-ти. Из этого следует, что циклу незачем работать быстрее.
Поэтому в главном цикле следует выполнять задержку. Делают это либо вызовом функции delay() модуля time библиотеки pygame, либо создают объект часов и устанавливают ему частоту кадров. Первый способ проще, второй – более профессиональный.
import pygame
while True:
for i in pygame.event.get():
if i.type == pygame.QUIT:
Функция delay() принимает количество миллисекунд (1000 мс = 1 с). Если передано значение 20, то за секунду экран обновится 50 раз. Другими словами, частота составит 50 кадров в секунду.
import pygame
while True:
for i in pygame.event.get():
if i.type == pygame.QUIT:
Методу tick() класса Clock передается непосредственно желаемое количество кадров в секунду. Задержку он вычисляет сам. То есть если внутри цикла указано tick(60) – это не значит, что задержка будет 60 миллисекунд или произойдет 60 обновлений экрана за одну итерацию цикла. Это значит, что на каждой итерации цикла секунда делится на 60 и уже на вычисленную величину выполняется задержка.
Нередко частоту кадров выносят в отдельную константоподобную переменную:
while True:
for i in pygame.event.get():
if i.type == pygame.QUIT:
В итоге каркас игры на Pygame должен выглядеть примерно так:
import pygame
while True:
for i in pygame.event.get():
if i.type == pygame.QUIT:
Модуль pygame.draw – геометрические примитивы
Функции модуля pygame.draw рисуют геометрические примитивы на поверхности – экземпляре класса Surface. В качестве первого аргумента они принимают поверхность. Поэтому при создании той или иной поверхности ее надо связать с переменной, чтобы потом было что передать в функции модуля draw. Поскольку мы пока используем только одну поверхность – главную оконную, то ее будем указывать в качестве первого параметра, а при создании свяжем с переменной:
import pygame
sc = pygame.display.set_mode((300, 200))
while 1:
for i in pygame.event.get():
if i.type == pygame.QUIT: exit()
В большинстве случаев фигуры прорисовывают внутри главного цикла, так как от кадра к кадру картинка на экране должна меняться. Поэтому на каждой итерации цикла в функции модуля draw передаются несколько измененные аргументы (например, каждый раз меняется координата x).
Однако у нас пока не будет никакой анимации, и нет смысла перерисовывать фигуры на одном и том же месте на каждой итерации цикла. Поэтому создавать примитивы будем в основной ветке программы. На данном этапе цикл while нужен лишь для того, чтобы программа самопроизвольно не завершалась.
После прорисовки, чтобы увидеть изменения в окне игры, необходимо выполнить функцию update() или flip() модуля display. Иначе окно не обновится. Рисование на поверхности – одно, а обновление состояния главного окна – другое. Представьте, что в разных местах тела главного цикла на поверхности прорисовываются разные объекты. Если бы каждое такое действие приводило к автоматическому обновлению окна, то за одну итерацию оно обновлялось бы несколько раз. Это приводило бы как минимум к бессмысленной трате ресурсов, так как скорость цикла связана с FPS.
Итак, первый аргумент функций рисования – поверхность, на которой размещается фигура. В нашем случае это будет sc. Вторым обязательным аргументом является цвет. Цвет задается в формате RGB, используется трехэлементный целочисленный кортеж. Например, (255, 0, 0) определяет красный цвет.
Далее идут специфичные для каждой фигуры аргументы. Последним у большинства является толщина контура.
Все функции модуля draw возвращают экземпляры класса Rect – прямоугольные области, имеющие координаты, длину и ширину. Не путайте функцию rect() модуля draw и класс Rect, это разные вещи.
Начнем с функции rect() модуля draw:
pygame.draw.rect(sc, (255, 255, 255), (20, 20, 100, 75))
pygame.draw.rect(sc, (64, 128, 255), (150, 20, 100, 75), 8)
Если указывается толщина контура (последний аргумент во второй строке), то прямоугольник будет незаполненным, а цвет определит цвет рамки. Третьим аргументом является кортеж из четырех чисел. Первые два определяют координаты верхнего левого угла прямоугольника, вторые – его ширину и высоту.
Следует отметить, что в функцию draw.rect() и некоторые другие третьим аргументом можно передавать не кортеж, а заранее созданный экземпляр Rect. В примере ниже показан такой вариант.
Обычно цвета выносят в отдельные переменные-константы. Это облегчает чтение кода:
WHITE = (255, 255, 255)
GRAY = (125, 125, 125)
LIGHT_BLUE = (64, 128, 255)
GREEN = (0, 200, 64)
YELLOW = (225, 225, 0)
PINK = (230, 50, 230)
r1 = pygame.Rect((150, 20, 100, 75))
pygame.draw.rect(sc, WHITE, (20, 20, 100, 75))
pygame.draw.rect(sc, LIGHT_BLUE, r1, 8)
Чтобы нарисовать линию, а точнее – отрезок, надо указать координаты его концов. При этом функция line() рисует обычную линию, aaline() – сглаженную (толщину для последней указать нельзя):
pygame.draw.line(sc, WHITE, [10, 30], [290, 15], 3)
pygame.draw.line(sc, WHITE, [10, 50], [290, 35])
pygame.draw.aaline(sc, WHITE, [10, 70], [290, 55])
Координаты можно передавать как в виде списка, так и кортежа.
Функции lines() и aalines() рисуют ломанные линии:
pygame.draw.lines(sc, WHITE, True, [[10, 10], [140, 70], [280, 20]], 2)
pygame.draw.aalines(sc, WHITE, False, [[10, 100], [140, 170], [280, 110]])
Координаты определяют места излома. Количество точек может быть произвольным. Третий параметр (True или False) указывает замыкать ли крайние точки.
Функция polygon() рисует произвольный многоугольник. Задаются координаты вершин.
pygame.draw.polygon(sc, WHITE, [[150, 10], [180, 50], [90, 90], [30, 30]])
pygame.draw.polygon(sc, WHITE, [[250, 110], [280, 150], [190, 190], [130, 130]])
pygame.draw.aalines(sc, WHITE, True, [[250, 110], [280, 150], [190, 190], [130, 130]])
Сглаженная ломаная здесь повторяет контур многоугольника, чем сглаживает его ребра.
Так же как в случае rect() для polygon() можно указать толщину контура.
Функция circle() рисует круги. Указывается центр окружности и радиус:
pygame.draw.circle(sc, YELLOW, (100, 100), 50)
pygame.draw.circle(sc, PINK, (200, 100), 50, 10)
В случае эллипса передается описывающая его прямоугольная область:
pygame.draw.ellipse(sc, GREEN, (10, 50, 280, 100))
pygame.draw.arc(sc, WHITE, (10, 50, 280, 100), 0, pi)
pygame.draw.arc(sc, PINK, (50, 30, 200, 150), pi, 2*pi, 3)
Указывается прямоугольник, описывающий эллипс, из которого вырезается дуга. Четвертый и пятый аргументы – начало и конец дуги, выраженные в радианах. Нулевая точка справа.
Есть код, я пока смогу нарисовать только просто квадрат. Помогите нарисовать круг.
Данные которые вводятся - это размер квадрата и насыщенность цвета.
1 ответ 1
pygame.draw.circle(surface, color, center, radius)
Всё ещё ищете ответ? Посмотрите другие вопросы с метками python python-3.x gui pygame или задайте свой вопрос.
Похожие
Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.
дизайн сайта / логотип © 2022 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2022.1.24.41248
Не понимаю как сделать так, чтобы квадрат отскакивал от стен по горизонтали в методе update.
Пробовал использовать циклы, но тоже ничего не получалось. Получается сделать только так, чтобы прямоугольник дошёл до одной из стен, дальше не выходит.
Потому что эта проверка зацикливает квадрат у границы: как только он начинает идти в обратную сторону, срабатывает первое условие и он снова меняет направление.
Отскок обычное делается сменой знака прироста расстояния (скорости) на каждой из границ.
Модуль ImageDraw из библиотеки обработки изображений Pillow (PIL) предоставляет методы для рисования круга, квадрата и прямой линии в Python.
Содержание статьи
Создание объекта Draw в Python
Используя объекта Image мы создадим фоновое изображение на которой мы будем рисовать наши фигуры при помощи объекта Draw . Не забудьте импортировать модуль Image и ImageDraw в начале кода.
Здесь создается пустое изображение с размером 500 на 300 пикселей и с тёмно желтым фоном.
Рисуем фигуры в Pillow: ellipse, rectangle и line
Вызываем методы рисования из объекта Draw для рисования фигур на нашем желтом фоне.
Рисуем эллипс, прямоугольник и прямую линию в качестве примера.
Справочник по параметрам методов рисования
Даже если, способы рисования отличаются в зависимости от используемого метода, следующие параметры являются общими для всех.
Область рисования — xy
Параметр xy указывает прямоугольную область для рисования новой фигуры.
Уточняется один из следующих форматов:
- (((Верхняя левая x координата, Верхняя левая y координата), (нижняя правая x координата, нижняя правая y координата)) ;
- (Верхняя левая x координата, Верхняя левая y координата, нижняя правая x координата, нижняя правая y координата) .
В методах line() , polygon() и point() используются многочисленные координаты вместо двух точек, представляющих прямоугольную область.
- (x1, y1, x2, y2, x3, y3. ) ;
- ((x1, y1), (x2, y2), (x3, y3). ) .
Метод line() рисует прямую линию, которая связывает каждую точку, polygon() рисует многоугольник, а метод point() рисует точку в 1 пиксель для каждой указанной точки.
Параметр fill — заполняем фигуру определенным цветом
Параметр fill указывает какой цвет будет использован для заполнения нашей геометрической формы.
Спецификация формата цвета отличается в зависимости от указанного режима изображения (объект Image ):
- RGB : Указывает значение цвета в форме (R, G, B) ;
- L (Черно-белое): Указывает значение (0-255) как целое число).
Значение по умолчанию None (не заполнено).
Есть три способа указать цвет, возьмем красный цвет, его можно записать так:
Параметр outline — цвет границ
Параметр outline указывает на цвет границы фигуры.
Спецификация формата цвета такая же, как и у параметра fill которого мы обсуждали выше. Значение по умолчанию равно None (без границ).
Параметр width — размер границ
Вне зависимости от рисуемой фигуры, вы можете указать размер в пикселях для границы фигуры.
Рисование эллипса и прямоугольника в Python
- Эллипс (Круг): ellipse(xy, fill, outline) ;
- Прямоугольник (Квадрат): rectangle(xy, fill, outline) .
Метод ellipse() рисует эллипс, область рисования указывается в параметр xy . Если мы зададим четыре координата которые будут соответствовать квадрату, то у нас получится ровный круг.
Читайте также: