Pygame alpha in polygon only

Viewed 248

I am currently working on making a pygame code that draws a polygon on top of existing JPG.

What I do is draw 2 surfaces, one for the Background JPG at the bottom and another for the polygon on top. For the polygon surface, I need to give "SRCALPHA" property to the surface so that no background Fill will block the view at the Background JPG. However, when I do this, I cannot use polygon surface.set_alpha to control polygon's transparency.

What is the method to do this or should I entirely change my approach?

Edit: After this problem is solved, i get another problem in similar thing, please see Python pygame alpha in text and help me if you know the solution. Thank you very much.

1 Answers

You are mixing two things together that you do not need to (and cannot mix). However you do not need to use set_alpha() to achieve what you want.

SRCALPHA tells it that you are going to use per pixel alpha on this surface. If you read the docs here you will find it says 'SRCALPHA the pixel format will include a per-pixel alpha'. Here you see that the docs for set_alpha() indicate it is incompatible with per-pixel alpha 'For a surface with per pixel alpha, blanket alpha is ignored' (unless you are using pygame 2 which I doubt).

From your description of the problem, I doubt that you need set_alpha though. If you have created your upper surface to use per pixel alpha with "SRCALPHA" then the pixels you do not draw will already be transparent. when you blit it over the other surface only the polygon you drew should be transferred.

Here is an example:

GREEN = pygame.Color('green')
RED = pygame.Color('red')

size = (800, 400)
    
pygame.init()
screen = pygame.display.set_mode(size)

lowersurf = pygame.Surface(size)
lowersurf.fill(GREEN)

polysurf = pygame.Surface(size, flags=pygame.SRCALPHA)
pygame.draw.polygon(polysurf, RED, ((100, 100), (600, 100), (600, 200), (350, 300), (100, 200)), 4)

lowersurf.blit(polysurf, (0, 0))

screen.blit(lowersurf, (0, 0))
pygame.display.flip()

It draws a polygon outline on the transparent polysurf and then blits that onto the normal lowersurf.

Then it blits the resulting lowersurf onto the screen.

Edit:

In a comment the OP asked how to draw the polygon onto the lowersurf with transparency so that it would have 50% transparency. One way that can be done by drawing the images onto the polysurf with as partially transparent. Like this:

GREEN = pygame.Color('green')
RED = pygame.Color('red')

transparent_red = RED
transparent_red[3] = 125

size = (800, 400)
    
pygame.init()
screen = pygame.display.set_mode(size)

lowersurf = pygame.Surface(size)
lowersurf.fill(GREEN)

polysurf = pygame.Surface(size, flags=pygame.SRCALPHA)
pygame.draw.polygon(polysurf, transparent_red, ((100, 100), (600, 100), (600, 200), (350, 300), (100, 200)), 4)

lowersurf.blit(polysurf, (0, 0))

screen.blit(lowersurf, (0, 0))
pygame.display.flip()

This creates a color transparent_red that is 50% transparent. The fourth parameter in the color is the alpha value and it ranges from 0 (fully transparent) to 255 (fully opaque), and so 125 is halfway.

A further approach, which is likely what you really want, is to do this with the entire polysurf and not just specific things drawn onto it. Draw the entire polysurf as originally done and then adjust the alpha of the entire surface before drawing it. Like this:

GREEN = pygame.Color('green')
RED = pygame.Color('red')

size = (800, 400)

blend_alpha = 125
    
pygame.init()
screen = pygame.display.set_mode(size)

lowersurf = pygame.Surface(size)
lowersurf.fill(GREEN)

polysurf = pygame.Surface(size, flags=pygame.SRCALPHA)
pygame.draw.polygon(polysurf, RED, ((100, 100), (600, 100), (600, 200), (350, 300), (100, 200)), 4)

transparent_polysurf = polysurf.copy()
transparent_polysurf.fill((255, 255, 255, blend_alpha), special_flags=pygame.BLEND_RGBA_MULT)

lowersurf.blit(transparent_polysurf, (0, 0))

screen.blit(lowersurf, (0, 0))
pygame.display.flip()

In this example I copied the polysurf and then used the fill() using special_flags=pygame.BLEND_RGBA_MULT (see docs here) on the copy to make it partially transparent before blit'ing the copy. I did that so the original is unaffected, but if you don't care, then you can do the blending fill() directly on polysurf without making a copy.

As I said, you likely want to go with the last approach since it blends everything from polysurf with the same level of transparency. The other approach is useful if you want to blend different things drawn to polysurf with different transparency levels.

Related