user2977298
user2977298

Reputation: 1

Pygame game loop trouble

I am a novice programming a game in the Python language using Pygame. I'm having a problem with my game loop. I can only run my game once then I can't make my game loop again. I will post my code below here:

This is my mouse based menu (Menu.py)

import pygame, os, sys
from pygame.locals import *
pygame.init()

def play_music(name, volume=0.7, loop=-1):
    fullname = os.path.join('data', name)
    try:
        pygame.mixer.music.load(fullname)
        pygame.mixer.music.set_volume(volume)
        pygame.mixer.music.play(loop)
    except:
        raise SystemExit, "Can't load: " + fullname

def load_sound(name, volume=0.05):
    fullname = os.path.join('data', name)
    try:
        sound = pygame.mixer.Sound(fullname)
        sound.set_volume(volume)
    except:
        raise SystemExit, "Can't load: " + fullname
    return sound

def run_game():
    import Grab

def reset_highscore():
    open("data/highscore.sav", "w").write(str(0))
    print "Grab High score reset to 0"

class GrabMenu():
    os.environ["SDL_VIDEO_CENTERED"] = "1"
    pygame.mouse.set_visible(0) #make the mouse cursor invisible
    pygame.display.set_caption("Grab") #name the game
    pygame.display.set_icon(pygame.image.load("data/Icon.png")) #set an icon for the game
    screen = pygame.display.set_mode((800, 800)) #screen resolution width and height
    background = pygame.Surface(screen.get_size()) #make the background
    background = pygame.image.load("data/BG.png").convert() #convert background 
    background = pygame.transform.scale(background,(800, 800)) #scale the background down to the screen resulution
    cursor = pygame.image.load("data/Hand1.png") #make a new cursor inside the game
    WHITE = (255, 255, 255) # colors
    YELLOW = (255, 216, 0)
    running = True # value for main loop
    clock = pygame.time.Clock()
    font = pygame.font.SysFont("times new roman", 28, bold=True) # menu font and text.
    fontcolor = WHITE
    fontcolor2 = WHITE
    fontcolor3 = WHITE
    fontcolor4 = WHITE
    mousetrigger = False
    mouseclick = load_sound("Click.wav", 3.5) # mouse click
    Menu1 = True
    Menu2 = False #options menu
    Menu3 = False #reset score menu
    #JOYSTICK
    try:
        j = pygame.joystick.Joystick(0) # create a joystick instance
        j.init() # init instance
        print 'Enabled joystick: ' + j.get_name()
    except:
        pass

    #main_loop
    while running == True:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                running = False, sys.exit()
            if event.type == MOUSEBUTTONDOWN and event.button == 1: # if mouse button is pressed, (left mouse key only)
                if Menu1:
                    if ren_r.collidepoint(pygame.mouse.get_pos()): # play the game
                        if Menu1 == False:
                            pass
                        else:
                            mouseclick.play()
                            run_game()
                    elif ren2_r.collidepoint(pygame.mouse.get_pos()): #options
                        if Menu1 == False:
                            pass
                        else:
                            mouseclick.play()
                            Menu1 = False
                            Menu2 = True
                    elif ren3_r.collidepoint(pygame.mouse.get_pos()): #how to play
                        if Menu1 == False:
                            pass
                        else:
                            mouseclick.play()
                    elif ren4_r.collidepoint(pygame.mouse.get_pos()): #quit the game
                        if Menu1 == False:
                            pass
                        else:
                            mouseclick.play()
                            running = False, pygame.quit(), sys.exit()
                elif Menu2:
                    if ren5_r.collidepoint(pygame.mouse.get_pos()): #reset high score
                        mouseclick.play()
                        reset_highscore()

                    elif ren6_r.collidepoint(pygame.mouse.get_pos()): #go back
                        mouseclick.play()
                        Menu1 = True
                        Menu2 = False

        screen.blit(background, (0, 0)) #draw the background
        screen.blit(cursor, pygame.mouse.get_pos()) #set the cursor image as the new mouse cursor

        if Menu1:
            ren = font.render("Play", True, (fontcolor))
            ren_r = ren.get_rect()
            ren_r.x, ren_r.y = 340, 530

            ren2 = font.render("Options", True, (fontcolor2))
            ren2_r = ren2.get_rect()
            ren2_r.x, ren2_r.y = 340, 590

            ren3 = font.render("How to Play", True, (fontcolor3))
            ren3_r = ren3.get_rect()
            ren3_r.x, ren3_r.y = 340, 650

            ren4 = font.render("Quit Game", True, (fontcolor4))
            ren4_r = ren4.get_rect()
            ren4_r.x, ren4_r.y = 340, 710

            screen.blit(ren, (340, 530))
            screen.blit(ren2, (340, 590))
            screen.blit(ren3, (340, 650))
            screen.blit(ren4, (340, 710))

            if ren_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor = YELLOW
            else:
                fontcolor = WHITE

            if ren2_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor2 = YELLOW
            else:
                fontcolor2 = WHITE

            if ren3_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor3 = YELLOW
            else:
                fontcolor3 = WHITE

            if ren4_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor4 = YELLOW
            else:
                fontcolor4 = WHITE

        elif Menu2:
            options = font.render("Options", 1, (WHITE))

            ren5 = font.render("Reset High Score", True, (fontcolor))
            ren5_r = ren5.get_rect()
            ren5_r.x, ren5_r.y = 350, 650

            ren6 = font.render("Go back", True, (fontcolor2))
            ren6_r = ren6.get_rect()
            ren6_r.x, ren6_r.y = 350, 700

            screen.blit(options, (350, 600))
            screen.blit(ren5, (350, 650))
            screen.blit(ren6, (350, 700))

            if ren5_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor = YELLOW
            else:
                fontcolor = WHITE

            if ren6_r.collidepoint(pygame.mouse.get_pos()):
                mousetrigger = True
                fontcolor2 = YELLOW
            else:
                fontcolor2 = WHITE

        pygame.display.update()

