Как нарисовать круг в pygame
Перейти к содержимому

Как нарисовать круг в pygame

  • автор:

Рисование графических примитивов

На этом занятии рассмотрим функции модуля pygame.draw для рисования графических примитивов:

  • pygame.draw.rect(surface, …) – прямоугольник;
  • pygame.draw.line(surface, …) – линия;
  • pygame.draw.aaline(surface, …) – сглаженная линия;
  • pygame.draw.lines(surface, …) – ломаная линия;
  • pygame.draw.aalines(surface, …) – ломаная сглаженная линия;
  • pygame.draw.polygon(surface, …) – полигон;
  • pygame.draw.circle(surface, …) – круг;
  • pygame.draw.ellipse(surface, …) – эллипс;
  • pygame.draw.arc(surface, …) – дуга.

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

sc = pygame.display.set_mode((600, 400))

(здесь sc – ссылка на базовый объект Surface). Давайте теперь нарисуем в окне прямоугольник с помощью функции rect:

pygame.draw.rect(sc, (255,255,255), (10,10, 50, 100))

Мы здесь первым параметром указали главную поверхность, затем, цвет прямоугольника и его размеры. Цвет определяется в формате (R, G, B). Причем, каждая цветовая компонента меняется в диапазоне от 0 до 255:

  • 0 – отсутствие цветовой составляющей;
  • 255 – полная насыщенность цветовой составляющей.

В данном случае мы включаем все три цветовые компоненты по максимуму и получаем белый цвет. Далее, размеры прямоугольника определяются по формату: (x, y, width, height)

  • x, y – начальные координаты прямоугольника;
  • width, height – ширина и высота прямоугольника.

Обратите внимание, что координаты откладываются от верхнего левого угла и ось Oy направлена вниз (а не вверх, как мы привыкли по математике). Итак, указание нарисовать прямоугольник даны. Но если сейчас выполнить программу, то мы ничего не увидим на экране. Почему? Это связано с тем, что базовый объект Surface использует механизм рисования, известный как буферизация вывода. Ее принцип проще пояснить на таком рисунке. Представим, что объект Surface имеет две стороны A и B: Изначально мы видим сторону B, но рисование выполняется на противоположной стороне – A. Затем, чтобы отобразить нарисованные объекты, мы должны перевернуть объект Surface другой стороной. В PyGame это делается с помощью функции flip():

pygame.display.flip()

Теперь при запуске программы мы видим сторону A с нарисованным прямоугольником. В этом заключается принцип буферизации вывода графической информации. Но спрашивается: зачем все это нужно? Почему бы сразу не рисовать на видимой стороне объекта? В этом случае при большом числе объектов и сложной анимации пользователь будет замечать процесс отрисовки текущего кадра игры. И это негативно скажется на визуальном восприятии игрового процесса. Чтобы перерисовка кадров проходила незаметно для человеческого глаза, как раз и используется механизм буферизации. Помимо метода flip() можно использовать похожий метод: pygame.display.update(rectangle) Здесь rectangle – это прямоугольная область, которую требуется перерисовать (по умолчанию, если ничего не указано, то перерисовывается вся клиентская область и метод update повторяет метод flip). Так как метод update более гибкий, то в дальнейшем я буду использовать именно его. Итак, мы с вами нарисовали закрашенный прямоугольник. Если нужно нарисовать не закрашенный, то следует указать следующий параметр – толщину линии:

pygame.draw.rect(sc, (0, 0, 255), (100, 10, 50, 100), 2)

Разумеется, все функции рисования должны следовать до метода update. Наконец, последний важный штрих. Цвета заливки или линий обычно задаются вначале в виде констант, а затем, уже используются в функциях рисования:

WHITE = (255, 255, 255) BLUE = (0, 0, 255) pygame.draw.rect(sc, WHITE, (10, 10, 50, 100)) pygame.draw.rect(sc, BLUE, (100, 10, 50, 100), 2) pygame.display.update()

Так программа выглядит более читабельной. Давайте теперь посмотрим как рисуются остальные графические примитивы:

