Модуль 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-версия


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




Все разделы сайта