2

I'm trying to make the background of my game fade to black over about 30 seconds. I'm doing so by trying to change the alpha value of my surface.

class Screen:
    def __init__(self):
        self.win = pygame.display.set_mode((1200, 800))
        pygame.display.set_caption("Fire Game")
        self.win.fill((255, 255, 255))

        self.darkness = pygame.Surface((1200, 800))
        self.darkness.fill((0, 0, 0))
        self.darkness.set_alpha(0)
        self.win.blit(self.darkness, (0, 0))

        self.darknessLevel = 0
        self.darknessCount = 0
        pygame.display.flip()

    def run(self):
        self.darknessLevel = self.darknessCount / 10

        # two ways of changing the alpha value

        # 1. self.darkness.fill((0, 0, 0, self.darknessLevel), None, pygame.BLEND_RGBA_MULT)
        # 2. self.darkness.set_alpha(self.darknessLevel)

        self.win.blit(self.darkness, (0, 0))
        pygame.display.flip()
        self.darknessCount += 1
        print(self.darkness.get_alpha())
        print(self.darknessLevel)

the first option should work according to my research but does not, and whenever I use the print statement (self.darkness.get_alpha())I can see that the alpha value does not change. The second way does change the alpha value, however once the alpha value hits 1 it fades all of the ways to black. Experimenting around with this I hardcoded the set_alpha() and learned that the higher the number being the quicker it fades to black. I should also mention that Screen.run() is being called in my games main while loop.

example:
self.darkness.set_alpha(1) fades to black
self.darkness.set_alpha(10) fades to black but much quicker

any ideas on what I'm doing wrong or why this may be happening would be much appreciated

Gearmo
  • 41
  • 3

1 Answers1

2

Pygame has different types of transparency. See this answer.


So if you want to use per-pixel alpha (your option 1, pygame's doc calls this pixel alpha), you have to create the surface with the right flag:

self.darkness = pygame.Surface((1200, 800), flags=pygame.SRCALPHA)

remove the self.darkness.set_alpha(0) line (set_alpha is used for setting the transparency of whole surface), and just fill the surface in your loop without any flags:

    self.darkness.fill((0, 0, 0, self.darknessLevel))

But if you do this, you'll note that you run into the same problem as with your second option: the screen get's to dark too fast.

The problem is that you keep blitting the darkness surface on top of itself while your loop runs. So in the first frame, you blit it onto a white screen. In the second frame, you blit a slightly darker darkness surface on top of an already slightly darker screen, as it is no longer pure white. In the third and each following frame, this effects multiples.

So you could either stop making the darkness surface darker each frame, so the effect does not multiply, or redraw the background every frame, too.


Option 1:

import pygame

class Screen:
    def __init__(self):
        self.win = pygame.display.set_mode((1200, 800))
        pygame.display.set_caption("Fire Game")
        self.win.fill((255, 255, 255))
        self.darkness = pygame.Surface((1200, 800), flags=pygame.SRCALPHA)
        self.darkness.fill((0, 0, 0))
        self.win.blit(self.darkness, (0, 0))
        self.darknessCount = 0
        pygame.display.flip()

    def run(self):
        self.win.fill((255, 255, 255))
        self.darkness.fill((0, 0, 0, self.darknessCount))
        self.win.blit(self.darkness, (0, 0))
        pygame.display.flip()
        self.darknessCount += 1

s = Screen()
c = pygame.time.Clock()
while True:
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            quit()
    s.run()
    c.tick(60)

Opiton 2:

import pygame

class Screen:
    def __init__(self):
        self.win = pygame.display.set_mode((1200, 800))
        pygame.display.set_caption("Fire Game")
        self.win.fill((255, 255, 255))
        self.darkness = pygame.Surface((1200, 800))
        self.darkness.fill((0, 0, 0))
        self.darkness.set_alpha(0)
        self.win.blit(self.darkness, (0, 0))
        self.darknessCount = 0
        pygame.display.flip()

    def run(self):
        self.win.fill((255, 255, 255))
        self.darkness.set_alpha(self.darknessCount)
        self.win.blit(self.darkness, (0, 0))
        pygame.display.flip()
        self.darknessCount += 1

s = Screen()
c = pygame.time.Clock()
while True:
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            quit()
    s.run()
    c.tick(60)

For some more examples, look here:

Pygame fade to black function

How to fade the screen out and back in using PyGame?

sloth
  • 99,095
  • 21
  • 171
  • 219