Kris Schnee wrote:
But a problem appeared in trying to make the process more efficient, by drawing a lightmask on its own, once, then each blitting it onto the black mask, then blitting the black mask onto the screen. Doing it that way would be better for complex, gradient lights such as the big one seen in my previous code. That is, you'd make a (radius*2,radius*2) surface that's black with a gradually-shaded circle of translucency, once, then blit it onto solid black each frame. But when I tried that, Pygame took me too literally.

Try the following code. It uses a gradient light.

import pygame

SCREENSIZE = [800, 600]
LIGHTSIZE = 400
NIGHTCOLOR = [0, 0, 0, 200]

def CreateLight():
    gradient = pygame.Surface([LIGHTSIZE, LIGHTSIZE], 0, 8)
    gradient.set_palette([[x, x, x] for x in range(256)])
    a = NIGHTCOLOR[3]
    gradient.fill((a, a, a))
    r = LIGHTSIZE/2
    for i in range(r):
        c = (a * (r-i))/r
        pygame.draw.circle(gradient, [c, c, c], [r, r], r-i)
        c -= 1
    return gradient

def CreateBackground():
    bg = pygame.Surface(SCREENSIZE, pygame.SRCALPHA, 32).convert_alpha()
    bg.fill((0, 0, 128, 255))
    bg.fill((255, 0, 0, 255), (50, 50, 100, 100))
    return bg

def CreateNight():
    pic = pygame.Surface(SCREENSIZE, pygame.SRCALPHA, 32).convert_alpha()
    pic.fill(NIGHTCOLOR)
    return pic

def CreateAlpha():
    pic = pygame.Surface(SCREENSIZE, 0, 8)
    pic.set_palette([[x, x, x] for x in range(256)])
    a = NIGHTCOLOR[3]
    pic.fill([a, a, a])
    return pic

def RefreshNight(night, alpha, light, x, y):
    a = NIGHTCOLOR[3]
    alpha.fill([a, a, a])
    r = LIGHTSIZE/2
    alpha.blit(light, [x-r, y-r])
pygame.surfarray.pixels_alpha(night)[:, :] = pygame.surfarray.pixels2d(alpha)

def main():
    pygame.init()
    screen = pygame.display.set_mode(SCREENSIZE, 0, 32)
    bg = CreateBackground()
    circle = CreateLight()
    night = CreateNight()
    alpha = CreateAlpha()
    done = 0
    x, y = 400, 300
    while not done:
        RefreshNight(night, alpha, circle, x, y)
        screen.blit(bg, (0, 0))
        screen.blit(night, (0, 0))
        pygame.display.flip()
        pygame.event.pump()
        for event in pygame.event.get():
            if (event.type == pygame.QUIT) or \
(event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                done = True
                break
            elif event.type == pygame.MOUSEMOTION:
                x, y = event.pos
    pygame.quit()

main()

Reply via email to