[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
Re: [pygame] Rain Generator
Kai Kuehne wrote:
Looks similar to http://www.scriptedfun.com/pygame-starfield-rain/
but it's cool.
Yep, that's the site that inspired me. Mine is a different solution to
the same problem, but the raindrops look similar, that's true. If you
look closely, his are leaving trails behind - mine isn't, it's using an
entire raindrop with a tail that 'peters out.'
Luke noticed the dirty rectangle code wasn't working quite correctly, so
I've modified the code and reposted it at
http://incarnation.danbo.com/ubbthreads/modifypost.php .
I also added some features, such as:
* Speeding up big raindrops so they appear closer
* Changing the translucency of raindrops so smaller ones are dimmer and
look farther away
* Optimized the particle engine so the raindrops are created once when
the generator is created (as opposed to being continually created and
destroyed)
* Put the drops on a timer so they move at the desired speed regardless
of how often you call the rain generator
* Made the left and right arrow keys decrease/increase the rain speed.
plus miscellaneous enhancements.
Or - read it here if you wish:
'''
Rain.py - a rain generator by Kamilche.
This rain generator creates the particles once when the generator is
created, to save CPU time.
The bigger the raindrop, the faster it moves. The smaller the raindrop,
the dimmer it is.
Parameters are:
screen = surface to draw rain on
height = height of raindrops (will vary from 40% to 100% of size
specified)
speed = speed of raindrops (how fast they fall)
color = color of raindrops, including alpha level (opacity)
numdrops = number of raindrops
'''
import pygame
import random
import time
SCREENSIZE = 640, 480
class Rain(object):
' Rain generator'
def __init__(self, screen, height = 160, speed = 3, color = (180,
215, 228, 255), numdrops = 10):
'Create and reuse raindrop particles'
self.screen = screen
self.drops = []
self.height = height
self.speed = speed
self.color = color
self.numdrops = numdrops
for i in range(self.numdrops):
# Randomize the size of the raindrop.
raindropscale = random.randint(40, 100) / 100.0
w, h = 3, int(raindropscale * self.height)
# The bigger the raindrop, the faster it moves.
velocity = raindropscale * self.speed/10.0
pic = pygame.Surface((w, h), pygame.SRCALPHA,
32).convert_alpha()
colorinterval = float(self.color[3] * raindropscale)/h
r, g, b = self.color[:3]
for j in range(h):
# The smaller the raindrop, the dimmer it is.
a = int(colorinterval * j)
pic.fill( (r, g, b, a), (1, j, w-2, 1) )
pygame.draw.circle(pic, (r, g, b, a), (1, h-2), 2)
drop = Rain.Drop(self.speed, velocity, pic)
self.drops.append(drop)
def Timer(self, now):
' Render the rain'
dirtyrects = []
for drop in self.drops:
r = drop.Render(self.screen, now)
if r:
i = r.collidelist(dirtyrects)
if i > -1:
dirtyrects[i].union_ip(r)
else:
dirtyrects.append(r)
return dirtyrects
def AdjustSpeed(self, adj):
newspeed = self.speed + adj
newspeed = max(1, newspeed)
newspeed = min(100, newspeed)
self.speed = newspeed
for drop in self.drops:
drop.SetSpeed(newspeed)
print 'Rain speed: %d' % newspeed
class Drop(object):
' Rain drop used by rain generator'
nexttime = 0 # The next time the raindrop will draw
interval = .01 # How frequently the raindrop should draw
def __init__(self, speed, scale, pic):
' Initialize the rain drop'
self.speed = speed
self.scale = scale
self.pic = pic
self.size = pic.get_size()
self.SetSpeed(speed)
self.pos = [random.random() * SCREENSIZE[0],
-random.randint(-SCREENSIZE[1], SCREENSIZE[1])]
self.currentspeed = speed
def SetSpeed(self, speed):
' Speed up or slow down the drop'
self.speed = speed
self.velocity = self.scale * self.speed/10.0
def Reset(self):
' Restart the drop at the top of the screen.'
self.pos = [random.random() * SCREENSIZE[0],
-random.random() * self.size[1] - self.size[1]]
self.currentspeed = self.speed
def Render(self, screen, now):
' Draw the rain drop'
if now < self.nexttime:
return None
self.nexttime = now + self.interval
oldrect = pygame.Rect(self.pos[0], self.pos[1],
self.size[0], self.size[1]+self.currentspeed)
self.pos[1] += self.currentspeed
newrect = pygame.Rect(self.pos[0], self.pos[1],
self.size[0], self.size[1])
r = oldrect.union(newrect)
screen.blit(self.pic, self.pos)
self.currentspeed += self.velocity
if self.pos[1] > SCREENSIZE[1]:
self.Reset()
return r
def main():
# Initialize pygame
pygame.init()
pygame.key.set_repeat(500, 30)
screen = pygame.display.set_mode(SCREENSIZE, 0, 32)
# Create rain generator
rain = Rain(screen)
print 'right arrow to increase speed, left arrow to decrease speed.'
# Main loop
quitgame = 0
while not quitgame:
# Emulate CPU usage.
# Commenting this out will no longer matter,
# as the raindrops update on a timer.
time.sleep(.01)
# Draw rain
dirtyrects = rain.Timer(time.time())
# Update the screen for the dirty rectangles only
pygame.display.update(dirtyrects)
# Fill the background with the dirty rectangles only
for r in dirtyrects:
screen.fill((0, 0, 0), r)
# Look for user events
pygame.event.pump()
for e in pygame.event.get():
if e.type in [pygame.QUIT, pygame.MOUSEBUTTONDOWN]:
quitgame = 1
break
elif e.type == pygame.KEYDOWN:
if e.key == 27:
quitgame = 1
break
elif e.key in [pygame.K_LEFT, pygame.K_UP]:
rain.AdjustSpeed(-1)
elif e.key in [pygame.K_RIGHT, pygame.K_DOWN]:
rain.AdjustSpeed(1)
# Terminate pygame
pygame.quit()
if __name__ == "__main__":
main()