[Tutor] Fwd: high score list error and displaying text in the game/graphics window

D. Hartley denise.hartley at gmail.com
Tue Apr 19 00:15:44 CEST 2005


d'oh! here's the file I was supposed to attach:  

---------- Forwarded message ----------
From: D. Hartley <denise.hartley at gmail.com>
Date: Apr 18, 2005 3:14 PM
Subject: high score list error and displaying text in the game/graphics window
To: Python tutor <tutor at python.org>


Hi everyone!

Thanks for all your help/ideas for the high score list. I managed to
get one working! Well, almost ;)

It runs in the text (python) window, behind the graphics window. when
you dont make the high score list, it displays a "sorry" message, and
you can keep playing (i.e., hit y/n for a new game).

however if you DO make the high score list, there's a problem.  It
prompts you for your name (in the text window), and then displays the
high score list, just like it should.  But then when you click to the
game window to say y/n for another game, it all closes! (this is
double-clicking on the "play.py" icon).  If I open the doc in IDLE and
then hit F5, it'll let me click back to the game window and hit y/n to
play again, but I dont know why it's crashing the other way.  I've
attached the code file.  Can anyone offer any suggestions?

Alternately,  I'd LOVE to get the game to display all of the text
window messages (and ask for input if the user makes the high score
list) in the game/graphics window, NOT the text window. can anyone
tell me how to do this? it's using pygame.  I'd like to do it that way
anyway, and then also it would solve the problem of clicking back and
forth between the game screen and the python/text window.

Any ideas?

Thanks,

Denise
-------------- next part --------------
#!/usr/bin/env python

#------------------------------------------------------
# Spacin'Vaders 0.1
#
# Created by Rodrigo Vieira
# (icq, msn) = (9027513, rodrigo_eon at hotmail.com)
# email = rodrigo74 at gmail.com
#
# License: GPL
#
# Have fun! Feel free to contact me for comments,
# questions or new features :)
#
# Check README.txt for more info
#------------------------------------------------------

#Import Modules
import os, pygame
import random
from pygame.locals import *
from livewires import *
import pickle

fullscreen = 0 #1: starts on fullscreen, 0: starts windowed

def load_image(name, colorkey=None):
    """loads one image in memory"""
    fullname = os.path.join('data', name)
    try:
        image = pygame.image.load(fullname)
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    image = image.convert()
    if colorkey is not None:
        if colorkey is -1:
            colorkey = image.get_at((0,0))
        image.set_colorkey(colorkey, RLEACCEL)
    return image, image.get_rect()


def load_sound(name):
    """loads a sound file (.wav) in memory"""
    class NoneSound:
        def play(self): pass
    if not pygame.mixer or not pygame.mixer.get_init():
        return NoneSound()
    fullname = os.path.join('data', name)
    try:
        sound = pygame.mixer.Sound(fullname)
    except pygame.error, message:
        print 'Cannot load sound:', fullname
        raise SystemExit, message
    return sound


class LifeSprites(pygame.sprite.RenderClear):
    """This class shows the lives left at the bottom-right corner of the screen"""
    def __init__(self, lives):
        pygame.sprite.RenderClear.__init__(self)
        self.startx = 630
        self.starty = 460
        for i in xrange(lives-1):
            s = pygame.sprite.Sprite()
            s.image, s.rect = load_image('ranch_ship_small.bmp', -1)
            s.rect.centerx = self.startx - (i*17)
            s.rect.centery = self.starty
            self.add(s)

    def update(self, lives):
        for sprite in self.sprites():
            sprite.kill()
        for i in xrange(lives-1):
            #create the new one
            s = pygame.sprite.Sprite()
            if i < lives-1:
                s.image, s.rect = load_image('ranch_ship_small.bmp', -1)
            else:
                s.image, s.rect = load_image('blank.bmp', -1)
            s.rect.centerx = self.startx - (i*17)
            s.rect.centery = self.starty
            self.add(s)

    
class ScoreSprites(pygame.sprite.RenderClear):
    """This class shows the score on screen"""
    def __init__(self):
        pygame.sprite.RenderClear.__init__(self)
        #create the inner digit-sprites
        self.startx = 540
        self.starty = 12
        self.img_list = []
        self._sprites = []
        for i in xrange(10):
            self.img_list.append(pygame.image.load(os.path.join('data', str(i) + '.gif')))
        for i in xrange(8):
            s = pygame.sprite.Sprite()
            s.image, s.rect = load_image('0.gif', -1)
            s.rect.centerx = self.startx + (i*11)
            s.rect.centery = self.starty
            self.add(s)
            self._sprites.append(s)

    def update(self, value):
        #pad the value with 0s in the left
        s_value = str(value).zfill(8)
        #write the number
        for i in xrange(8):
            self._sprites[i].image = self.img_list[int(s_value[i])]
        

class EnemySprites(pygame.sprite.RenderClear):
    """This class will hold all the enemy ships (the vader helmets)"""
    def __init__(self, speed):
        pygame.sprite.RenderClear.__init__(self)
        
        #this variable indicates if the enemies 
        #are moving to the left (-1) or right (1)
        self.direction = 1 
        
        #this variable controls if it's time to move the enemies 
        self.counter = 0
        
        #this variable checks if it's time for the enemies to move down
        self.jump_counter = 0
        
        #this one sets how fast the enemies move
        self.speed = speed

        #the sound that plays everytime the enemy moves
        self.moveSound =  load_sound("fx.wav")

    def update(self):
        self.counter += 1
        if self.counter >= 50 - (self.speed * 5): #time to move the enemies?
            self.counter = 0
            self.jump_counter += 1
            go_down = False
            if self.jump_counter > 4: #time to move down and change direction?
                self.jump_counter = 0
                self.direction *= -1
                go_down = True

            #move the enemies!
            self.moveSound.play()
            pygame.sprite.RenderClear.update(self, self.direction, go_down)

    def lowerEnemy(self):
        lower = 0
        for e in self.sprites():
            if e.rect.centery > lower:
                lower = e.rect.centery
        return lower


class Enemy(pygame.sprite.Sprite):
    """This class is for each enemy ship"""
    def __init__(self,startx, starty):
        pygame.sprite.Sprite.__init__(self) #call Sprite intializer
        self.image, self.rect = load_image('pizza_ship.bmp', -1)
        self.rect.centerx = startx
        self.rect.centery = starty
        
    def update(self, direction, go_down):
        jump = 40 #how much the vaders move to the right/left on each jump
        
        if go_down:
            #if a ship is moving down on this round,
            #it doesn't move on the x-axys
            self.rect.move_ip((0, 5))
        else:
            #move a ship in the x-axys.
            #if direction=1, it moves to the right; -1 to the left
            self.rect.move_ip((jump * direction, 0))
        
        #maybe it's time for a shot? :) 
        #the chances are 1/30
        dice = random.randint(0,30)
        global enemy_shot_sprites
        if dice == 1:
            shot = EnemyShot(self.rect.midtop)
            enemy_shot_sprites.add(shot)
    
class EnemyShot(pygame.sprite.Sprite):
    """class for enemy shot (red laser)"""
    def __init__(self, startpos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image('red_laser.bmp', -1)
        self.rect.centerx = startpos[0]
        self.rect.centery = startpos[1]
    
    def update(self):
        #move the enemy shot and kill itself
        #if it leaves the screen
        self.rect.move_ip((0,5))
        if self.rect.centery > 480:
            self.kill()

            
class Hero(pygame.sprite.Sprite):
    """This class is for the "hero" ship in the bottom"""
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image('ranch_ship.bmp', -1)
        self.blinking = 1 #the hero ship starts blinking (immune)
        self.visible = 1
        self.counter = 0
        self.blank_ship = pygame.image.load(os.path.join('data','blank.bmp'))
        self.normal_ship = pygame.image.load(os.path.join('data','ranch_ship.bmp'))
        #the ship starts around the center of the screen...
        self.rect.centerx = 300
        self.rect.centery = 440
        self.direction = 0 #the ship starts standing still

    def update(self):
        if self.blinking:
            self.counter += 1
            if self.counter % 10 == 0:
                if self.visible:
                    self.image = self.blank_ship
                else:
                    self.image = self.normal_ship
                self.visible = not self.visible
            if self.counter == 150:
                self.blinking = 0
                self.image = pygame.image.load(os.path.join('data','ranch_ship.bmp'))
                self.counter = 0
            colorkey = self.image.get_at((0,0))
            self.image.set_colorkey(colorkey, RLEACCEL)

            
        #check if the ship is out of bounds
        if self.rect.centerx < 20:
            self.rect.centerx = 20
        if self.rect.centerx > 620:
            self.rect.centerx = 620
        
        #move the ship to the left/right, if direction<>0
        self.rect.move_ip((self.direction * 6,0))

class HeroShot(pygame.sprite.Sprite):
    """class for a hero shot (white laser)"""
    def __init__(self, startpos):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_image('white_laser.bmp', -1)
        self.rect.centerx = startpos[0]
        self.rect.centery = startpos[1]
    
    def update(self):
        #moves the shot up, and kills itself
        #if it leaves the screen
        self.rect.move_ip((0,-5))
        if self.rect.centery < 0:
            self.kill()

def createEnemies(screen, speed):
    enemyship_sprites = EnemySprites(speed)
    for rows in xrange(5):
        for cols in xrange(8):
            enemyship_sprites.add(Enemy((cols*60)+20, (rows*40)+30))
    enemyship_sprites.draw(screen)
    return enemyship_sprites

def createHero(screen):
    global hero
    hero = Hero()
    hero_sprites = pygame.sprite.RenderClear()
    hero_sprites.add(hero)
    hero_sprites.draw(screen)
    return hero_sprites

def showGameOver(screen, background_image):
    sprites = pygame.sprite.RenderClear()
    s = pygame.sprite.Sprite()
    s.image, s.rect = load_image('game_over.GIF', -1)
    s.rect.centerx = 320
    s.rect.centery = 200
    sprites.add(s)
    sprites.clear(screen, background_image)
    sprites.draw(screen)

def main():
    """this function is called when the program starts.
       it initializes everything it needs, then runs in
       a loop until the function returns."""
    pygame.init()
    random.seed()
    total_enemy_hits = 0
    level = 1
    lives = 3
    print "You have", lives, "lives left"
    print "Level 1"

    global screen
    if fullscreen:
        screen = pygame.display.set_mode((640, 480), FULLSCREEN)
    else:
        screen = pygame.display.set_mode((640, 480))

    
    pygame.display.set_caption("Behold, the Awesome Power of Ranch: H.A.P.P.Y. B.I.R.T.H.D.A.Y. v1.0")
    enemy_speed = 1

    #Load music
    explode = load_sound("explode2.wav")
    clearAll = load_sound("impressive.wav")
    laser = load_sound("laser.wav")
    end = load_sound("explode2.wav")

    #load the background image
    background_image, background_rect = load_image('bluebg.bmp')
    screen.blit(background_image, (0,0))
    
    #create a holder for the hero and enemy shots
    hero_shot_sprites = pygame.sprite.RenderClear()
    global enemy_shot_sprites
    enemy_shot_sprites = pygame.sprite.RenderClear()

    #create the score and life sprites
    score_sprites = ScoreSprites()
    life_sprites = LifeSprites(lives)
    
    #create enemy ships!
    enemyship_sprites = createEnemies(screen, enemy_speed)
    
    #create our hero!
    global hero
    hero_sprites = createHero(screen)
    clock = pygame.time.Clock()
    running = 1
    paused = 0
    while running:
        # Make sure game doesn't run at more than 50 frames per second
        clock.tick(50)
        
        #get the keyboard events and act
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                if event.key == K_LEFT:
                    hero.direction = -1 #change the hero ship direction
                elif event.key == K_RIGHT:
                    hero.direction = 1  #change the hero ship direction
                elif event.key == K_UP or event.key == K_SPACE or event.key == K_s or event.key == K_LCTRL or event.key == K_RCTRL or event.key == K_d or event.key == K_f or event.key == K_a:
                    #shoots with s,d,f,a, UP or CTRL keys. 
                    if not hero.blinking:
                         hero_shot_sprites.add(HeroShot(hero.rect.midtop))
                         laser.play()
                elif event.key == K_ESCAPE:
                    running = 0 #leave if the user press ESC
                elif event.key == K_p:
                    paused = not paused
                elif event.key == K_q:
                    running = 0 #leave if the user press "q"
                elif event.key == K_F2 or event.key == K_RETURN:
                    pygame.display.toggle_fullscreen()
            elif event.type == KEYUP:
                #if the user leave the left/right buttons, stop moving
                #the hero ship
                if event.key == K_LEFT and hero.direction == -1:
                    hero.direction = 0
                elif event.key == K_RIGHT and hero.direction == 1:
                    hero.direction = 0
            elif event.type == QUIT:
                running = 0 #leave if the user close the window

        if not paused:
            #Clear Everything
            enemyship_sprites.clear(screen, background_image)
            hero_sprites.clear(screen, background_image)
            hero_shot_sprites.clear(screen, background_image)
            enemy_shot_sprites.clear(screen, background_image)
            score_sprites.clear(screen, background_image)
            life_sprites.clear(screen, background_image)
    
            #see if any hero shot collided with enemy shot
            for hit in pygame.sprite.groupcollide(enemy_shot_sprites, hero_shot_sprites, 1, 1):
                pass        
            
            #See if a hero shot hit any enemy vaders
            for hit in pygame.sprite.groupcollide(enemyship_sprites, hero_shot_sprites, 1, 1):
                #yay got one!
                explode.play()
                total_enemy_hits += 1
                if total_enemy_hits % 200 == 0:
                    #killed 200 vaders, got extra life!
                    lives += 1
                    print "You have", lives, "lives left"
                    
                
            #see if the hero was hit by enemy shots
            if not hero.blinking and lives > 0:
                for hit in pygame.sprite.groupcollide(enemy_shot_sprites, hero_sprites, 1, 1):
                    #ouch!!
                    explode.play()
                    hero.blinking = 1
                    lives -= 1
                    hero_sprites = createHero(screen)
                    print "You have", lives, "lives left"
                if enemyship_sprites.lowerEnemy() > 400:
                    #enemy is too low, so you die and the level restarts
                    explode.play()
                    hero.blinking = 1
                    lives -= 1
                    hero_sprites = createHero(screen)
                    enemyship_sprites = createEnemies(screen, enemy_speed)
                    print "You have", lives, "lives left"
                    
    
            if len(enemyship_sprites.sprites()) == 0:
                #you killed'em all!! reset the enemies and make the game a bit faster >:)
                clearAll.play()
                level += 1
                print "Level", level
                hero_shot_sprites = pygame.sprite.RenderClear()
                if enemy_speed < 8: #don't let it get _too_ fast!!!
                    enemy_speed += 1
                enemyship_sprites = createEnemies(screen, enemy_speed)
    
            #update everything
            enemyship_sprites.update()
            hero_sprites.update()
            hero_shot_sprites.update()
            enemy_shot_sprites.update()
            score_sprites.update(total_enemy_hits)
            life_sprites.update(lives)
    
            #Draw Everything
            enemyship_sprites.draw(screen)
            hero_sprites.draw(screen)
            hero_shot_sprites.draw(screen)
            enemy_shot_sprites.draw(screen)
            score_sprites.draw(screen)
            life_sprites.draw(screen)
    
            #game over..
            if lives == 0:
### trying addscore

                end.play()
                showGameOver(screen, background_image)                
                pygame.display.flip()

                def add_score():
                    high_scores = [(1000,"Denise"), (945,"Denise"),
                                   (883,"Denise"),(823,"Grant"),
                                   (779,"Aaron"), (702,"Pete"),
                                   (555,"Tom"), (443,"Tom"),
                                   (442,"Robin"), (4,"Pete")]
 #                   high_scores = pickle.load(file("scores.pik"))
                    score = total_enemy_hits
                    if score > high_scores[-1][0]:
                        print "Ta da! You got", total_enemy_hits, "Ranch Delivery Devices!"
                        name = read_string("You made the high score list! What's your name? ")
                        user_score = (score,name)
                        high_scores.append(user_score)
                        high_scores.sort(reverse=True)
                        del high_scores[-1]
  #                      pickle.dump(high_scores, file("scores.pik", "w"))
                        for score, name in high_scores:
                            slip = 30 - len(name)
                            slip_amt = slip*" "
                            prefix = 5*" "
                            print prefix,name,slip_amt,score
                    else:
                        print "Sorry, you only got", total_enemy_hits, "Ranch Delivery Devices."
                        print "You didn't quite make the high score list!"
                        for score, name in high_scores:
                            slip = 30 - len(name)
                            slip_amt = slip*" "
                            prefix = 5*" "
                            print prefix,name,slip_amt,score
                        print "Better luck next time!"
                
                add_score()

                answer = ""
                while not answer in ("y","n"):
                   for event in pygame.event.get():
                      if event.type == KEYDOWN:
                         if event.key == K_n:
                            answer = "n"
                         elif event.key == K_y:
                            answer = "y"
                if answer == "n":
                    running = 0
                else:
                    return 1
    
            #refresh the display
            pygame.event.pump()
            pygame.display.flip()

    #well, nice playing with you...
#    print "Ta da! You got", total_enemy_hits, "Ranch Delivery Devices!"
 #   add_score()
    screen = pygame.display.set_mode((640, 480))
    return 0

#this calls the 'main' function when this script is executed
if __name__ == '__main__':
    playing = 1
    while playing:
        playing = main()


More information about the Tutor mailing list