[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[pygame] Masking Test: Simulated Lighting (Follow-Up)
- To: pygame-users@xxxxxxxx
- Subject: [pygame] Masking Test: Simulated Lighting (Follow-Up)
- From: Kris Schnee <kschnee@xxxxxxxxxx>
- Date: Sun, 21 Jan 2007 09:42:34 -0500
- Delivered-to: archiver@seul.org
- Delivered-to: pygame-users-outgoing@seul.org
- Delivered-to: pygame-users@seul.org
- Delivery-date: Sun, 21 Jan 2007 09:42:47 -0500
- Reply-to: pygame-users@xxxxxxxx
- Sender: owner-pygame-users@xxxxxxxx
- User-agent: Thunderbird 1.5.0.9 (Windows/20061207)
I played with the idea more and was able to make a moving light source
by, each frame, making a solid black mask, using pygame.draw.circle to
draw a transparent circle on it, then blitting the holey mask onto the
screen. This turned everything black except where the "light" had been
placed, and the light's position could be changed each frame.
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. I think what happened was that when I
blitted the lightmask onto the black mask, the transparent areas, being
transparent, didn't affect the black mask and so didn't create a hole!
As-is, the method is only really suitable for sharp-edged lights --
those that can be drawn with a single call to pygame.draw.circle -- and
even then it's a framerate-wounder.
## <code>
SCREEN_SIZE = (800,600)
light_size = 100
light_location = (200,200)
## Setup
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
## A black mask for the screen.
mask = pygame.surface.Surface(SCREEN_SIZE).convert_alpha()
## A moving light mask drawn atop the black mask.
lightmask = pygame.surface.Surface((light_size,light_size)).convert_alpha()
#### An inefficiently-drawn shaded "light"
##radius = 200
##t = 255
##delta = 3
##while radius > 50:
## pygame.draw.circle(mask,(0,0,0,t),light_location,radius)
## t -= delta
## radius -= delta
##pygame.draw.circle(mask,(0,0,0,95),light_location,radius)
def DrawScreen():
## A blue screen with a couple of white squares
screen.fill((0,0,255))
pygame.draw.rect(screen,(255,255,255),(100,100,100,100))
pygame.draw.rect(screen,(255,255,255),(300,250,100,100))
def CreateLightMask():
"""Call once. Only needed for second method."""
lightmask.fill((0,0,0,255)) ## Opaque black except where changed
pygame.draw.circle(lightmask,(0,0,0,0),(50,50),50)
def DrawMask():
"""Inefficient method."""
## Blank the mask
mask.fill((0,200,0,255))
## Put the light onto it, using manual drawing
pygame.draw.circle(mask,(0,0,0,0),light_location,50)
## Cover the screen with the partly-translucent mask
screen.blit(mask,(0,0))
def DrawMask_SecondMethod():
"""For some reason this method doesn't work."""
## Blank the mask
mask.fill((0,0,0,255)) ## Try changing one of the RGB values to 255.
## Put the light onto it, by blitting the pre-drawn lightmask
mask.blit(lightmask,(0,0))
## Cover the screen with the partly-translucent mask
screen.blit(mask,(0,0))
## MAIN LOOP ##
CreateLightMask() ## Draw the light source for the first time
## Test FPS.
frames_drawn = 0
ticks = pygame.time.get_ticks()
done = False
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
## Move the light a bit
light_location = (light_location[0] + 5, light_location[1]+2)
DrawScreen()
DrawMask() ## Working method
## DrawMask_SecondMethod() ## Non-working method
## Make it so
pygame.display.update()
frames_drawn += 1
## FPS rating.
print "Done. FPS: %d" %
((frames_drawn*1000)/(pygame.time.get_ticks()-ticks))
## </code>