Инициализация
Для работы с pygame следует инициализировать необходимые модули, проще всего инициализировать все:
pygame.init()
Существует несколько вариантов инициализации окна pygame:
Создание рабочей области окна
Создание окна требуемого размера.
screen = pygame.display.set_mode((320, 240))
Создание окна исходя из размеров фона
background = pygame.image.load('media/img_backgournd.jpg')
screen = pygame.display.set_mode(background.get_size())
screen.blit(background, (0, 0))
Работа с прямоугольниками и текстом
Прямоугольники служат для выбора части поверхностей, для получения размеров областей и др. Конструктор простейшего прямоугольника выглядит так:
In [1]: import pygame
In [2]: r = pygame.Rect(0, 0, 100, 50) # 100х50 px
In [3]: r
Out[3]: <rect(0, 0, 100, 50)>
У объекта класса Rect есть множество методов, названия говорят за себя:
['bottom', 'bottomleft', 'bottomright', 'center', 'centerx', 'centery', 'clamp', 'clamp_ip', 'clip', 'collidedict', 'collidedictall',
'collidelist', 'collidelistall', 'collidepoint', 'colliderect', 'contains', 'copy', 'fit', 'h', 'height', 'inflate', 'inflate_ip',
'left', 'midbottom', 'midleft', 'midright', 'midtop', 'move', 'move_ip', 'normalize', 'right', 'size', 'top', 'topleft',
'topright', 'union', 'union_ip', 'unionall', 'unionall_ip', 'w', 'width', 'x', 'y']
Из этих атрибутов я выделю centerx и centery:
font = pygame.font.Font('media/presentum.ttf', 30) # задание шрифта и размера
text_img = font.render('Строка для рендеринга', True, 0xFF0000) # строка, сглаживание, цвет
text_pos = text_img.get_rect() # получаем пр-к нашего текста
text_pos.centerx = r.centerx # центрируем позицию нашего текста по середине контейнера r
text_pos.centery = r.centery # центрируем позицию нашего текста по середине контейнера r
screen.blit(text_img, text_pos) # копирование текста на экран
pygame.display.update() # обновление экрана
Прозрачность (Альфа-канал)
Для загрузки изображения из png файла с альфа каналом следует использовать следующую строчку:
pic_with_alpha = pygame.image.load('media/src_with_alpha.png').convert_alpha()
Для получения изображения с прозрачным фоном мы редактируем png, удаляем фон, затем сохраняем файл без сохранения цвета прозрачности.
Создание прозрачности для сложных поверхностей, полигонов и прочего
Моё решение было следующим:
Немного меняю исходное изображение для того чтобы чёрный цвет не превратился в прозрачный, затем накладываю чёрную маску на изображение, говорю, что чёрный цвет становится прозрачным.
# Берём изображение, подгоняем под размер
img = pygame.image.load('media/src.png')
img_s = pygame.transform.scale(img, (204, 142))
# нужно заместить черный в исходном изображении на +1, иначе станет прозрачным
pa_img_s = pygame.PixelArray(img_s) # создаем массив для замены цвета
pa_img_s.replace((0, 0, 0), (0, 0, 1)) # заменяем цвет
img_s = pa_img_s.surface
del pa_img_s # удаляем, иначе блочит поверхность
s = pygame.Surface((240, 146)) # поверхность для преобразований
pat = pygame.image.load('media/pattern.png').convert_alpha() # накладываем чёрный шаблон, с прозрачными вырезами
s.blit(img_s, (0, 0)) # копируем наше изображение с "немного не чёрным цветом" на поверхность для преобразований
s.blit(pat, (0, 0)) # сверху накладываем (копируем) маску
s.set_colorkey(pygame.Color('black')) # устанавливаем чёрный цвет прозрачным
Выделение части поверхности
Мой стандартный use-case использования части поверхности (subsurface) — это копирование части фона для создания эффектов движения, анимации:
- копируем часть фона, на котором будет происходить действие
- копируем изменение
- ждем
- снова копируем фон.
# задаём фон
background = pygame.image.load('media/img_backgournd.jpg')
screen = pygame.display.set_mode(background.get_size())
screen.blit(background, (0, 0))
r = pygame.Rect(0, 0, 300, 400) # размеры пр-ка, на котором будет производиться действие
ball = pygame.image.load('media/ball.png') # загружаем картинку
bg = background.subsurface(r) # создаём копию фона
x_pos_left = 0
y_pos = 0
c = 10
while c:
x_pos_left += 10
screen.blit(bg, (0, 0)) # копируем фон
screen.blit(ball, (x_pos_left, y_pos)) # копируем картинку поверх
c -= 1
pygame.display.update(r) # обновлять не обязательно весь экран, можно определённую часть.
sleep(0.08) # задержка, можно использовать pygame-овскую
Работа с событиями (events)
Данный вопрос рассмотрен везде, но не упомянуть его нельзя :)
``` python простейший выход из приложения по кнопке bRunning = True
while bRunning:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
bRunning = False
exit(0) # к примеру
А это пример кастомного события
``` python
# coding=utf-8
import pygame
COUNTER = pygame.USEREVENT + 5 # 24+5 = 29
class Counter():
def __init__(self, coord, screen, background, counter, up):
self.current_sub_timer = 0
self.coord = coord
self.screen = screen
self.counter = counter # сколько секунд считать
self.up = up # если 1, возрастает счётчик, 0, убывает
rendtext = self.get_colored_text(str(30), (255, 0, 0))
r = rendtext.get_rect() # взяли 30 и увеличили размер пр-ка
self.bg = background.subsurface(r.move(self.coord)) # сдвинули пр-к и взяли фон
def get_colored_text(self, text, color):
bigfont = pygame.font.Font('presentum.ttf', 60)
rendtext = bigfont.render(text, True, color)
return rendtext
def get_next(self):
"""
возвращет 0 если таймер оттикал
"""
cur_second = self.current_sub_timer / 10
if self.current_sub_timer / 10 == self.counter:
return 0
else:
if self.up:
new_val = cur_second + 1
else:
new_val = self.counter - cur_second
rendtext = self.get_colored_text(str(new_val), (255, 0, 0))
self.screen.blit(self.bg, self.coord)
self.screen.blit(rendtext, self.coord)
pygame.display.update()
self.current_sub_timer += 1
return 1
def main():
pygame.init()
screen = pygame.display.set_mode((1024, 768))
background = pygame.image.load('media/screen3.jpg')
screen.blit(background,(0, 0))
pygame.display.update()
pygame.time.set_timer(COUNTER, 100) # запускаем генерацию even-тов каждые 100мс
counter = Counter((350, 300), screen, background, 5, 0) # передаём где вывести счётчик,
# наш экран, фон, сколько секунд считать, 0 - убывает
b_running = True
while b_running:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
b_running = False
elif event.type == COUNTER:
if not counter.get_next():
pygame.time.set_timer(COUNTER, 0) # значит оттикал таймер, нужно остановить генерацию событий
if __name__ == '__main__':
main()