#~ /*************************************************************************** #~ * soundmemory.py #~ * #~ * Fri Oct 22 08:54:33 2004 #~ * Copyright 2004 Stas #~ * stas@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, 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to # the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. # DEBUG = 0 RCFILE = 0 import os,sys,random import pygame from pygame.constants import * from utils import load_image,MyError,import_module,trace_error from SpriteUtils import CPSprite,CPinit class Img: """ Container to store image objects""" pass class Snd: """ Container to store sound objects""" pass class Misc: """ Container to store all kind of stuff""" pass NOSOUNDTXT = """It seems that we cannot use the sound card right now and because this game is all about sound, we just quit. This problem can also be caused by another application which uses the soundcard right now.""" class SndBut(CPSprite): Selected = None # This is a global reference to hold a selected object def __init__(self,snd,pos): CPSprite.__init__(self) self.snd = snd # self.img and self.img_high are set in the Game class self.image = self.img.convert()# self.image and self.rect are mandatory for the pygame sprite class self.rect = self.image.get_rect().move(pos) self.high = 0 # used to signal highlight or not self.connect_callback(self.on_select_button, MOUSEBUTTONDOWN) # MOUSEBUTTONDOWN = pygame constant def play(self): self.snd.play() def highlight(self): if self.high:# we use a flag, because the images used are references. self.image = self.img self.high = 0 else: self.image = self.img_high self.high = 1 r = Img.screen.blit(self.image,self.rect) pygame.display.update(r) def on_update(self,*args): """ This is called when there's no callback function registered with the connect_callback method.""" pass # we use callbacks, this is just as an example def on_select_button(obj,event,*args): """ This is a callback function used by a CPSprite object, like the callback fuctions in gtk++. A callback function must be connected to the object with a call to the connect_callback method. When this fuction is called by the class it is called with a tuple of arguments. This tuple consist of: 0 - a reference to the connected object. 1 - the event that triggers this call. 2 .. - data which where passed to the connect call. """ if DEBUG: print " obj,event,*args",obj,event,args if not SndBut.Selected: # nothing selected yet obj.play() # play the sound obj.highlight() # toggle the high light button SndBut.Selected = obj # store reference to compare when there's a second selection return if obj.rect is SndBut.Selected.rect:# selected the same object twice, do nothing return obj.play() obj.highlight() pygame.time.wait(1500) if SndBut.Selected.snd is obj.snd: # sounds are the same SndBut.Selected.remove_sprite()# remove sprite object obj.remove_sprite()# remove SndBut.Selected = None Misc.score = 1 else: SndBut.Selected.highlight() #toggle highlight to normal obj.highlight() SndBut.Selected = None class Game: """ soundmemory.py - part of childsplay.py, a suite of educational games for young children. """ def __init__(self,screen,backgr,rc_dic,basepath,libdir): self.screen = screen self.backgr = backgr back_img = load_image(os.path.join(libdir,'SoundMemory','but_back.png')) s = pygame.Surface((768, 468)).convert() for y in range(0,257, 256): for x in range(0, 513, 256): s.blit(back_img, (x,y)) pygame.draw.rect(s, (0,0,0), s.get_rect(), 6)# draw a box self.s = s # store two surfaces for later use Img.screen = self.screen Img.backgr = self.backgr self.rc_dic = rc_dic self.basedir = basepath self.libdir = libdir try: import pyassetmlSDL #assetmlSDL = import_module(os.path.join(self.basedir,'pyassetmlSDL.py')) except (ImportError,MyError),info: print >> sys.stderr,info,"\nThis version of childsplay depends on pyassetmlSDL" text = "Module memory fails to import pyassetmlSDL" raise MyError,text # create two assetmlSDL instances one for parsing memory sounds and one for CP sounds self.Assets_snd = pyassetmlSDL.AssetmlSDL() self.Assets_snd.set_mldir('childsplay/sounds-misc/sounds-misc.assetml') self.Assets_cpsnd = pyassetmlSDL.AssetmlSDL() self.Assets_cpsnd.set_mldir('childsplay/childsplay-sounds/childsplay-sounds.assetml') # number of items y, number of items y, x offset, y offset self.gamelevels = [(2,3,200,100),(2,4,180,100),(3,4,180,60),(4,6,50,20)] #self.gamelevels =[(3,4,90)] self.gameitems = [None] self.group = CPinit(self.screen,self.backgr) self._setup() def _setup(self): # Sound becomes self.Sound., self.Sound. ... etc self.Sound = Snd()# get a instance for passing to assetmlSDL self.Image = Img() files = (('*.ogg',))# sequence of one will return all the ogg files from assetml # See pyassetmlSDL.py get_assets docstring for this special sequence. d = self.Assets_snd.get_assets(files) try: objects = d.values() except AttributeError,info: print >> sys.stderr, "Can't find sounds",info raise MyError,info if DEBUG: print "dictionary from assetmlSDL",d,"/nvalues from dict ",objects if not pygame.mixer.get_init(): MyError.name = str(self) MyError.extra = NOSOUNDTXT raise MyError if len(objects) < 12: print >> sys.stderr, "Not enough sounds found, must be at least 12" raise MyError,info self.snd_objects = objects if DEBUG: print "snd_objects",self.snd_objects # set images to class. We do this outside the class defenition because we # don't have a reference to the libdir until now. # And we use the same images for all the buttons.Also we check the sound objects for equality # not the images. SndBut.img = load_image(os.path.join(self.libdir,'SoundMemory','but_bleu_up.png'),1) SndBut.img_high = load_image(os.path.join(self.libdir,'SoundMemory','but_red_down.png'),1) def start(self,l,spam): """Hit the buttons and find pairs""" # stop and score are stored in class object to be used globally # restore screen self.screen.blit(self.s,(16,16)) self.backgr.blit(self.s,(16,16)) pygame.display.update() Misc.stop = 0 Misc.score = 0 r, c ,xoffset, yoffset = l x_offset = SndBut.img.get_width()+ 16 y_offset = SndBut.img.get_height() + 16 # shuffle sounds random.shuffle(self.snd_objects) num = (r * c)/2 objects = self.snd_objects[:num] * 2 random.shuffle(objects) for y in range(r): for x in range(c): obj = SndBut(objects.pop(),(xoffset + x*x_offset,yoffset + y*y_offset)) # if we don't use callbacks you could do: # SndBut(self.snd_...) the instance adds itself to the group and everything in a group # gets rendered whit a call to .draw() -> list of rects -> display.update(list) # (see pygame docs, sprite class) self.group.add(obj) def loop(self,events): item,Misc.score = None,0 for event in events: if event.type is MOUSEBUTTONDOWN: item = event break try: v = self.group.refresh(item)# Check all objects in group for callback function if v: print "return from refresh",v except: print trace_error() raise MyError # check if there objects left in the sprite group if not self.group.sprites(): Misc.stop = -1 Misc.score = 100 if DEBUG and Misc.score: print "self.score",Misc.score return Misc.stop,Misc.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 "Soundmemory" def helptitle(self): return "Soundmemory" def help(self): text = [_("The aim of the game:"), _("Classic memory game where you have to find pairs of sounds."), " ", _("Difficulty : 2-5 years"), " ", _("Number of levels : 4")] return text