Pygame инициализация, работа с прямоугольниками, прозрачностью

Инициализация

Для работы с 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()

Anshik в разное Вт. 22 Октябрь 2013. Tags: python,


© Anshik 2012-2015