python - 如何在 pygame 中对透明图像进行 blit 以制作 alpha“剪切”
问题描述
给定一个填充了一些像素的 pygame Surface,我想以编程方式在该图像中创建一个 alpha 通道“窗口”(以便背景显示出来)。
显然,我意识到这可以通过位图编辑器轻松完成,问题的关键是作为不同的更复杂操作的一部分即时执行此操作。
所以我制作了一个在“全红色”和“带孔红色”图像之间切换的精灵,并尝试通过将完全透明的图像粘贴到基本位图上来动态制作位图窗口。
我认为正在发生的事情是 PyGame 没有绘制完全透明的像素,因为它们是透明的!有没有办法对它们进行 blit 以便制作窗口?
我尝试添加pygame.BLEND_RGBA_MIN
和其他(根据需要在 Pygame 的表面上 blit 透明度中的建议)的建议),但未能达到预期的结果。
我所得到的只是一个以红色为中心的黑色方块,而不是背景的窗口。
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
FPS = 60
# background colours
INKY_BLACK = (128, 128, 128)
class HoleSprite( pygame.sprite.Sprite ):
def __init__( self ):
pygame.sprite.Sprite.__init__( self )
# Make a full-image (no hole)
self.base_image = pygame.Surface( ( 32, 32 ), pygame.SRCALPHA )
self.base_image.fill( ( 255,0,0 ) )
# Make an image with a see-through window
self.hole_image = pygame.Surface( ( 32, 32 ), pygame.SRCALPHA )
self.hole_image.fill( ( 255,0,0 ) )
self.hole = pygame.Surface( ( 10, 10 ), pygame.SRCALPHA )
self.hole.fill( ( 0, 0, 0, 255 ) ) # transparent
self.hole_image.blit( self.hole, [ 10,10, 10,10 ] ) # punch the middle out?
# sprite housekeeping
self.image = self.base_image
self.rect = self.image.get_rect()
self.rect.x = WINDOW_WIDTH // 2 # centred
self.rect.y = WINDOW_HEIGHT // 2
self.last = 0
def update( self ):
time_ms = pygame.time.get_ticks()
# FLip the images each second
if ( time_ms - self.last > 1000 ):
if ( self.image == self.hole_image ):
self.image = self.base_image
else:
self.image = self.hole_image
self.last = time_ms
### MAIN
pygame.init()
pygame.font.init()
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
WINDOW = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Hole Srite Test")
anims = pygame.sprite.GroupSingle()
holey = HoleSprite( )
anims.add( holey )
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Repaint the screen
anims.update()
WINDOW.fill( INKY_BLACK )
anims.draw( WINDOW )
pygame.display.flip()
# Update the window, but not more than 60fps
clock.tick_busy_loop( FPS )
pygame.quit()
解决方案
第一:你需要(0,0,0,0)
代替(0,0,0,255)
第二:您必须使用fill(color, rect)
直接在红色矩形中创建透明孔。
self.hole_image.fill( (0, 0, 0, 0), (10, 10, 10, 10) )
或者你可以直接在红色表面绘制透明矩形
pygame.draw.rect(self.hole_image, (0, 0, 0, 0), (10, 10, 10, 10) )
当您在全彩色图像上对透明图像进行 blit 时,它不会替换像素,而是混合两种颜色(透明和完整)并且您会获得全彩色。
blit()
有标志,,,BLEND_ADD
等BLEND_SUB
,BLEND_MULT
也许使用这个标志之一你可以替换像素,但我从未尝试过。
其他信息:pygame透明度
完整代码:
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
FPS = 60
# background colours
INKY_BLACK = (128, 128, 128)
class HoleSprite( pygame.sprite.Sprite ):
def __init__( self ):
pygame.sprite.Sprite.__init__( self )
# Make a full-image (no hole)
self.base_image = pygame.Surface( ( 32, 32 ), pygame.SRCALPHA )
self.base_image.fill( ( 255,0,0 ) )
# Make an image with a see-through window
self.hole_image = pygame.Surface( ( 32, 32 ), pygame.SRCALPHA )
self.hole_image.fill( ( 255,0,0 ) )
self.hole_image.fill( (0, 0, 0, 0), (10, 10, 10, 10) )
# OR
#pygame.draw.rect(self.hole_image, (0, 0, 0, 0), (10, 10, 10, 10) )
# sprite housekeeping
self.image = self.base_image
self.rect = self.image.get_rect()
self.rect.x = WINDOW_WIDTH // 2 # centred
self.rect.y = WINDOW_HEIGHT // 2
self.last = 0
def update( self ):
time_ms = pygame.time.get_ticks()
# FLip the images each second
if ( time_ms - self.last > 1000 ):
if ( self.image == self.hole_image ):
self.image = self.base_image
else:
self.image = self.hole_image
self.last = time_ms
### MAIN
pygame.init()
pygame.font.init()
SURFACE = pygame.HWSURFACE|pygame.DOUBLEBUF|pygame.RESIZABLE
WINDOW = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ), SURFACE )
pygame.display.set_caption("Hole Srite Test")
anims = pygame.sprite.GroupSingle()
holey = HoleSprite( )
anims.add( holey )
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
# Repaint the screen
anims.update()
WINDOW.fill( INKY_BLACK )
anims.draw( WINDOW )
pygame.display.flip()
# Update the window, but not more than 60fps
clock.tick_busy_loop( FPS )
pygame.quit()
推荐阅读
- java - 将带有表连接结果列表的 nativeQuery 获取到 JSONObject
- javascript - 如何屏蔽 ApolloServer 中的错误并返回不同的响应
- android - 我无法在 sql server 的子类中发布我的值
- git - 如何合并非源存储库中的特定文件?
- angular - 无法在 mat-icon 中加载自定义 SVG
- php - 通过直接 URL 的全局变量或无法访问的链接
- pm2 - PM2 无法在集群模式下写入日志文件
- php - 重置 mPDF 中的 writeHTML() 缓冲区
- r - R data.table 按列值设置子集
- python - 人脸识别功能在静态路径下工作正常,但在烧瓶后请求中的动态路径失败