Pygame - есть ли способ только блицировать или обновлять в маске

Есть ли способ в pygame вывести что-то на экран внутри маски. Например: если бы у вас была маска, в которой все биты были установлены на 1, кроме верхнего левого угла и полностью черного изображения, без изменения изображения, могли бы вы оставить левый верхний угол (такой же, как маска) чистым? Поможет только обновление маски (а не прямоугольника).


person user1912132    schedule 02.06.2013    source источник
comment
Изучите попиксельные альфа-каналы: pygame.org/docs/ref/surface.html Я сам ничего о них не знаю, но документация, похоже, подсказывает, как это сделать   -  person ahuff44    schedule 02.06.2013
comment
Спасибо, я попробую это.   -  person user1912132    schedule 02.06.2013
comment
Вы просите спрайты с прозрачностью, или переменную альфу на пиксель, или обновляете только крошечную часть экрана, которая изменилась?   -  person ninMonkey    schedule 02.06.2013
comment
Больше обновления дисплея маской, а не ректом.   -  person user1912132    schedule 03.06.2013


Ответы (2)


Хорошо, если я правильно понимаю ваш вопрос, хитрость заключается в флаге BLEND_RGBA_MULT.

Я решил проверить это на себе, потому что мне было любопытно. Я начал с этого изображения:

320x240 листьев

Я сделал изображение с белым, где я хотел, чтобы изображение было видно, и прозрачностью, где я хотел, чтобы оно было замаскировано. Я даже придал ему различные уровни прозрачности, чтобы увидеть, смогу ли я получить нечеткую маскировку.

Нечеткая круглая маска

^^^ Возможно, вы не видите изображение, потому что оно белое на прозрачном, но оно есть. Вы можете просто щелкнуть правой кнопкой мыши и скачать его.

Я загрузил два изображения, обязательно используя convert_alpha():

background = pygame.image.load("leaves.png").convert_alpha()
mask = pygame.image.load("mask-fuzzy.png").convert_alpha()

Затем, чтобы замаскировать изображение, я сделал копию маскируемого изображения,

masked = background.copy()

...Я скопировал маску на эту копию, используя BLEND_RGBA_MULT,

masked.blit(mask, (0, 0), None, pygame.BLEND_RGBA_MULT)

...и я нарисовал это на экране.

display.blit(masked, (0, 0))

Конечно же, это сработало:

результат

Вот полный код, который я использовал.

import pygame
from pygame.locals import *

pygame.init()
display = pygame.display.set_mode((320, 240))

background = pygame.image.load("leaves.png").convert_alpha()
mask = pygame.image.load("mask-fuzzy.png").convert_alpha()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    # draw
    display.fill(Color(255, 0, 255))
    masked = background.copy()
    masked.blit(mask, (0, 0), None, pygame.BLEND_RGBA_MULT)
    display.blit(masked, (0, 0))
    pygame.display.flip()

Если вам нужна переменная маска, вы можете попробовать вручную отредактировать поверхность и использовать ее в качестве маски.

Редактировать: Вот пример создания маски путем редактирования поверхности:

mask = pygame.Surface((320, 240), pygame.SRCALPHA)
for y in range(0, 240):
    for x in range(0, 320):
        if (x/16 + y/16) % 2 == 0:
            mask.set_at((x, y), Color("white"))

Это дает такой результат:

результат маски шахматной доски

Теперь я хочу использовать это в игре!

person nkorth    schedule 05.06.2013
comment
Большое спасибо, я еще не проверял это, но это определенно то, что я искал :) - person user1912132; 08.06.2013

Итак, если я правильно понимаю, вопрос был - можно ли использовать битовые маски для блитинга. Ответ да, и нет. Насколько я знаю, в pygame нет поддержки 1-битных масок, это означает, что вы должны использовать 32-битный RGBA (флаг SRCALPHA), чтобы исходная поверхность блистала прозрачностью, и в этом случае вы используете 8-битную маску = 256 степеней прозрачности на пиксель, и это описано в предыдущем ответе. Другой вариант — использовать блиттинг «colorkey». В данном случае она больше похожа на 1-битную маску и используется со стандартными 24-битными RGB-поверхностями. Вы просто устанавливаете, какой цвет исходной поверхности вы не хотите записывать в пункт назначения. См. «Surface.set_colorkey» в документации. Однако проблема с методом colorkey заключается в том, что вы можете случайно получить несколько пикселей в исходном коде, которые имеют тот же цвет, что и colorkey, но которые вы все еще хотите рисовать. Так что вы должны быть осторожны. Я лично использую для маскирования поверхности RGBA, это мощнее, но почти всегда мне не нужны 8-битные, достаточно 1-битной маски. Так что мне кажется немного странным, что нет поддержки блитинга по битовой маске. То же самое и с переключением буфера — вы можете описать области экранного буфера для обновления только списком прямоугольников. Более гибким и простым было бы использование битовых масок, но это тоже невозможно. Вероятно, нужно преобразовать битовую маску в список прямоугольников, но я не пробовал. Третий вариант - не использовать поверхность pygame и использовать Numpy для ваших данных, а затем использовать копирование массива:

pygame.surfarray.blit_array(Destination_surface, my_array)

Тогда вы можете делать со своими данными все, что захотите, но это уже другая история.

person Mikhail V    schedule 18.10.2014
comment
Спасибо, я решил проблему с другим ответом, но это все еще полезно :) - person user1912132; 04.07.2015