WHITE = (255, 255, 255) BLUE = (0, 0, 255) GREEN = (0, 255, 0) RED = (255, 0, 0) pygame.draw.rect(sc, WHITE, (10, 10, 50, 100)) pygame.draw.rect(sc, BLUE, (100, 10, 50, 100), 2) pygame.draw.line(sc, GREEN, (200, 20), (350, 50)) pygame.draw.aaline(sc, GREEN, (200, 40), (350, 70)) pygame.draw.lines(sc, RED, True, [(200, 80), (250, 80), (300, 200)], 2) pygame.draw.aalines(sc, RED, True, [(300, 80), (350, 80), (400, 200)], 2) pygame.draw.polygon(sc, WHITE, [[150, 210], [180, 250], [90, 290], [30, 230]]) pygame.draw.polygon(sc, WHITE, [[150, 310], [180, 350], [90, 390], [30, 330]], 1) pygame.draw.circle(sc, BLUE, (300, 250), 40) pygame.draw.ellipse(sc, BLUE, (300, 300, 100, 50), 1) pi = 3.14 pygame.draw.arc(sc, RED, (450, 30, 50, 150), pi, 2*pi, 5)

Дополнительные главы

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

Основной цикл

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

import sys import pygame # Инициализация pygame pygame.init() # Размер окна screen = pygame.display.set_mode((300, 300)) # Заголовок окна pygame.display.set_caption('Blue Circle') while True: # Задаем цвет фона screen.fill((255, 255, 224)) # Рисуем круг pygame.draw.circle(screen, (50, 50, 200), (150, 150), 75) # Обновляем экран pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.quit() sys.exit() 

Функция pygame.draw.circle принимает следующие аргументы:

  • surface — объект типа Surface — поверхность, на которой будет отрисован круг. В данном случае это основное окно программы.
  • color — кортеж из трех целых чисел или объект типа Color — цвет фигуры в представлении RGB.
  • center — кортеж из двух целых чисел — координаты центра круга в пикселях. Координаты отсчитываются от левого верхнего угла.
  • radius — радиус круга в пикселях.
  • width — ширина кольца в пикселях — необязательный параметр. Если параметр задан, то будет нарисовано кольцо, а не круг.

Функция pygame.draw.circle возвращает объект Rect — прямоугольник, содержащий нарисованный объект. Это нам еще пригодится, когда мы будем организовывать взаимодействие с кругом.

pygame1

Вывод текста

За работу с текстом в pygame отвечает модуль font. Перед его использованием необходимо выполнить инициализацию

pygame.font.init() 

Функция pygame.font.SysFont создает объект типа Font , который может отрисовывать текст:

font = pygame.font.SysFont(name=font, size=20) surf = font.render( 'Click on the circle', antialias=True, color=(0, 0, 0)) screen.blit(surf, (70, 260)) 

Функция render создает объект типа Surface с отрисованным текстом. Параметр antialias управляет сглаживанием текста.

Метод Surface.blit отрисовывает одну поверхность на другой. Мы ей воспользовались чтобы отрисовать поверхность с текстом в основном окне. В результате получаем следующее:

pygame2

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

Сделаем так, чтобы круг менял цвет при нажатии на него мышкой:

def get_color(): idx = 0 colors = [ (50, 50, 200), (50, 200, 50), (200, 50, 50) ] while True: yield colors[idx % len(colors)] idx += 1 colors = get_color() color = next(colors) while True: # . circ_rect = pygame.draw.circle(screen, color, (150, 150), 75) for event in pygame.event.get(): # . if event.type == pygame.MOUSEBUTTONDOWN: if circ_rect.collidepoint(event.pos): color = next(colors) 

Атрибут pos возвращает координаты нажатия курсора, метод Rect.collidepoint возвращает True , если координаты лежат внутри прямоугольника.

Графические примитивы и маски

Модуль pygame.draw содержит инструменты для отрисовки различных графических примитивов:

  • pygame.draw.polygon(surface, color, pointlist, width)
  • pygame.draw.line(surface, color, start_point, end_point, width)
  • pygame.draw.lines(surface, color, closed, pointlist, width)
  • pygame.draw.circle(surface, color, center_point, radius, width)
  • pygame.draw.ellipse(surface, color, bounding_rectangle, width)
  • pygame.draw.rect(surface, color, rectangle_tuple, width)

