Reputation: 1
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
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