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

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

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"))

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

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

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

Так что, если я правильно понимаю, вопрос был - можно ли использовать битовые маски для блиттинга. Ответ и да и нет. 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)

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

Другие вопросы по тегам