В текущем виде программа реагирует на нажатие мышки внутри квадрата, описанного вокруг круга. Для проверки попадания координаты внутрь круга можно использовать инструменты модуля pygame.mask :

while True: # . circ_surf = pygame.Surface((150, 150), pygame.SRCALPHA, 32)\ .convert_alpha() circ_rect = pygame.draw.circle(circ_surf, color, (75, 75), 75) screen.blit(circ_surf, (75, 75)) circ_mask = pygame.mask.from_surface(circ_surf) for event in pygame.event.get(): # . if event.type == pygame.MOUSEBUTTONDOWN: rpos = (event.pos[0] - 75, event.pos[1] - 75) if circ_rect.collidepoint(rpos) and\ circ_mask.get_at(rpos): color = next(colors) 

Сначала мы создали прозрачную поверхность, на которой нарисовали круг. Затем на основе этой поверхности создали битовую маску, соответствующую пикселям поверхности. Маска выделяет все непрозрачные пиксели поверхности. При проверке попадания координаты внутрь круга используется метод mask.get_at , возвращающий значение маски в заданной позиции. Поскольку круг нарисован на поверхности circ_surf , а не в главной поверхности, то проверка положения выполняется в локальных координатах на поверхности circ_surf .

Работа с растровыми файлами

Модуль pygame.image позволяет открывать изображение из файла и сохранять поверхности (объекты типа Surface ) в файл. Поместим логотип pygame в наше окно:

logo_surf = pygame.image.load('figs/logo_lofi.png') screen.blit(logo_surf, (60, 10)) 

В результате получаем:

pygame_logo

Чтобы сохранить содержимое поверхности в файл, нужно вызвать

pygame.image.save(screen, 'screen.png') 

Частота обновления

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

frames_per_second = 30 clock = pygame.time.Clock() while True: # . clock.tick(frames_per_second) 

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

import sys import pygame # Инициализация pygame pygame.init() pygame.font.init() # Размер окна screen = pygame.display.set_mode((300, 300)) # Заголовок окна pygame.display.set_caption("Blue Circle") font = pygame.font.SysFont(name='arial', size=20) def get_color(): idx = 0 colors = [ (50, 50, 200), (50, 200, 50), (200, 50, 50) ] while True: yield colors[idx % len(colors)] idx += 1 text = 'Click on the circle' colors = get_color() color = next(colors) logo_surf = pygame.image.load('figs/logo_lofi.png') delay = 100 while True: # Задаем цвет фона screen.fill((255, 255, 224)) # Рисуем круг circ_surf = pygame.Surface((150, 150), pygame.SRCALPHA, 32)\ .convert_alpha() circ_rect = pygame.draw.circle(circ_surf, color, (75, 75), 75) screen.blit(circ_surf, (75, 75)) circ_mask = pygame.mask.from_surface(circ_surf) # Рисуем текст font_surf = font.render(text, True, (0, 0, 0)) screen.blit(font_surf, (70, 260)) # Рисуем лого pygame screen.blit(logo_surf, (60, 10)) # Обновляем экран pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: pygame.quit() sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN: rpos = (event.pos[0] - 75, event.pos[1] - 75) if circ_rect.collidepoint(rpos) and\ circ_mask.get_at(rpos): color = next(colors) pygame.time.wait(delay) 

Резюме

В этом разделе мы обсудили основные инструменты библиотеки pygame.

