简体   繁体   English

如何在pygame中屏蔽透明图像以制作Alpha“切口”

[英]How to blit a tranparent image in pygame to make an alpha “cut-out”

Given a pygame Surface filled with some pixels, I want to programmatically make an alpha-channel "window" in that image (such that the background shows through). 给定一个充满一些像素的pygame曲面,我想以编程方式在该图像中创建一个Alpha通道“窗口”(这样背景就会显示出来)。

在此处输入图片说明

Obviously I realise that this can be trivially done with a bitmap editor, the point of the question is to do this on-the-fly as part of a different, more-complex operation. 显然,我意识到可以使用位图编辑器轻松完成此操作,问题的关键是作为不同,更复杂的操作的一部分即时进行此操作。

So I made a sprite that switches between the "full-red" and "red-with-hole" images, and tried to dynamically make the bitmap-window by blitting a fully-transparent image onto the base-bitmap. 因此,我制作了一个在“全红”和“带孔的红色”图像之间切换的精灵,并尝试通过将完全透明的图像涂抹到基本位图上来动态创建位图窗口。

I think what is happening, is that PyGame is not painting the fully-transparent pixels because, well they're transparent! 我认为正在发生的是,PyGame没有绘制完全透明的像素,因为它们是透明的! Is there a way to blit them such that the window is made? 有什么方法可以使它们变薄,从而制成窗户吗?

I tried adding pygame.BLEND_RGBA_MIN and others (as per the suggestion in Need to blit transparency on a surface in Pygame ), but failed to achieve the desired result. 我尝试添加pygame.BLEND_RGBA_MIN 和其他 (根据“ 需要在Pygame中 pygame.BLEND_RGBA_MIN 表面透明性的建议”),但未能获得所需的结果。

All I ever get is a black square, centred in the red, rather than a window to the background. 我得到的只是一个以红色为中心的黑色正方形,而不是背景的窗口。

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()

First: you need (0,0,0,0) instead of (0,0,0,255) 首先:您需要(0,0,0,0)而不是(0,0,0,255)

Second: you have to use fill(color, rect) to create transparent hole directly in red rectangle. 第二:您必须使用fill(color, rect)直接在红色矩形中创建透明孔。

self.hole_image.fill( (0, 0, 0, 0), (10, 10, 10, 10) )

Or you can draw transparent rectangle directly in red surface 或者您可以直接在红色表面上绘制透明矩形

pygame.draw.rect(self.hole_image, (0, 0, 0, 0), (10, 10, 10, 10) )

When you blit transparent image on full color image then it doesn't replace pixels but it mix both colors (transparent and full) and you get full color. 当您在全彩色图像上对透明图像进行blit时,它不会替换像素,但会同时混合两种颜色(透明和全色),您会获得全彩色。

blit() has flags BLEND_ADD , BLEND_SUB , BLEND_MULT , etc. and maybe using one of this flag you could replace pixels but I never tried it. blit()具有标志BLEND_ADDBLEND_SUBBLEND_MULT等,也许使用此标志之一可以替换像素,但我从未尝试过。

Other information: pygame transparency 其他信息: pygame透明度

Full code: 完整代码:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM