August'24: Kamaelia is in maintenance mode and will recieve periodic updates, about twice a year, primarily targeted around Python 3 and ecosystem compatibility. PRs are always welcome. Latest Release: 1.14.32 (2024/3/24)
Cookbook Example
How can I...?
Example 9 : Simple component based game using pygame. This demonstrates use of a collection of simple physics behaviours components, Graphline to bind these to a BasicSprite component, an EventHandler to show how to deal with keyboard handling, a fanout component to help co-ordinate shutdown, and a specialised scheduler - the SpriteScheduler component to run these. Components used:Graphline, BasicSprite, SpriteScheduler, EventHandler, fanout, bouncingFloat, cartesianPingPong, loopingCounter, continuousIdentity, continuousZero, continuousOne
Warnings: if you're less than 4 you'll love this game ;-) Also, This isn't quite integrated with the PyGameApp code, but shows a nice way of writing simple games.
#!/usr/bin/python
import pygame
import random
import os
from Kamaelia.Util.Graphline import Graphline
from Kamaelia.UI.Pygame.BasicSprite import BasicSprite
from Kamaelia.Physics.Behaviours import bouncingFloat, cartesianPingPong, loopingCounter, continuousIdentity, continuousZero, continuousOne
from Kamaelia.UI.Pygame.EventHandler import EventHandler
from Kamaelia.Util.Fanout import fanout
from Kamaelia.UI.Pygame.SpriteScheduler import SpriteScheduler
banner_location = "banner.gif"
cat_location = "cat.gif"
cat_pop_wav_file = "hold.wav"
cat_appear_wav_file = "KDE_Beep_Bottles.wav"
screensize = (700,550)
back_colour = (255,255,255)
border = 40
flags = pygame.DOUBLEBUF
cat_pop_wav = pygame.mixer.Sound(cat_pop_wav_file)
cat_appear_wav = pygame.mixer.Sound(cat_appear_wav_file)
pygame.init()
# --------------------------------------------------------------------------
def makeAndInitialiseBackground(banner_location, screensize,
screen_surface, back_colour):
#
# Load images for background
#
banner_surface = pygame.image.load(banner_location)
banner = banner_surface.convert()
surface = banner_surface
width = banner_surface.get_width()
height = banner_surface.get_height()
#
# Calculate position for image, relative to screen size.
# This is calculated as a rectangle
#
horizonal_to_move = (screensize[0] - width)/2
vertical_to_move = (screensize[1] - height)/2
rect = banner_surface.get_rect()
rect = rect.move([horizonal_to_move,vertical_to_move])
# Create the actual background, and then insert the image(s) into the
# background.
#
background = pygame.Surface(screen_surface.get_size())
background = background.convert()
background.fill(back_colour)
background.blit(banner_surface, rect)
#
# Finally, return the completed background.
#
return background
def randomFromRangeExcludingZero(min,max):
result = 0
while result == 0:
result = random.randint(min,max)
return result
def make_cat(cat_location, screensize, border ):
# Get the cat again!
files = list()
for x in os.listdir("pictures"):
if x not in ("README","CVS"):
files.append(x)
image_location = files[random.randint(0,len(files)-1)]
cat_surface = pygame.image.load("pictures/"+image_location)
cat = cat_surface.convert()
cat.set_colorkey((255,255,255), pygame.RLEACCEL)
rotation_speed = randomFromRangeExcludingZero(-2,2)
scale_speed = float(randomFromRangeExcludingZero(-1,1))
position = list( (random.randint(border,screensize[0]-border),
random.randint(border,screensize[1]-border)))
newCat = BasicSprite(image=cat)
X = Graphline(
newCat = newCat,
rotator = loopingCounter(rotation_speed),
translation = cartesianPingPong(position,screensize[0],screensize[1],border),
scaler = bouncingFloat(scale_speed),
imaging = continuousIdentity(cat),
shutdown_fanout = fanout(["rotator","translation","scaler", "imaging","self_shutdown"]),
linkages = {
("rotator","outbox" ) : ("newCat", "rotator"),
("translation","outbox" ) : ("newCat", "translation"),
("scaler","outbox" ) : ("newCat", "scaler"),
("imaging","outbox" ) : ("newCat", "imaging"),
("newCat", "signal" ): ("shutdown_fanout", "inbox"),
("shutdown_fanout", "rotator") : ("rotator", "control"),
("shutdown_fanout", "translation") : ("translation", "control"),
("shutdown_fanout", "scaler") : ("scaler", "control"),
("shutdown_fanout", "imaging") : ("imaging", "control"),
("shutdown_fanout", "self_shutdown") : ("shutdown_fanout", "control"),
}
).activate()
return newCat
def make_cats(cat_location, screensize, border, numberCats=20):
cat_sprites = []
for i in range(numberCats):
# Need to load the image separately for each sprite...
newCat = make_cat(cat_location, screensize, border)
cat_sprites.append(newCat)
return cat_sprites
class MyGamesEvents(EventHandler):
def __init__(self, cat_args, trace=1, ):
self.trace = 0
self.cat_args = cat_args
def mousebuttondown(self, pos, button, where):
if button == 1:
channel = cat_appear_wav.play()
newCat = make_cat(*self.cat_args)
cat_sprite = newCat
where.allsprites.add(cat_sprite)
if button == 2:
sprites = where.allsprites.sprites()
for sprite in sprites:
if sprite.rect.collidepoint(*pos):
sprite.togglePause()
if button == 3:
# Make a sprite disappear
channel = cat_pop_wav.play()
sprites = where.allsprites.sprites()
popped = 0
for sprite in sprites:
if sprite.rect.collidepoint(*pos):
spriteToZap = sprite
spriteToZap.shutdown()
where.allsprites.remove(spriteToZap)
return
try:
spriteToZap = sprites[len(sprites)-1]
except IndexError:
pass
else:
spriteToZap.shutdown()
where.allsprites.remove(spriteToZap)
def keydown(self, unicode, key, mod, where):
if key == 112: # "P"
# PAUSE ALL MOVEMENT
for sprite in where.allsprites.sprites():
sprite.pause()
if key == 113: # "Q"
raise "QUIT"
if key == 117: # "U"
# UNPAUSE ALL MOVEMENT
for sprite in where.allsprites.sprites():
sprite.unpause()
if key == 116: # "T"
# Toggle PAUSE ALL MOVEMENT
for sprite in where.allsprites.sprites():
sprite.togglePause()
screen_surface = pygame.display.set_mode(screensize, flags)
background = makeAndInitialiseBackground(banner_location, screensize, screen_surface,back_colour)
cat_sprites = make_cats(cat_location, screensize, border,1)
cat_args = (cat_location, screensize, border)
try:
SpriteScheduler(cat_args, cat_sprites, background, screen_surface, MyGamesEvents).run()
except:
passSource: Examples/example9/Simplegame.py