Источники

  • Документация pygame
  • PyGame: A Primer on Game Programming in Python
  • Python pygame – The Full Tutorial
  • Game loop
  • Game Loop pattern
  • dr0id pygame tutorials
  • Введение
  • Настройка рабочей среды
  • Язык C++
  • Язык Python
  • Дополнительные главы
    • Графика и GUI с библиотекой pygame
    • Виртуальная машина

    Модуль pygame.draw

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

    import pygame as pg import sys sc = pg.display.set_mode((300, 200)) # здесь будут рисоваться фигуры pg.display.update() while 1: for i in pg.event.get(): if i.type == pg.QUIT: sys.exit() pg.time.delay(1000)

    В большинстве случаев фигуры прорисовывают внутри главного цикла, так как от кадра к кадру картинка на экране должна меняться. Поэтому на каждой итерации цикла в функции модуля 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) BLACK = (0, 0, 0) 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))

    Эллипс

    pi = 3.14 pygame.draw.arc(sc, WHITE, (10, 50, 280, 100), 0, pi) pygame.draw.arc(sc, PINK, (50, 30, 200, 150), pi, 2*pi, 3)

    Дуги

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

    Практическая работа. Анимация

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

    Суть алгоритма в следующем. Берем фигуру. Рисуем ее на поверхности. Обновляем главное окно, человек видит картинку. Стираем фигуру. Рисуем ее с небольшим смещением от первоначальной позиции. Снова обновляем окно и так далее.

    Как «стереть» старую фигуру? Для этого используется метод fill() объекта Surface . В качестве аргумента передается цвет, т. е. фон можно сделать любым, а не только черным, который задан по-умолчанию.

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

    import pygame import sys FPS = 60 WIN_WIDTH = 400 WIN_HEIGHT = 100 WHITE = (255, 255, 255) ORANGE = (255, 150, 100) clock = pygame.time.Clock() sc = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) # радиус будущего круга r = 30 # координаты круга # скрываем за левой границей x = 0 - r # выравнивание по центру по вертикали y = WIN_HEIGHT // 2 while 1: for i in pygame.event.get(): if i.type == pygame.QUIT: sys.exit() # заливаем фон sc.fill(WHITE) # рисуем круг pygame.draw.circle(sc, ORANGE, (x, y), r) # обновляем окно pygame.display.update() # Если круг полностью скрылся за правой границей, if x >= WIN_WIDTH + r: # перемещаем его за левую x = 0 - r else: # Если еще нет, # на следующей итерации цикла # круг отобразится немного правее x += 2 clock.tick(FPS)

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

    X Скрыть Наверх

    Pygame. Введение в разработку игр на Python

    Нарисовать круг в Pygame

    Есть код, я пока смогу нарисовать только просто квадрат.
    Помогите нарисовать круг. Данные, которые вводятся, это размер квадрата и насыщенность цвета. main.py:

    import pygame RED = (70, 0, 0) w, color = map(int, input().split()) pygame.init() size = width, height = 700, 700 screen = pygame.display.set_mode(size) pygame.display.set_caption("Прямоугольник") screen.fill((0, 0, 0)) font = pygame.font.Font(None, 50) pygame.draw.rect(screen, (color, 0, 0), (100, 100, w, w)) pygame.display.flip() while pygame.event.wait().type != pygame.QUIT: pass pygame.quit 

    Отслеживать
    73.5k 110 110 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков
    задан 17 дек 2020 в 14:30
    319 3 3 серебряных знака 14 14 бронзовых знаков

    1 ответ 1

    Сортировка: Сброс на вариант по умолчанию

    pygame.draw.circle(surface, color, center, radius)

    import pygame RED = (70, 0, 0) w, colorRect, colorCircle = map(int, input('\nВведите например 200 180 250: ').split()) pygame.init() size = width, height = 700, 700 screen = pygame.display.set_mode(size) pygame.display.set_caption("Прямоугольник") screen.fill((0, 0, 0)) font = pygame.font.Font(None, 50) pygame.draw.rect(screen, (colorRect, 0, 0), (100, 100, w, w)) pygame.draw.circle(screen, (colorCircle, 0, 0), (350, 350), w/2) # +++ pygame.display.flip() while pygame.event.wait().type != pygame.QUIT: pass pygame.quit 

    введите сюда описание изображения

    Отслеживать
    ответ дан 28 дек 2020 в 23:12
    73.5k 110 110 золотых знаков 38 38 серебряных знаков 55 55 бронзовых знаков

    • python
    • python-3.x
    • gui
    • pygame
    • рисование
      Важное на Мете
    Похожие

    Подписаться на ленту

    Лента вопроса

    Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

    Дизайн сайта / логотип © 2024 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2024.1.9.3159

    Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *