! !
Smoke. , . , Particle , , :
class Particle():
def __init__(self, col, size, *strategies):
self.x, self.y = 0, 0
self.col = col
self.alive = 0
self.strategies = strategies
self.size = size
def kill(self):
self.alive = -1
def move(self):
for s in self.strategies:
s(self)
. , ( ) __init__, move.
, , , , .
, , :
def ascending(speed):
def _ascending(particle):
particle.y -= speed
return _ascending
- , , :
def kill_at(max_x, max_y):
def _kill_at(particle):
if particle.x < -max_x or particle.x > max_x or particle.y < -max_y or particle.y > max_y:
particle.kill()
return _kill_at
, ( ), , :
def age(amount):
def _age(particle):
particle.alive += amount
return _age
, ( !), :
def fan_out(modifier):
def _fan_out(particle):
d = particle.alive / modifier
d += 1
particle.x += random.randint(-d, d)
return _fan_out
! , , , :
def wind(direction, strength):
def _wind(particle):
if random.randint(0,100) < strength:
particle.x += direction
return _wind
, . . , .
: !
def smoke_machine():
colors = {0: grey,
1: dark_grey,
2: light_grey}
def create():
for _ in xrange(random.choice([0,0,0,0,0,0,0,1,2,3])):
behaviour = age(1), ascending(1), fan_out(400), wind(1, 15), kill_at(1000, 1000)
p = Particle(colors[random.randint(0, 2)], random.randint(10, 15), *behaviour)
yield p
while True:
yield create()
, , ? . , . , - , , create. , , 0 3 random.choice. , 0 70% 1, 2 3 10% .
. . , . , .
- .
, , :
>>> s=smoke_machine()
>>> list(next(s))
[]
>>> list(next(s))
[<particle.Particle instance at 0x02AD94B8>, <particle.Particle instance at 0x02
AD9030>]
>>> list(next(s))
[]
>>> list(next(s))
[]
>>> list(next(s))
[<particle.Particle instance at 0x02AD9030>]
>>> list(next(s))
[<particle.Particle instance at 0x02AD9418>, <particle.Particle instance at 0x02
AD93C8>]
>>> list(next(s))
[<particle.Particle instance at 0x02AD9030>]
, , , 3 .
? , :
class Emitter(object):
def __init__(self, pos=(0, 0)):
self.particles = []
self.pos = pos
self.factories = []
def add_factory(self, factory, pre_fill=300):
self.factories.append(factory)
tmp = []
for _ in xrange(pre_fill):
n = next(factory)
tmp.extend(n)
for p in tmp:
p.move()
self.particles.extend(tmp)
def update(self):
for f in self.factories:
self.particles.extend(next(f))
for p in self.particles[:]:
p.move()
if p.alive == -1:
self.particles.remove(p)
def draw(self, screen, position_translater_func):
for p in self.particles:
target_pos = position_translater_func(map(sum, zip((p.x, p.y), self.pos)))
pygame.draw.circle(screen, p.col, target_pos, int(p.size))
factory (, smoke_machine), , , self.particles, . :
factory add_factory, factory 300 ( - pre_fill) . , .
, , Emitter. , , , , , .
, Emitter . GameScene self.emitter Emitter smoke_machine factory.
render
for e in self.emitter:
e.draw(screen, self.camera.apply)
update
for e in self.emitter:
e.update()
!
!

:
game.py
, 30000 : -)
import pygame
from pygame import *
from particle import Emitter, smoke_machine
WIN_WIDTH = 1120 - 320
WIN_HEIGHT = 960 - 320
HALF_WIDTH = int(WIN_WIDTH / 2)
HALF_HEIGHT = int(WIN_HEIGHT / 2)
DISPLAY = (WIN_WIDTH, WIN_HEIGHT)
DEPTH = 0
FLAGS = 0
CAMERA_SLACK = 30
levels = {0: {'level': [
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" E ",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPP PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPP P",
" PPPP P",
" PPPP PPPPPPP",
" PPPPPPPPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
"PPPPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPPP PPPP PPPPPPP",
"PPP PPPP",
"PPP PPPP",
"PPP PPPP",
"PPP PPPPPPPPPPPPPPPPPP",
"PPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP S PPPPPPPPPPPPPPPPPP",],
'enemies': [(9, 38)]},
1: {'level': [
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" ",
" E ",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPPP PPPPPPPPPPPPPPPP",
" PPPPPPPPPPPPPPPP",
" PPPP P",
" PPPP P",
" PPPP PPPPPPP",
" PPPPPPPPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
" PPPP PPPPPPP",
"PPPPP PPPP PPPPPPP",
"PPP PPPPPPPPPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPP PPPPPPP",
"PPP PPPPPPPP PPPP PPPPPPP",
"PPP PPPP",
"PPP PPPP",
"PPP PPPPP PPPP",
"PPP P PPPPPPPPPPPPPPPPPP",
"PPP P PPPPPPPPPPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",
"PPPPPPPPPPPPPPP PPPPPPPPPPPPPPPPPP",],
'enemies': [(9, 38), (18, 38), (15, 15)]}}
...
class GameScene(Scene):
def __init__(self, levelno):
super(GameScene, self).__init__()
self.bg = Surface((32,32))
self.bg.convert()
self.bg.fill(Color("#0094FF"))
up = left = right = False
self.entities = pygame.sprite.Group()
self.player = Player(5, 40)
self.player.scene = self
self.platforms = []
self.levelno = levelno
levelinfo = levels[levelno]
self.enemies = [Enemy(*pos) for pos in levelinfo['enemies']]
level = levelinfo['level']
total_level_width = len(level[0]) * 32
total_level_height = len(level) * 32
self.emitter = []
x = 0
y = 0
for row in level:
for col in row:
if col == "P":
p = Platform(x, y)
self.platforms.append(p)
self.entities.add(p)
if col == "E":
e = ExitBlock(x, y)
self.platforms.append(e)
self.entities.add(e)
if col == "S":
e = Emitter((x, total_level_height))
e.add_factory(smoke_machine())
self.emitter.append(e)
x += 32
y += 32
x = 0
self.camera = Camera(complex_camera, total_level_width, total_level_height)
self.entities.add(self.player)
for e in self.enemies:
self.entities.add(e)
def render(self, screen):
for y in range(20):
for x in range(25):
screen.blit(self.bg, (x * 32, y * 32))
for e in self.emitter:
e.draw(screen, self.camera.apply)
for e in self.entities:
screen.blit(e.image, self.camera.apply(e))
def update(self):
for e in self.emitter:
e.update()
pressed = pygame.key.get_pressed()
up, left, right = [pressed[key] for key in (K_UP, K_LEFT, K_RIGHT)]
self.player.update(up, left, right, self.platforms)
for e in self.enemies:
e.update(self.platforms)
self.camera.update(self.player)
def exit(self):
if self.levelno+1 in levels:
self.manager.go_to(GameScene(self.levelno+1))
else:
self.manager.go_to(CustomScene("You win!"))
def die(self):
self.manager.go_to(CustomScene("You lose!"))
def handle_events(self, events):
for e in events:
if e.type == KEYDOWN and e.key == K_ESCAPE:
self.manager.go_to(TitleScene())
...
if __name__ == "__main__":
main()
particle.py
import pygame,random
def ascending(speed):
def _ascending(particle):
particle.y -= speed
return _ascending
def kill_at(max_x, max_y):
def _kill_at(particle):
if particle.x < -max_x or particle.x > max_x or particle.y < -max_y or particle.y > max_y:
particle.kill()
return _kill_at
def age(amount):
def _age(particle):
particle.alive += amount
return _age
def fan_out(modifier):
def _fan_out(particle):
d = particle.alive / modifier
d += 1
particle.x += random.randint(-d, d)
return _fan_out
def wind(direction, strength):
def _wind(particle):
if random.randint(0,100) < strength:
particle.x += direction
return _wind
class Particle():
def __init__(self, col, size, *strategies):
self.x, self.y = 0, 0
self.col = col
self.alive = 0
self.strategies = strategies
self.size = size
def kill(self):
self.alive = -1
def move(self):
for s in self.strategies:
s(self)
black = (0,0,0)
grey = (145,145,145)
light_grey = (192,192,192)
dark_grey = (183, 183, 183)
def smoke_machine():
colors = {0: grey,
1: dark_grey,
2: light_grey}
def create():
for _ in xrange(random.choice([0,0,0,0,0,0,0,1,2,3])):
behaviour = ascending(1), kill_at(1000, 1000), fan_out(400), wind(1, 15), age(1)
p = Particle(colors[random.randint(0, 2)], random.randint(10, 15), *behaviour)
yield p
while True:
yield create()
class Emitter(object):
def __init__(self, pos=(0, 0)):
self.particles = []
self.pos = pos
self.factories = []
def add_factory(self, factory, pre_fill=300):
self.factories.append(factory)
tmp = []
for _ in xrange(pre_fill):
n = next(factory)
tmp.extend(n)
for p in tmp:
p.move()
self.particles.extend(tmp)
def update(self):
for f in self.factories:
self.particles.extend(next(f))
for p in self.particles[:]:
p.move()
if p.alive == -1:
self.particles.remove(p)
def draw(self, screen, position_translater_func):
for p in self.particles:
target_pos = position_translater_func(map(sum, zip((p.x, p.y), self.pos)))
pygame.draw.circle(screen, p.col, target_pos, int(p.size))
. , , , , factory.
, , SRP, factory - .
, . , -, .
, ,
def grow(amount):
def _grow(particle):
if random.randint(0,100) < particle.alive / 20:
particle.size += amount
return _grow
grow(0.5) smoke_machine

, .
!
P.S.: ( ) . numpy, itertools, psyco pygame.surfarray random .