# Импорт библиотеки Pygame
import pygame
# инициализация модулей библиотеки Pygame
pygame.init()
Запишем программный код, который будем использовать как основной шаблон для игровой программы. Поскольку в большинстве случаев внутри основного цикла выполняется рисование или вывод изображений, то дополним наш программный код рисованием. Для примера в игровом цикле будем рисовать круг синего цвета.
Вот основные функции, которые реализует код шаблона игровой программы:
# Импорт Pygame
import pygame
# инициализация модулей Pygame
pygame.init()
# задаем основные параметры
W = 600 # ширина окна
H = 400 # высота окна
r = 20 # радиус круга
x = 300 # координата x центра круга
y = 200 # координата y центра круга
# задаем цвета
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
blue = (0, 0, 255 )
# Создание окна, шириной 600 и высотой 400 пикселей
screen = pygame.display.set_mode((W, H))
# Задание заголовка окна
pygame.display.set_caption("Игровое окно")
# устанавливаем цвет игрового окна
screen.fill(green)
# обновление основного окна
pygame.display.flip()
# задаем частоту кадров - 60 кадров в секунду
FPS = 60
# подключаем часы
clock = pygame.time.Clock()
# Игровой цикл событий
# Оставаться в цикле, пока пользователь не нажмёт на кнопку закрытия окна
running = True
while running:
for event in pygame.event.get():
# закрытие окна
if event.type == pygame.QUIT:
running = False
# рисуем круг в памяти компьютера
pygame.draw.circle(screen, blue, (x, y), r)
# отображаем все игровое окно на экран
pygame.display.flip()
# устанавливаем автоматический контроль кадров
clock.tick(FPS)
# Завершение Pygame, освобождаем ресурсы
pygame.quit()
Программное окно, в котором в любой момент времени будет формироваться один кадр игры, а в процессе игры отображаться другие кадры, называется основным графическим окном игры. Вот код, который создаст пустое окно игры.
# Импорт библиотеки Pygame
import pygame
# инициализация модулей библиотеки Pygame
pygame.init()
# Создание окна, шириной 600 и высотой 400 пикселей
screen = pygame.display.set_mode((600, 400))
# Задание заголовка окна
pygame.display.set_caption("Заголок окна")
# закрытие Pygame и освобождение ресурсов
pygame.quit()
В пустом окне программы невозможно отобразить текст или графику, поэтому в различных графических библиотеках для этих целей использую такие понятия как поверхность или хост, по аналогии с холстом художника.
В Pygame для отображения графики в окне программы используют термин поверхность ( анг. surface - поверхность). Поверхность surface представляет часть экрана, на которой отображаются игровые элементы. В программе может быть много поверхностей, но всегда имеется основная поверхность, которую создает следующий метод:
screen = pygame.display.set_mode((600, 400))
Объект, присвоенный переменной screen, называется поверхностью (surface). Метод display.set_mode всегда возвращает основную поверхность - это основное графическое окно программы. При каждом проходе игрового цикла происходит обновление основного графического окна программы.
В методе display.set_mode((600, 400))первый параметр 600 - ширина, второй 400 – высота окна в пикселях. Двойные круглые скобки обязательны, поскольку метод set_mode() принимает значения не как два отдельных параметра, а как связанные значения в качестве параметра - кортеж.
Игры так устроены, что большая часть действий циклически потеряется: выполняется действие в игре, которое приводит к изменению состояния игры и, которое в свою очередь формирует новую стратегию поведения игрока. Далее все повторяется: действие, состояние, стратегия. Это и есть игровой цикл - базовое понятие в теории игр, на котором строится структура и логика игры.
С точки зрения программирования структура игровой программы построена следующим образом: в начале программы идет блок кода, в котором выполняется инициализация вспомогательных компонентов – графики, звука, времени, видео и других. Далее идет блок кода, который содержит бесконечный цикл, выход из которого приводит к окончанию игры.
В бесконечном цикле необходимо постоянно выполнять какие-то действия: реагировать на действия игрока, например, игрок нажал клавишу на клавиатуре, обновлять экран игры, потому что изменилось его содержимое. Поэтому в игровых программах присутствует цикл, который непрерывно проверяет, выполняет ли пользователь какие-либо действия и необходимо ли выполнять обновление игрового экрана. Такой цикл называется игровым циклом событий.
Игровой цикл событий записывается с помощью оператора while. Он должен работать все время, пока пользователь играет в игру и может быть записан следующим образом:
# Игровой цикл событий
running = True
while running:
# здесь записываем:
# код выхода из цикла
# обработку игровых событий
# всю игровую логику
# и весь код рисования и анимации
Один цикл в игре называется кадром. Частота кадров в секунду определяет скорость работы цикла и, следовательно, и скорость самой игры. Обычно используют значения 30 кадров в секунды для статических игр и 60 кадров в секунду для динамических игр. Для обозначения частоты кадров используется переменная с именемFPS (Frames Per Second - кадры в секунду).
Здесь важно еще одно условие: необходимо чтобы частота кадров не завесила от того, на каком компьютере запущена игра на «медленном» или на «быстром». Для того, чтобы выполнить это условие используют команду clock.tick(FPS), которая работает таким образом, что в секунде всегда заданное количество кадров FPS, например, 60, не зависимо от характеристик конкретного компьютера. Такая возможность достигается за счет автоматического подбора длительности паузы между кадрами.
Таким образом, команда clock.tick(FPS) выполняет автоматический контроль заданной частоты кадров.
Программная реализация контроля частоты кадров может быть записана следующим образом:
# задаем частоту кадров - 60 кадров в секунду
FPS = 60
# подключаем часы
clock = pygame.time.Clock()
# Игровой цикл событий
running = True
while running:
# здесь записываем:
# код выхода из цикла
# обработку игровых событий
# всю игровую логику
# весь код рисования и анимации
# устанавливаем автоматический контроль кадров
clock.tick(FPS)
Событие (англ. Event) – это один из объектов pygame. Все события в PyGame при их появлении добавляются в очередь событий. Каждый элемент в этой очереди является Event объектом. Для получения доступа к событиям используется метод pygame.event.get(), который возвращает список событий, произошедших с момента последнего вызова этого метода. Просматривая список событий, мы может обработать выход из программы
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
С помощью цикла for проходим по списку. Каждое возникающее событие последовательно извлекается из цепочки событий, и проверяется, является ли оно событием pygame.QUIT. Если есть событие QUIT в очереди событий, то выйдем из игрового цикла
Добавим код закрытия окна в наш
# Импорт Pygame
import pygame
# инициализация модулей Pygame
pygame.init()
# Создание окна, шириной 600 и высотой 400 пикселей
screen = pygame.display.set_mode((600, 400))
# Задание заголовка окна
pygame.display.set_caption("Игровое окно")
# задаем частоту кадров - 60 кадров в секунду
FPS = 60
# подключаем часы
clock = pygame.time.Clock()
# Игровой цикл событий
# Оставаться в цикле, пока пользователь не нажмёт на кнопку закрытия кна
running = True
while running:
for event in pygame.event.get():
# закрытие окна
if event.type == pygame.QUIT:
running = False
# здесь записываем:
# обработку игровых событий
# всю игровую логику
# весь код рисования и анимации
# устанавливаем автоматический контроль кадров
clock.tick(FPS)
# Завершение Pygame, освобождаем ресурсы
pygame.quit()
Если запустить эту программу, то увидим работающее игровое окно, исчезающее, когда вы его закрываете.
Метод pygame.display.flip() обновляет содержимое основного окна игры. При обновлении используется механизм двойной буферизации. Экранная картинка сначала формируется в памяти компьютера, где она невидима, а затем методом display.flip () переносится на экран. В результате изменения появляются не постепенно, а сразу, что позволяет избежать возникновения на экране изображений нарисованных лишь наполовину и уменьшить мерцания экрана.
Аналогом метода pygame.display.flip() является метод update(), имеющий тоже назначение.
pygame.display.update(rectangle)
Здесь rectangle – это прямоугольная область, которую требуется перерисовать. По умолчанию, если параметр rectangle не указан
pygame.display.update(),
то перерисовывается вся клиентская область. Этот метод позволяет повысить производительность рисования, обновляя не все главное игровое окно, а обновляя только те части окна, которые были изменены. Для этого необходимо задать прямоугольные области, которые требуется перерисовать.
Примечание.
Вся область игрового окна состоит из клиентской и не клиентской областей.
Клиентской называется та область, в которой отображается содержимое окна.
Не клиентская область – это служебные области окна: рамка, заголовок, полосы прокрутки, главное меню и т.п.
Выполним обновление содержимого основного игрового окна
# Импорт Pygame
import pygame
# инициализация модулей Pygame
pygame.init()
# Создание окна, шириной 600 и высотой 400 пикселей
screen = pygame.display.set_mode((600, 400))
# Задание заголовка окна
pygame.display.set_caption("Игровое окно")
# задание цветов
black = ( 0, 0, 0)
white = (255, 255, 255)
green = ( 0, 255, 0)
blue = (0, 0, 255 )
red = (255, 0, 0)
screen.fill(green)
pygame.display.flip() обновление основного игрового окна
# задаем частоту кадров - 60 кадров в секунду
FPS = 60
# подключаем часы
clock = pygame.time.Clock()
# Игровой цикл событийrunning = True
while running:
#Оставаться в цикле, пока пользователь не нажмёт на кнопку закрытия окна
# далее программный код изложенный выше
Поверхность surface представляет часть экрана, на которой отображаются игровые элементы. В программе может быть много поверхностей, но всегда имеется основная поверхность, которую создает следующий метод:
screen = pygame.display.set_mode((600, 400))
Объект, присвоенный переменной screen, называется поверхностью (surface). Метод display.set_mode всегда возвращает основную поверхность - это основное графическое окно программы. При каждом проходе игрового цикла происходит обновление основного графического окна программы
Функция Surface()
Эта функция pygame.Surface() используется для создания объекта surface - это дополнительная поверхность для размещения на ней изображений. Она принимает в качестве параметра кортеж с двумя значениями (ширина, высота) поверхности
mySurface = pygame.Surface((100, 100))
Этот код создаст пустое изображение размером 100 x 100 пикселей. Цвет по умолчанию будет черным.
Функция fill()
Функция принимает объект color – цвет заливки поверхности, это кортеж RGB, например, BLUE = (0, 0, 255)
mySurface.fill((0, 0, 255)) # BLUE
Поверхности можно делать прозрачными с помощью их метода set_alpha(). Аргумент меняется от 0 (полная прозрачность) до 255 (полная непрозрачность).
mySurface.set_alpha(0) # полная прозрачность
Функция blit()
Эта функция обычно принимает два параметра Первый параметр - это дополнительная поверхность, которая должна быть нарисована на основной поверхности. Второй параметр - координаты размещения верхнего левого угла дополнительной поверхности в координатной системе основной поверхности
screen.blit(mySurface, (50,50))
В этом примере функция blit() отображает содержимое дополнительной поверхности mySurface на поверхности screen.
Метод pygame.display.flip()
Этот метод обновляет содержимое основного экрана, используя механизм двойной буферизации. Если он не будет вызван, ни одно из изменений, вызванных вызовом функции blit(), не будет отображаться на экране.
Метод pygame.display.update()
Метод pygame.display.update() является аналогом метода
pygame.display.flip().
Механизм двойной буферизации
Метод pygame.display.flip() обновляет содержимое основного окна игры. При обновлении используется механизм двойной буферизации. Экранная картинка сначала формируется в памяти компьютера, где она невидима, а затем методом display.flip() переносится на экран. В результате изменения появляются не постепенно, а сразу, что позволяет избежать возникновения на экране изображений нарисованных лишь наполовину и уменьшить мерцания экрана.
Класс Draw имеет 9 методов рисования геометрических фигур, которые имеют следующие общие параметры:
Surface – поверхность рисования, в нашем случае это объект screen
color – цвет фигуры, это кортеж RGB, например, RED = (255, 0, 0)
Rect – прямоугольная область, в которой будет рисоваться
фигура. Задается кортежем Rect(x, y, w, h), x, y – координаты
левого верхнего угла, w, h – ширина, высота,width – толщина
линии, если width=0, то рисуется закрашенная фигура.
pygame.draw.rect(Surface, color, Rect, width=0)
pygame.draw.circle(Surface, color, (x, y), radius, width=0)
pygame.draw.polygon(Surface, color, pointlist, width =0)
pointlist –координаты вершин многоугольника
Рисование линий
1. Рисование линии между точками start=(x,y) и end=(x1,y1)
pygame.draw.line(Surface, color, start, end, width=1)
2. Рисование тонкой сглаженной линии между точками start=(x,y) и end=(x1,y1),blend– коэффициент сглаживания линии
pygame.draw.aaline(Surface, color, start, end, blend =1)
3. Рисование ломаной линии, pointlist = ((x1,y1),(x2,y2),(x3,y4)) – координаты точек связанных отрезков, сlosed = (True или False) указывает замыкать ли крайние точки.
pygame.draw.lines(Surface, color, closed, pointlist, width =1)
pygame.draw.ellipse(Surface, color, Rect, width=0)
pygame.draw.arc(Surface, color, Rect, start_angle, stop_angle, width =1)
start_angle– начальный угол stop_angle– конечный угол рисования, задаются в радианах
Алгоритм движения можно записать следующим образом.
В игровом цикле:
screen.fill(green)
x += 1
у += 1
здесь x += 1 и у += 1 означает, что координаты круга изменяются на 1 пиксель на каждом игровом цикле.
pygame.draw.circle(screen, blue, (x, y), r)
pygame.display.flip()
Для игрового цикла мы использовали частоту 60 кадров в секунду. Следовательно, за 1 секунду центр круга сместиться на 60 пикселей по оси х, по оси y и через несколько секунд исчезнет за границей окна, поскольку главный цикл обновляет экран с частотой 60 кадров в секунду , постоянно перерисовывая его содержимое .
Отталкивание круга от границ окна
В PyGame используется экранная система координат – это координатная система, заданная на экранной плоскости. Две ее оси параллельны сторонам экрана, ось OX направлена слева на право, OY – снизу вверх.
Запишем условия не выхода круга за границы игрового экрана. Введем переменные для скорости перемещения круга: dx, dy – количество пикселей, на которое смещается центр круга по оси x и оси y за один кадр
x += dx
y += dy
В этом случае код контроля движения круга внутри игрового окна можно записать следующим образом:
if y + r > H or y-r < 0:
dy = dy * -1
if x + r > W or x-r < 0:
dx = dx * -1
Полный листинг программы
# Импорт Pygame
import pygame
# инициализация модулей Pygame
pygame.init()
# задаем основные параметры
W = 600 # ширина окна
H = 400 # высота окна
r = 20 # радиус круга
x = 300 # координата x центра круга
y = 200 # координата y центра круга
# задаем цвета
black = (0, 0, 0)
white = (255, 255, 255)
green = (0, 255, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
dv = 3 # скорость перемещения
dx = dv
dy = dv
# Создание окна, шириной 600 и высотой 400 пикселей
screen = pygame.display.set_mode((W, H))
# Задание заголовка окна
pygame.display.set_caption("Игровое окно")
# устанавливаем цвет игрового окна
screen.fill(green)
# обновление основного окна
pygame.display.flip()
# задаем частоту кадров - 60 кадров в секунду
FPS = 60
# подключаем часы
clock = pygame.time.Clock()
# Игровой цикл событий
# Оставаться в цикле, пока пользователь не нажмёт на кнопку закрытия окна
running = True
while running:
for event in pygame.event.get():
# закрытие окна
if event.type == pygame.QUIT:
running = False
x += dx
y += dy
if y + r > H or y-r < 0:
dy = dy * -1
if x + r > W or x-r < 0:
dx = dx * -1
# очисщаем содержимое всего игрового окна
screen.fill(green)
# рисуем круг в памяти компьютера
pygame.draw.circle(screen, blue, (x, y), r)
# отображаем все игровое окно на экран
pygame.display.flip()
# устанавливаем автоматический контроль кадров
clock.tick(FPS)
# Завершение Pygame, освобождаем ресурсы
pygame.quit()
Есть два основных способа работы с клавиатурой, мышью.
Первый способ
Данный способ основан на обработке очереди событий. Все события в момент появления добавляются в очередь событий. Каждый раз, когда нажимается или отпускается клавиша или кнопка мыши или перемещается мышь, событие добавляется в очередь событий.
Очередь работает по принципу стека «последний вошел - первый вышел», поэтому если прочитать событие из этой очереди оно будет удалено из очереди. Для чтения очереди используется метод pygame.event.get(), который возвращает список всех событий.
Если вызывать метод pygame.event.get() в игровом цикле, то мы получим список событий для каждого кадра. Каждый элемент списка это объект типа Event, который имеет свойство type. Способ обработки этих событий зависит от типа самого события. Тип события можно проверить, прочитав поле event.type.
События клавиатуры могут иметь два типа
Если вы нажали клавишу и отпустили, то в очередь событий будут записаны оба.
События мыши могут иметь четыре типа
Второй способ
Данный способ основан на работе с модулем клавиатуры и модулем мыши
pygame.key, pygame.mouse
Ознакомится с модулями можно здесь:
https://www.pygame.org/docs/ref/key.html
https://www.pygame.org/docs/ref/mouse.html
В качестве примера рассмотрим фрагмент программы, в котором при нажатии на курсорные клавиши будет перемещаться прямоугольник на экране
Первый способ
Обработка событий клавиатуры с помощью очереди сообщений
С помощью цикла for проходим по списку
for event in pygame.event.get():
# закрытие окна
if event.type == pygame.QUIT:
running = False
# обработка клавиш
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx = -5
elif event.key == pygame.K_RIGHT:
dx = +5
if event.key == pygame.K_UP:
dy = -5
elif event.key == pygame.K_DOWN:
dy = +5
Каждое возникающее событие последовательно извлекаем из цепочки событий, и сравниваем с типом события pygame.KEYDOWN, если тип события равен pygame.KEYDOWN, то у этого типа есть атрибут event.key . Теперь сравниваем этот атрибут со значениями курсорных клавиш K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN. Если получили совпадение с одной из клавиш, то задаем смещение прямоугольника с помощью переменных dx или dy.
Далее определяем новые координаты для рисования прямоугольника
x += dx
y += dy
dx = dy = 0
и рисуем прямоугольник в блоке формирования кадра
pygame.draw.rect(screen, color, (x, y, 75, 50))
Второй способ
Обработка событий клавиатуры помощью с модуля клавиатуры pygame.key
Проверить состояние клавиш можно с помощью функции
pygame.key.get_pressed()
которая возвращает кортеж двоичных значений. Индекс каждого значения соответствует своей клавиатурной константе. Само значение равно 1, если клавиша нажата, и 0 – если не нажата.
В программном блоке формирования отдельного кадра получаем список значений и сравниваем с клавиатурными константами наших клавиш.
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
dx = -5
if keys[pygame.K_RIGHT]:
dx = 5
if keys[pygame.K_UP]:
dy = -5
if keys[pygame.K_DOWN]:
dy = 5
далее рисуем прямоугольник
События мыши могут иметь три типа
event.type == pygame.MOUSEBUTTONDOWN – кнопка мыши нажата
event.type == pygame.MOUSEBUTTONUP – кнопка мыши отпущена
event.type == pygame.MOUSEMOTION – курсор мыши перемещается
Событие |
атрибуты |
MOUSEBUTTONDOWN |
pos, button |
MOUSEBUTTONUP |
pos, button |
MOUSEMOTION |
pos, rel, buttons |
где
pos - кортеж, содержащий координаты мыши (x,y)
button - значение чисел для кнопок: 1 – левая, 2 – средняя, 3 -правая
buttons - кортеж, содержащий состояние трех кнопок мыши ( левая, средняя, правая)
rel - кортеж, содержащий относительное смещение по осям (dx, dy)
Модуль pyagme.image предоставляет методы загрузки и сохранения изображений
image = pygame.image.load(filename).convert()
filename – путь к файлу изображения
image – дополнительная поверхность,которая содержит изображение из файловой системы.
В последующем содержимое дополнительной поверхности image необходимо будет перенести
на поверхность основного экрана
convert() – эта функция оптимизирует изображение по отношению
к основной поврхности
Поддерживаются следующие типы изображений: bmp, jpg, png, GIF и другие
Если поверхность image была создана на базе изображения с альфа-каналом, то вместо convert() надо использовать метод convert_alpha()
image = pygame.image.load(filename).convert_alpha()
Если у изображения нет прозрачного слоя, но он необходим, то следует воспользоваться методом set_colorkey() класса Surface:
image = pygame.image.load(filename).convert()
image.set_colorkey((255, 255, 255))
Все пиксели, цвет которых совпадает с переданным значением в set_colorkey(), станут прозрачными.
Прмиер
Изображение ограничивается поугольником без прозрачного слоя, поэтому мы видим вокруг шара белый фон, но нам нужно изображение только шара без белого фона. Сделаем фон прозрачным. | Метод image.set_colorkey((255, 255, 255)) делает все пиксели белого фона прозрачными, не отображая его на основной поверхности. |
Вывод на экран
Для отображения изображения мы используем функцию blit(), которая отображает содержимое дополнительной поверхности image на поверхности основного экрана screen.
screen.blit(image, (x, y))
pygame.display.flip()
где
mage - дополнительная поверхность, которая содержит изображение из файловой системы
(x, y) - координаты размещения верхнего левого угла дополнительной поверхности в координатной
системе основной поверхности
flip() - функция обновляет содержимое основного экрана, используя механизм двойной буферизации.
Спрайт – это графический объект анимации, обладающий свойством движения, которое меняет его положение по отношению к другим объектам анимации.
Основными свойствами спрайтов являются:
image — изображение спрайта
rect — прямоугольная область, заключающая в себя спрайт.
В качестве изображения может выступать растровое изображение, например рисунок, созданный при помощи функций класса Draw.
Каждый спрайт имеет назначенный ему прямоугольник – объект Rect, который представляет границы спрайта: длину, ширину. Этот прямоугольник вокруг спрайта не виден и используется для обнаружения столкновений. Объект Rect имеет несколько функций, которые позволяют достаточно легко определить столкновения спрайтов.
Класс Sprite предназначен для использования в качестве базового класса для различных типов объектов в игре. Базовый класс спрайтов может рисовать спрайты, работать с группой спрайтов, имеет функции для определения столкно вений.
На основе базового класса создается пользовательский класс, который будет содержать те же атрибуты и методы, что и базовый класс, но при этом мы можем расширять его функциональность через добавление новых методов и атрибутов.
Пример. Создадим класс MyBall, который описывает шарик, родителем которого будет класс Sprite
class MyBall(pygame.sprite.Sprite):
def __init__(self, location, speed, filename):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load(filename).convert_alpha()
self.image.set_colorkey((WHITE))
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = location
self.speed = speed
Пояснения.
class MyBall означает, что мы определяем новый класс, родителем нашего класса является базовый класс Sprite.Pygame.
class MyBall(pygame.sprite.Sprite):
Второй строчкой является конструктор нашего класса
def __init__(self, location, speed, filename):
где
self – обязательный параметр, который должен быть указан первым. Он будет содержать ссылку на экземпляр класса,
когда будет создан объект – наш шарик
location – положение шарика– координаты [x,y]
speed – скорость шарика [vx, vy]
filename – путь к файлу изображения
В третьей строке вызывается конструктор родительского класса
pygame.sprite.Sprite.__init__(self)
Ему передается ссылка экземпляра нашего класса. С этого момента свойства и методы базового класса, у нас это класс Sprite, становиться доступны нашему классу.
В строках
self.image = pygame.image.load(filename).convert_alpha()
self.image.set_colorkey((WHITE))
загружается изображение мяча.
Далее определяются размеры прямоугольника, который определяет границы спрайта: width – ширину и height - высоту
self.rect = self.image.get_rect()
Объект self.rect представлен в формате[x, y, width, height], где x и y представляют собой верхний левый угол прямоугольника. Используя self.rect мы можем поместить спрайт туда, куда хотим. Установим начальные координаты спрайта:
self.rect.left, self.rect.top = location
Далее задается начальная скорость спрайта
self.speed = speed
Одна из многих важных тем в разработке игр это обнаружение столкновений. Рассмотрим алгоритмы обработки столкновений на примере двух спрайтов. В основе алгоритмов обработки столкновений лежит класс Rect. Экземпляры этого класса представляют собой прямоугольные области. Они не имеют графического представления в окне игры, но имеют методы для обнаружения столкновений: если два или более прямоугольных объектов пересекаются друг с другом или находяться в контакте, то это и есть столкновение. Эти методы используются в методах определения столкновения спрайтов.
Вот некоторые основные методы класса Rect:
collidepoint(x, y) – проверка попадания точки в прямоугольник;
colliderect(Rect) – проверка пересечения двух прямоугольников;
collidelist(list) – проверка пересечения хотя бы с одним прямоугольником из списка прямоугольников list;
collidelistall(list) – проверка пересечения со всеми прямоугольниками из списка прямоугольников list.
Полный их список и описание можно посмотреть на странице официальной документации: https://www.pygame.org/docs/ref/rect.html
Обнаружение столкновений между двумя спрайтами
Обнаружение столкновений между двумя спрайтами sprite1, sprite2 выполняется методом collide_rect(sprite1, sprite2), в котором используется функцию проверки пересечения двух прямоугольников colliderect(Rect)
hit = pygame.sprite.collide_rect(sprite1, sprite2)
метод возвращает логическое значение hit: True – столкновение или соприкосновение произошло, False в противном случае.
Вот пример. На рисунке два спрайта. Один из спрайтов может перемещаться с помощью клавиш управления курсором, поэтому мы легко можем моделировать столкновения и выполнить тестирования программного кода столкновения спрайтов.
Столкновения нет | Столкновение произошло. При столкновении меняем цвет фона окна. |
Напишем программу, которая демонтсрирует столкновения спрайтов.
Создание спрайтов
Создадим два спрайта. Для простоты изложения создавать объекты будем непосредственно от класса Sprite.
sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((LEN, LEN))
sprite1.image.fill((WHITE))
sprite1.rect = sprite1.image.get_rect(center = (100, 100))
Пояснения.
В первой строке вызываем конструктор базового класса Sprite. Поскольку у каждого спрайта обязательно должны быть свойства image и rect, то строка
sprite1.image = pygame.Surface((LEN, LEN))
создает дополнительную поверхность для отображения спрайта шириной и высотой LEN. Далее эту поверхность заливаем цветом WHITE. Используя метод get_rect() получаем размеры прямоугольника.
Прямоугольник представляет размеры спрайта и содержит атрибуты x и y. Рисование спрайта будет там, куда указывают атрибуты x и y. Устанавливанием координаты x = 100, y = 100 - это центра прямоугольника center = (100, 100) в основном окне
По аналогии создаем второй спрайт
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((LEN, LEN))
sprite2.image.fill((BLUE))
sprite2.rect = sprite2.image.get_rect(center = (200, 200))
Столкновение нескольких спрайтов
Большое преимущество работы со спрайтами - возможность с группой спрайтов. Вместо того, чтобы проверять каждый объект отдельно и смотреть, было ли столкновение, возможно просто проверить было ли столкновение в группе спрайтов. Кроме того, возможно автоматическое обновление и перерисовка каждого объекта на основном экране.
Создадим группу спрайтов
all_sprites_group = pygame.sprite.Group([sprite1, sprite2])
Автоматическое обновление группы выполняется методом
all_sprites_group.draw(screen)
Перемещение спрайта в основном экране будем выполнять с помощью клавиатуры
Вот полный код программы
import pygameWHITE = (255, 255, 255)
BLUE = (0, 0, 255)
GREEN = (0,255,0)
BG_COLOR = (255,127,127)
W = 600
H = 300
LEN = 40
FPS = 60
pygame.init()
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("Test Столкновение спрайтов")
screen.fill((GREEN))
pygame.display.flip()
clock = pygame.time.Clock()sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((LEN, LEN))
sprite1.image.fill((WHITE))
sprite1.rect = sprite1.image.get_rect(center = (100, 100))
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((LEN, LEN))
sprite2.image.fill((BLUE))
sprite2.rect = sprite2.image.get_rect(center = (200, 200))
all_sprites_group = pygame.sprite.Group([sprite1, sprite2])
running = True
dx=0
dy=0
while running :
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
dx = -5
if keys[pygame.K_RIGHT]:
dx = 5
if keys[pygame.K_UP]:
dy = -5
if keys[pygame.K_DOWN]:
dy = 5
sprite1.rect.x += dx
sprite1.rect.y += dy
dx = dy = 0
hit = pygame.sprite.collide_rect(sprite1, sprite2)
if hit :
bg_color = (255, 127, 127)
else :
bg_color = (GREEN)
screen.fill(bg_color)
all_sprites_group.draw(screen)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
Модуль pygame.time содержит функции для взаимодействия с игровым времени и его управлением.
Функция pygame.time.get_ticks()
Эта функция возвращает время, прошедшее с момента вызова pygame.init, но до инициализации pygame.init она всегда будет возвращать 0.
class pygame.time.Clock
Этот класс позволит отслеживать количество времени или управлять частотой кадров. Здесь несколько шагов
Создаем объект
clock = pygame.time.Clock()
Функция tick() возвращает время, прошедшее со времени предыдущего вызова в миллисекундах
time_tick = clock.tick()
Вызов выпоолняется в цикле обработки кадров.
Функцию clock.tick() с числовым параметром number
clock.tick(number),
выполняет автоматический контроль заданной частоты кадров. Вызов выпоолняется в цикле обработки кадров.
Функция pygame.time.Clock.get_time()
Эта функция возращает время в миллисекундах, прошедшее с момента последнего вызова pygame.time.Clock.get_time()
Функция pygame.time.wait()— приостанавливает программу на некоторое время, в миллисекундах;
pygame.time.wait(100)
100 — время в миллисекундах, на которое будет приостановлено выполнение программы.
Функция pygame.time.delay()— приостановить программу на некоторое время, в миллисекундах;
pygame.time.delay(100)
100 — время в миллисекундах, на которое будет приостановлено выполнение программы.
Pyinstaller - программа, которая конвертирует программу на Python в самостоятельный исполнимый файл, работающий без установки среды выполнения Python под Windows, Linux.
Установка
PyInstaller — обычный пакет python. Устанавливать будем для среды программирования PyCharm. Переходим в настройки File->setting- > имя вашего проекта-> interpretator. Смотрим наличие пакета pyinstaller. Если нет, жмем «+». Открывается новое окно
Вписываем имя пакета – pyinstaller и жмем «install Package». Ждем некоторое время. появляется рядом с кнопкой «install Package» сообщение о успешной инсталляции.
Пакет будет установлен в папку, где установлен Python. У меня это C:\Program Files\Python38\Scripts.
Создание exe файла
В папку для создания exe файла переносим Python-файл, который будет конвертирован в exe файл, а также изображения, которые должны иметь туже структуру подчиненности, что и в python проекте. Обычно файлы изображений хранятся в папке images. Например, D:\exe – папка для создания exe файла. Сюда помешаем файл Arkanoid.py. Имя python файла не должно содержать пробелов. D:\exe\images – папка, в которой находится изображение pong.png. В папке для создания exe файла запускаем от имени администратора командную строку (cmd)
Переходим в папку D:\exe>
Записываем код
D:\exe>pyinstaller.exe --onefile --windowed Arkanoid.py
После успешной работы программы вы найдете две папки: dist и build. В папке dist и находится наше приложение: Arkanoid.exe. Впоследствии папку build можно спокойно удалить, она не влияет на работоспособность приложения. Если запустить наше приложение Arkanoid.exe в папке dist получим ошибку.
Причина ошибки – не найдено изображение, поэтому переносим наше приложение из D:\exe\dist в нашу корневую папку D:\exe и запускаем. Ошибок нет.