Pygame - есть ли способ только блит или обновить в маске
Есть ли способ в Pygame, чтобы что-то перетянуть на экран внутри маски. Например: если бы у вас была маска, в которой все биты были установлены в 1, кроме верхнего угла и полностью черного изображения, без изменения изображения, могли бы вы оставить верхний левый угол (такой же, как у маски) чистым? Поможет только обновление маски (а не прямоугольника).
2 ответа
Хорошо, если я правильно понимаю ваш вопрос, дело в том, BLEND_RGBA_MULT
флаг.
Я решил проверить это для себя, потому что мне было любопытно. Я начал с этого изображения:
Я сделал изображение с белым, где я хотел, чтобы изображение показывалось, и прозрачность, где я хотел, чтобы оно маскировалось. Я даже дал ему различные уровни прозрачности, чтобы посмотреть, смогу ли я получить нечеткую маскировку.
^^^ Вы, вероятно, не можете видеть изображение, потому что оно белое на прозрачном, но оно есть. Вы можете просто щелкнуть правой кнопкой мыши и скачать его.
Я загрузил два изображения, убедившись, что использовать 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"))
Это дает такой результат:
Теперь я хочу использовать это в игре!
Так что, если я правильно понимаю, вопрос был - можно ли использовать битовые маски для блиттинга. Ответ и да и нет. AFAIK, в pygame нет поддержки 1-битных масок, это означает, что вы должны использовать 32-битный RGBA (флаг SRCALPHA) для поверхности источника, чтобы блиц с прозрачностью, и в этом случае вы используете 8-битную маску = 256 степеней прозрачности за пиксель, и это описано в предыдущем ответе. Другой вариант - использовать блики "colorkey". В этом случае это больше похоже на 1-битную маску и используется со стандартными поверхностями RGB с 24 битами на пиксель. Вы просто устанавливаете, какой цвет на исходной поверхности вы не хотите писать по назначению. Смотрите 'Surface.set_colorkey' в документации. Проблема с методом colorkey заключается в том, что вы можете случайно получить несколько пикселей в источнике, которые имеют тот же цвет, что и colorkey, но которые вы все еще хотите нарисовать. Так что вы должны быть осторожны. Я лично использую поверхности RGBA для маскировки, они более мощные, но почти всегда мне не нужны 8-битные, 1-битной маски будет достаточно. Так что мне кажется странным, что нет поддержки для каждой битовой маски. То же самое и с переворотом в буфере - вы можете описать области экранного буфера для обновления только списком прямоугольников. Более гибким и понятным было бы использование битовых масок, но на самом деле это невозможно. Возможно, преобразование битовой маски в список прямоугольников - это путь, но я не пробовал. Третий вариант - не использовать поверхность Pygame и использовать Numpy для ваших данных, а затем использовать блики массива:
pygame.surfarray.blit_array(Destination_surface, my_array)
Тогда вы можете делать с данными все, что захотите, но это уже другая история.