furthermore I use this when I press on "Play" text on my menu:

def run_game():
    import Grab

to start my main program "Grab.py":

import pygame, time, math, sys, random, os
from pygame.locals import *
pygame.init() #make pygame ready
pygame.joystick.init

#my game code
done = False

while done == False:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True                   
        elif event.key == K_ESCAPE:
            if highscore == 0:
                pass
            if highscore < get_highscore():
                pass
            else:
                save_highscore(highscore)
            if score == 0:
                pass
            else:
                save_score(score)
            save_level(level)
            save_world(world)
            done = True 
            pygame.mixer.music.stop()

Main game loop ends here and sends me back to my menu just like I want. However, when I try to import grab again from my menu then nothing happens. I went and searched for "Python import cycle" from Google and I discovered a few things but i'm still stuck. There must be an easier way to make Grab.py loop from this:

def run_game():
    import Grab

Any help is very much appreciated. Regards HJ.

Upvotes: 0

Views: 2214

Answers (1)

unutbu
unutbu

Reputation: 879123

Generally speaking, use import to load the definition of constants, functions or classes. Do not use it to run a bunch of statements. Call a function to run a bunch of statements.

For efficiency, Python only imports modules once. After it is loaded the first time, the module is cached in sys.modules. Every time Python encounters an import statement it check if the module is in sys.modules and uses the cached module if it exists. Only if the module is not in sys.modules does Python execute the code in the module. Thus the code in the module is never executed more than once. That is why import Grab does not execute the code in Grab.py the second time the import statement is reached.

So, instead, refactor Grab.py to put all the code you wish to run multiple times inside a function:

import pygame, time, math, sys, random, os
from pygame.locals import *
pygame.init() #make pygame ready
pygame.joystick.init()   # <-- Note you need parentheses to *call* the init function

def main():
    done = False

    while done == False:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True                   
            elif event.key == K_ESCAPE:
                if highscore == 0:
                    pass
                if highscore < get_highscore():
                    pass
                else:
                    save_highscore(highscore)
                if score == 0:
                    pass
                else:
                    save_score(score)
                save_level(level)
                save_world(world)
                done = True 
                pygame.mixer.music.stop()

and then change

import Grab

to

import Grab    
Grab.main()        

You could move import Grab to the top of Menu.py; generally speaking it is recommended to put all the import statements at the top of any Python script or module.

Upvotes: 3

Related Questions