使图像背景透明的问题:pygame
我正在使用 pygame 编写一个简单的打字导师。我的问题是我使用的是白色背景的图像 waves1.png
。现在我已经指定我希望白色在图像中是透明的 (self.image.set_colorkey((255, 255, 255))
),并且它适用于除文本块之外的所有内容。当波浪与文本
对象相交时,波浪的白色背景显示在文本顶部。如果你有 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()
I'm in the middle of working on a simple typing tutor using pygame. My problem is that I'm using an image that has a white background, waves1.png
. Now's I've specified that I want white to be transparent in the image (self.image.set_colorkey((255, 255, 255))
) and it is for everything except the text block. When the waves intersect with the text
object, the white background of the waves show on top of the text. You can try running this if you have pygame (with the exception of the waves1.png image).
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()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不知道这是否适合您,但您应该使用 png 的原生 alpha 透明度获得更好的结果。
如果您可以自己编辑/重新创建 png,请尝试使用透明背景。
从那里,您可以在加载图像后使用convert_alpha()。 (而不是使用颜色键)
http://pygame.org/docs/ref/ surface.html#Surface.convert_alpha
编辑: 另一方面,图像可能具有干扰色键的 Alpha 通道。最好确保您不会尝试同时使用两者。
我听说您可以通过编程方式检测图像的 Alpha 通道。类似...
请参见此处 http://pygame.org/docs/ref/ surface.html#Surface.get_masks
HTH
I don't know if it's an option for you, but you should get better results with png's native alpha transparency.
If you can edit/recreate the png yourself, then try using a transparent background.
From there, you can use convert_alpha() arfter loading the image. (instead of using a colorkey)
http://pygame.org/docs/ref/surface.html#Surface.convert_alpha
EDIT: one other aspect, is that the image may have an alpha channel interfering with the colorkey. Best to ensure you're not trying to use both.
I'm told that you can detect an image's alpha channel programmatically. Something like ...
See here http://pygame.org/docs/ref/surface.html#Surface.get_masks
HTH
干得好!实际上,您已经正确地完成了所有操作,以利用透明度和颜色键(即,确保在表面上调用转换,确保将颜色传递到 set_colorkey 方法等)。
问题在于调用各自的精灵组“all”和“waveList”上的绘制和清除的顺序。通过调用 all.draw 渲染文本块后,您可以调用 waveList.clear。
问题是:一旦绘制了文本精灵,您就不想清除波浪精灵下方的空间,否则会擦除与已绘制的文本块重叠的区域。
如果您想正确执行此操作,请尝试按以下顺序执行此操作:
(more简而言之,只需将 waveList.clear(screen, background) 移至 all.clear(screen, background); 下方的行即可)
当我使用精灵组时,我通常尝试将其分组,以便每个精灵group 按以下顺序调用相同的方法:清除、更新、碰撞检查(如果有)、绘制。
这通常会按正确的顺序处理事情。那么你可能仍然需要注意精灵是否有分层,但那是另一回事了。
Well done! You've actually done everything correctly to take advantage of transparency and colorkey (ie, making sure to call convert on the surface, making sure to pass the color into the set_colorkey method, etc).
The problem is with the order of calls to draw and clear on your respective sprite groups, "all" and "waveList". After you've rendered the text blocks by calling all.draw, you then follow it with the call to waveList.clear.
Here's the problem: once you've drawn the text sprites, you don't want to clear the space underneath the wave sprites, or that will wipe out the area that overlaps the already-drawn text blocks.
If you want to do this properly, try doing it in this order:
(more simply, just move waveList.clear(screen, background) to the line just below all.clear(screen, background); that should do it)
When I'm working with sprite groups, I usually try to group it so that each sprite group calls the same method in this order: clears, updates, collision checks (if any), draws.
This usually handles things in the right order. Then you still may have to pay attention to whether there is any layering of sprites, but that's another story for another day.