PyGame: полупрозрачные спрайты с пикселем alpha
Можно ли отображать поверхности PyGame с управляемой альфой? Я хотел бы взять поверхность с собственной альфа-пикселью и отобразить ее с переменным уровнем прозрачности, не затрагивая поверхностные данные, и сохранить прозрачность без изменений, т.е. Объекты на поверхности будут сохранять свои формы, но их "содержимое" становится более или менее полупрозрачный.
Другими словами, я хочу объединить альфа-пиксель из исходного изображения с альфа-поверхностью, рассчитанной во время выполнения.
Ответы
Ответ 1
После проверки документации PyGame и SDL я пришел к выводу, что то, что я просил, не выполнялось в PyGame, используя стандартные функции.
SDL docs заявляют, что альфа-альфа-альфа и альфа-альфа не могут быть объединены с первыми, которые всегда имеют приоритет. Единственный способ добиться эффекта, который я хочу, - написать код, который обновляет пиксельные значения альфа-данных поверхности источника до blit.
Ответ 2
Да, вы можете. документация класса Surface объясняет, как это сделать. Это сводится только к двум случаям:
Либо вы устанавливаете флаг во время создания объекта Surface:
s = pygame.Surface((16, 16), flags=pygame.SRCALPHA)
Или вы даете альфа-канал поверхности, которая еще не имеет этого:
s = pygame.image.load('spam.png')
s.convert_alpha()
Документация модуля pygame.image гласит, что применение PNG с прозрачностью требует применения convert_alpha.
Если вы хотите, вы можете изменить альфа-значение каждого пикселя с помощью рисования модулей и всплытия. При указании цвета используйте кортеж из четырех целых чисел: (красный, зеленый, синий, альфа). Параметр альфа составляет от 0 (полностью прозрачный) до 255 (полностью непрозрачный).
import pygame
pygame.init()
screen = pygame.display.set_mode((320, 200))
screen.fill((200, 100, 200))
s = pygame.Surface((64, 64), flags=pygame.SRCALPHA)
for i in range(64):
pygame.draw.line(s, (0, 0, 0, i*4), (0, i), (64, i))
screen.blit(s, (50, 30))
pygame.display.flip()
Ответ 3
Документация Pygame говорит, что вы не можете комбинировать альфа-поверхность с альфа-пикселем, но если вы используете Pygame 1.8. 1 или новее, вы можете обойти это, используя параметр special_flags
для .blit()
.
Вот как я это сделал:
# Load an image with per-pixel alpha
s = pygame.image.load('spam.png')
s.convert_alpha()
# Simulate s.set_alpha(alpha)
alpha_img = pygame.Surface(s.get_rect().size, pygame.SRCALPHA)
alpha_img.fill((255, 255, 255, alpha))
s.blit(alpha_img, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
Как это работает, нужно создать вторую поверхность того же размера, что и первая, и включить ее в первый раз, используя умножение RGBA. Благодаря тому, что компоненты R, G и B второго изображения равны 255, умножение не повлияет на цвет изображения, но будет масштабировать альфа-канал по данному альфа-коэффициенту.
Обратите внимание, что вышеописанный метод отличается от вызова set_alpha()
тем, что set_alpha()
можно отменить, вызвав set_alpha(255)
. Если вы используете метод выше, это приведет к изменению пиксельных альфов каждого пикселя, поэтому процесс не может быть просто отменен.
Ответ 4
Если ваше входное изображение имеет пиксельную альфа-версию, но использует только один бит для прозрачности (например,.png спрайты с прозрачным фоном или текстом), вы можете преобразовать прозрачный фон в фона colorkey-alpha довольно легко, а затем используйте set_alpha() для смешивания всей текстуры на что угодно.
Это быстрая и грязная вспомогательная функция, которую я использовал для угасания текстовых эффектов и других вещей:
def convert_to_colorkey_alpha(surf, colorkey=pygame.color.Color("magenta")):
newsurf = surface.Surface(surf.get_size())
newsurf.fill(colorkey)
newsurf.blit(surf, (0, 0))
newsurf.set_colorkey(colorkey)
return newsurf
Несколько других трюков, которые могут решить эту проблему, могут быть:
- Выполнение редактирования на пиксель для изменения альфа-канала перед blitting
- Нанесите на поверхность исходного изображения белую или черную заполненную полупрозрачную поверхность с особыми_флагами = BLEND_RGBA_MULT или BLEND_RGBA_SUB.