Hello, group! I am asking anyone who is knowledgeable about entering text into the text window while a game/graphics window is running (am using pygame). I have asked this on the 'tutor' mailing list and no one could/would answer it. I am making a space invaders clone for my Python Teacher's birthday, and so obviously can not ask him for help! Even the debugger wouldn't shed light on the situation, due to when it happens:
I am trying to make a high score list. If you do not score high enough, the list displays in the text window (fine), and you can type y/n in the game window for a new game. If you DO make the high score list, it prompts you to enter your name on the text window (and hit enter), and displays the updated score list (great). However, when I click back to the graphics window, the whole thing closes/shuts down/crashes. For the life of me I cant figure it out. I have looked at the order of my steps, I've tried to follow it through piece by piece, and like I said I tried to use the debugger to step through it - but since the game just closes out, it doesnt tell me anything. 1. How can I stop this crash from happening? I have copied and pasted the "game over" section of my code below, and am attaching the entire code to the email, in case that would be helpful. 2. I'd REALLY like to make it display the high scores/prompt for user name on the game/graphics window, not in the text window, anyway - and that would eliminate the problem it seems to have when using keystrokes in the text window and then trying to switch back to the game window. (it's not a click-specific issue, alt-tab does it too). I apologize for the "newbie" nature of this question to a more advanced list, but I have tried everything else I can think of and am at my wits' end. The 'deadline' (birthday) is in a week and I'm stuck. I'd appreciate any comments or suggestions you might have, in as simple of language as you can offer them, ha ha. I *am* new to python, and so my code may not be so elegant. But I hope you can read it enough to see what I'm doing wrong or possibly just offer suggestions for displaying it all in the graphics window and avoiding the problem altogether. Thank you so much for your time and ideas! Sincerely, Denise #game over.. if lives == 0: def add_score(): 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() end.play() showGameOver(screen, background_image) pygame.display.flip() 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... screen = pygame.display.set_mode((640, 480)) return 0
#!/usr/bin/env python #------------------------------------------------------ # Spacin'Vaders 0.1 # # Created by Rodrigo Vieira # (icq, msn) = (9027513, [EMAIL PROTECTED]) # email = [EMAIL PROTECTED] # # 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 # for debugging: import pdb 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 Enemy2(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('vader.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 Enemy3(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('berry.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 createEnemies2(screen, speed): enemyship_sprites2 = EnemySprites(speed) for rows in xrange(5): for cols in xrange(8): enemyship_sprites2.add(Enemy2((cols*60)+20, (rows*40)+30)) enemyship_sprites2.draw(screen) return enemyship_sprites2 def createEnemies3(screen, speed): enemyship_sprites3 = EnemySprites(speed) for rows in xrange(5): for cols in xrange(8): enemyship_sprites3.add(Enemy3((cols*60)+20, (rows*40)+30)) enemyship_sprites3.draw(screen) return enemyship_sprites3 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", level 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 if level == 2: enemyship_sprites = createEnemies2(screen, enemy_speed) elif level == 3: enemyship_sprites = createEnemies3(screen, enemy_speed) else: 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 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!" # pdb.set_trace() add_score() end.play() showGameOver(screen, background_image) pygame.display.flip() 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... 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()
-- http://mail.python.org/mailman/listinfo/python-list