Проблема с прозрачностью фона изображения: pygame
Сейчас я работаю над простым репетитором по печатанию с использованием pygame. Моя проблема в том, что я использую изображение с белым фоном, waves1.png
, Теперь я указал, что я хочу, чтобы белый цвет был прозрачным на изображении (self.image.set_colorkey((255, 255, 255))
) и это для всего, кроме текстового блока. Когда волны пересекаются с text
объект, белый фон волн показывают в верхней части текста. Вы можете попробовать запустить это, если у вас есть pygame (за исключением изображения waves1.png).
import pygame
from pygame.locals import *
class TextSprite(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.wordList = ['words yes', 'hello', 'this is a sentence', 'this is another sentence'] # read directly from external file
self.pos = 0
self.wordNum = 0
self.update1()
def update1(self):
# Render the given word
self.image = pygame.font.Font(None, 36).render(self.wordList[self.wordNum], 1, (0, 0, 0))
# Render the correctly guessed letters
self.correct = pygame.font.Font(None, 36).render(self.wordList[self.wordNum][:self.pos], 1, (255, 0, 0))
# Copy correct letters onto given word
self.image.blit(self.correct, (0, 0))
self.rect = self.image.get_rect()
# set the center of the center the given word to the center of the screen
self.rect.center = pygame.display.get_surface().get_rect().center
def keyin(self, key):
word = self.wordList[self.wordNum]
letter = word[self.pos]
if letter == key:
self.pos = self.pos + 1
if self.pos == len(word):
self.reset()
self.update1()
def reset(self):
self.pos = 0
self.wordNum = self.wordNum + 1
self.update1()
class Waves(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, filename):
# Call the parent class (Sprite) constructor
pygame.sprite.Sprite.__init__(self)
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.image.load(filename).convert()
# makes any white in the image transparent
self.image.set_colorkey((255, 255, 255))
self.rect = self.image.get_rect()
# Decrease the y coordinate so the waves look like they're moving up
def update(self, text):
self.rect.y = self.rect.y - 6
if self.rect.y <= 200:
text.reset()
self.rect.y = 485
def main():
#I - Import and initialize
pygame.init()
#D - Display configuration
# The screen variable is a pygame Surface object
# Note that the set_mode() method creates a Surface object for you automatically
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Typing Game")
#E - Entities (just background for now)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255, 255, 255))
screen.blit(background, (0,0))
#A - Action (broken into ALTER steps)
#A - Assign values to key variables
clock = pygame.time.Clock()
keepGoing = True
# Collect the sprite in a list
all = pygame.sprite.RenderPlain()
waveList = pygame.sprite.RenderPlain()
text = TextSprite()
all.add(text)
waves = Waves("waves1.png")
waveList.add(waves)
waves.rect.x = 0
waves.rect.y = 485
#L - Set up main loop
while keepGoing:
#T - Timer to set frame rate
# Tick is a method in the Clock class that determines the maximum frame rate
clock.tick(30)
#E - Event handling
for event in pygame.event.get():
if event.type == QUIT:
keepGoing = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
keepGoing = False
else:
text.keyin(event.unicode)
# update position of waves
waves.update(text)
# clears screen
all.clear(screen, background)
# update screen
all.draw(screen)
waveList.clear(screen, background)
waveList.draw(screen)
# display.flip is a method that copies everything from the screen object to the actual visual display
pygame.display.flip()
pygame.quit ()
if __name__ == '__main__': main()
2 ответа
Отлично сработано! Вы на самом деле сделали все правильно, чтобы воспользоваться преимуществами прозрачности и цветового ключа (т. Е. Убедиться, что вызываете функцию convert на поверхности, убедитесь, что передали цвет в метод set_colorkey и т. Д.).
Проблема заключается в порядке вызовов для отрисовки и очистки ваших соответствующих групп спрайтов "all" и "waveList". После того, как вы отрендерили текстовые блоки, вызвав all.draw, вы следуете за ним, вызвав waveList.clear.
Вот проблема: после того, как вы нарисовали текстовые спрайты, вам не нужно очищать пространство под волновыми спрайтами, или это сотрет область, которая перекрывает уже нарисованные текстовые блоки.
Если вы хотите сделать это правильно, попробуйте сделать это в следующем порядке:
- waves.update ()
- all.clear (экран, фон)
- waveList.clear (экран, фон)
- all.draw (экран)
- waveList.draw (экран)
(проще говоря, просто переместите waveList.clear(screen,background) на строку чуть ниже all.clear(screen, background); это должно быть сделано)
Когда я работаю с группами спрайтов, я обычно пытаюсь сгруппировать их так, чтобы каждая группа спрайтов вызывала один и тот же метод в следующем порядке: очищает, обновляет, проверяет столкновения (если есть), рисует.
Это обычно обрабатывает вещи в правильном порядке. Тогда вам, возможно, все же придется обратить внимание на то, существует ли какое-либо наслоение спрайтов, но это уже другая история для другого дня.
Я не знаю, если это вариант для вас, но вы должны получить лучшие результаты с нативной альфа-прозрачностью png.
Если вы можете редактировать / воссоздать png самостоятельно, попробуйте использовать прозрачный фон.
Оттуда вы можете использовать convert_alpha() после загрузки изображения. (вместо использования цветовой клавиши)
http://pygame.org/docs/ref/surface.html
РЕДАКТИРОВАТЬ: еще один аспект, это то, что изображение может иметь альфа-канал, мешающий цветовой клавише. Лучше всего убедиться, что вы не пытаетесь использовать оба.
Мне сказали, что вы можете определить альфа-канал изображения программно. Что-то вроде...
if self.image.get_masks()[3]!=0:
print "image has alpha!"
Смотрите здесь http://pygame.org/docs/ref/surface.html
НТН