处理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 个回答
做得好!你实际上已经正确地利用了透明度和颜色键(比如,确保对表面调用了转换,确保将颜色传递给set_colorkey方法等等)。
问题出在你对两个精灵组“all”和“waveList”的绘制和清除顺序上。在你通过调用all.draw渲染文本块之后,接着又调用了waveList.clear。
问题是:一旦你绘制了文本精灵,就不想清除波浪精灵下面的空间,否则会把已经绘制的文本块覆盖掉。
如果你想正确处理这个问题,可以尝试按以下顺序进行:
- waves.update()
- all.clear(screen, background)
- waveList.clear(screen, background)
- all.draw(screen)
- waveList.draw(screen)
更简单地说,只需把waveList.clear(screen, background)移动到all.clear(screen, background)下面一行就可以了;这样就可以解决问题。
当我处理精灵组时,通常会将它们分组,使每个精灵组按照这个顺序调用相同的方法:清除、更新、碰撞检查(如果有的话)、绘制。
这样通常能以正确的顺序处理事情。然后你可能还需要注意精灵的层次关系,但那是另一个话题,留到以后再说。
我不知道这对你来说是否可行,但使用png格式的原生透明度效果会更好。
如果你能自己编辑或重新制作png图片,试着使用透明背景。
这样的话,在加载图片后可以用convert_alpha()来处理它。(而不是使用颜色键)
http://pygame.org/docs/ref/surface.html#Surface.convert_alpha
编辑:还有一个方面是,图片可能有一个透明通道,这会影响颜色键。最好确保你不要同时使用这两者。
我听说你可以通过编程来检测图片的透明通道。类似于...
if self.image.get_masks()[3]!=0:
print "image has alpha!"
可以查看这里 http://pygame.org/docs/ref/surface.html#Surface.get_masks
希望这对你有帮助