# #~ /*************************************************************************** #~ * fallingletters.py #~ * #~ * Mon Feb 23 15:29:08 2004 #~ * Copyright 2004 Stas Z #~ * stasz@linux.isbeter.nl #~ ****************************************************************************/ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ## This is a port of the gletters (falling letters) activity from gcompris. RCFILE = 0 DEBUG = 0 import os,sys,random import pygame from pygame.constants import * from utils import load_image,trace_error,char2surf,MyError from SpriteUtils import CPSprite,CPGroup,CPinit import Timer class Img: pass class Snd: pass class Misc: pass class Letter(CPSprite):# we derive from this high-level class def __init__(self,c,pic,x,step,delay): CPSprite.__init__(self)# embed it in this class self.image= pic self.letter = c start = (x,0) self.delay = delay self.wait = delay self.rect = self.image.get_rect()#.move(start) end = (x,500+pic.get_height())# move of the screen loop = 0# 0 means one time, 1 means twice self.set_movement(start,end,step,0,loop)# setup the movement of this object self.connect_callback(self.callback, event_type=KEYDOWN) def __str__(self): return self.letter def on_update(self,*args): """This is called by group.refresh method""" if self.wait:# extra delay, otherwise they drop still to fast self.wait -= 1 return else: self.wait = self.delay status = self.moveit()# we move accoording to the movement set in the constructor if status != -1:# reached the end of the movement self.remove_sprite() # call the fail_to_type_letter? def callback(self,*args): """ This is called when the sprite class update method is called. Remember that you must 'connect' a callback first with a call to self.connect_callback, see the CPSprite reference for info on possibilities of connecting callbacks . """ if DEBUG: print __name__,"args>",args[0],args[1] try: c = args[1].unicode.upper() except ValueError: return if c == str(self): self.remove_sprite() return 2 class Level: def __init__(self): """All these attributes will get their value at run time""" self.timersleep = 0# set the timerobject delay self.delay = 0# set a extra pause in the speed of the letter object self.step = 0 # set the number of pixels the letter will fall self.background = None # name of the background png class Game(Img,Snd): """ Falling letters - part of childsplay.py, a suite of educational games for young children. """ def __init__(self,screen,backgr,configdic,basepath,libdir): self.screen = Img.screen = screen self.backgr = Img.backgr = backgr gamelevels = [] for level in ('0','1','2'): l = Level() l.timersleep = {'0':6, '1':5, '2':4}[level] l.delay = {'0':6, '1':4, '2':2}[level] l.step = {'0':1, '1':1, '2':2}[level] l.background = {'0':'scenery0.png',\ '1':'scenery1.png',\ '2':'scenery2.png'}[level] gamelevels.append(l) self.gamelevels = gamelevels self.gameitems = (1,2) self.letters = map(chr,range(65,91)) self.configdic = configdic # not used, perhaps in the future self.basedir = basepath self.libdir = libdir self.stop = 0 self.score = 0 # You MUST call CPinit BEFORE using any of the SpriteUtils stuff # it returns a reference to the special CPGroup Misc.actives = CPinit(self.screen,self.backgr) self._setup() def __del__(self): try: self.timer.stop() except: pass def _setup(self): """ Set all the stuff we need""" self.timer = None # will hold the timer object def start(self,level,items): """Try to hit the falling letters on the keyboard before they hit the ground.""" if DEBUG: print "level object", level.__dict__ self.score, self.stop = 0, 0 if self.timer: self.timer.stop() Img.org_backgr = Img.backgr.convert() # save a copy of the original, just in case s = load_image(os.path.join(self.libdir,'FallingLettersData',level.background),0) # restore scenery Img.screen.blit(s, (0, 0)) Img.backgr.blit(s,(0,0)) pygame.display.update() # setup the letters self.letter_objects = [] random.shuffle(self.letters) for c in self.letters: img = char2surf(c,56,(123,3,127)) x = random.randint(10,740) self.letter_objects.append(Letter(c,img,x,level.step,level.delay)) # special threaded timer object self.timer = Timer.Timer(level.timersleep,self.drop_letter) self.timer.start() def drop_letter(self): """Called by the timer, and responsible for the letter dropping. This will get a letter from the letter_objects list and place it in the Sprite actives group, and thereby it will be blitted on the screen.""" try: obj = self.letter_objects.pop() except IndexError: return 0 Misc.actives.add(obj) return 1 def loop(self,events): item,self.score = None,0 for event in events: if event.type is KEYDOWN: item=event break try: v = Misc.actives.refresh(item)# this erase the sprites, calls their update method # and redraws them including a call to pygame.display.update # check the return val from a callback or on_update method # for the format see the reference if v: self.score = v[0][1] except: print trace_error() raise MyError if not Misc.actives.sprites() and not self.letter_objects: self.stop = -1 return self.stop,self.score def __str__(self): """Must return the original, not translated, title of this game. It's needed by the high score class of childsplay.""" return "Fallingletters" def helptitle(self): return _("Fallingletters") def help(self): text = [_("The aim of the game:"), _("Type the falling letters before they hit the ground."), " ", _("Difficulty : 4-7 years"), " ", _("Number of levels : 3")] return text