When I make a new screen in pygame, you have to repeatedly click the exit button to close the window
Question:
In my PyGame game, when the player dies, I run a game_over()
function, which displays a screen with "GAME OVER Press E to exit or R to restart." But, while this is running, if you try to close the window, you have to click multiple times, and same goes for pressing E. Even if you press R and restart, you have to do this, but not before game_over()
has run.
Here is game_over()
:
def game_over():
running = False
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.score = 0
main()
break
if event.key == pygame.K_e:
running = True
pygame.QUIT
WIN.fill(BLACK)
game_over = BIGFONT.render('GAME OVER', False, WHITE)
WIN.blit(game_over, (200, 175))
instructions = SMALLFONT.render(f'You scored {player.score}. Press R to restart or E to exit', False, WHITE)
WIN.blit(instructions, (145, 290))
pygame.display.flip()
And here is the full code:
import pygame, random
pygame.init()
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('game')
BLOCK_MOVEMENT_TIMER_EVENT = pygame.USEREVENT + 1
BLOCK_MOVEMENT_TIME_DELAY = 15
pygame.time.set_timer(BLOCK_MOVEMENT_TIMER_EVENT , BLOCK_MOVEMENT_TIME_DELAY)
BLOCK_CREATE_TIMER_EVENT = pygame.USEREVENT + 2
BLOCK_CREATE_TIME_DELAY = 1500
pygame.time.set_timer(BLOCK_CREATE_TIMER_EVENT, BLOCK_CREATE_TIME_DELAY)
FPS = 60
#colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BIGFONT = pygame.font.Font('Retro.ttf', 65)
SMALLFONT = pygame.font.Font('Retro.ttf', 20)
FLOOR = pygame.Rect(0, 400, 900, 5)
class Player:
def __init__(self):
self.size = 20
self.x = 75
self.y = 380
self.jumping = False
self.fall = False
self.update_rect()
self.score = 0
def update_rect(self):
self.rect = pygame.Rect(self.x, self.y, self.size, self.size)
def jump(self):
pressed = pygame.key.get_pressed()
if pressed[pygame.K_SPACE] and not self.fall:
self.jumping = True
if self.jumping:
self.y -= 3
if self.y < 300:
self.y = 300
self.fall = True
self.jumping = False
if self.fall:
self.y += 3
if self.y > 380:
self.y = 380
self.fall = False
self.update_rect()
player = Player()
class Obstacles:
def __init__(self, width, height):
self.x = 900
self.y = HEIGHT - height - 100
self.width = width
self.height = height
self.update_rect()
def update_rect(self):
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
def move_obstacles(obstacle_list):
for obstacle in obstacle_list:
obstacle.x -= 3
if obstacle.x < -100:
obstacle_list.pop(0)
player.score += 1
obstacle.update_rect()
def add_obstacle(obstacle_list):
obstacle1 = Obstacles(20, 40)
obstacle2 = Obstacles(75, 20)
obstacle3 = Obstacles(35, 35)
obstacle4 = Obstacles(50, 25)
obstacle5 = Obstacles(80, 10)
obstacle6 = Obstacles(40, 20)
obstacle7 = Obstacles(20, 30)
obstacle_options = [obstacle1, obstacle2, obstacle3, obstacle4, obstacle5, obstacle6, obstacle7]
obstacle_list.append(obstacle_options[random.randint(0, 6)])
def is_game_over(obstacle_list):
for obstacle in obstacle_list:
if player.rect.colliderect(obstacle):
return True
def game_over():
running = False
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.score = 0
main()
break
if event.key == pygame.K_e:
running = True
pygame.QUIT
WIN.fill(BLACK)
game_over = BIGFONT.render('GAME OVER', False, WHITE)
WIN.blit(game_over, (200, 175))
instructions = SMALLFONT.render(f'You scored {player.score}. Press R to restart or E to exit', False, WHITE)
WIN.blit(instructions, (145, 290))
pygame.display.flip()
def draw_window(obstacle_list, is_game_over):
WIN.fill(BLACK)
pygame.draw.rect(WIN, WHITE, FLOOR)
pygame.draw.rect(WIN, WHITE, player.rect)
for obstacle in obstacle_list:
pygame.draw.rect(WIN, RED, obstacle.rect)
score_counter = BIGFONT.render(f'SCORE {player.score}', False, (255, 255, 255))
WIN.blit(score_counter, (240, 100))
pygame.display.flip()
def main():
clock = pygame.time.Clock()
obstacle_list = []
done = False
while not done:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.QUIT
if event.type == BLOCK_MOVEMENT_TIMER_EVENT:
move_obstacles(obstacle_list)
if event.type == BLOCK_CREATE_TIMER_EVENT:
add_obstacle(obstacle_list)
draw_window(obstacle_list, is_game_over(obstacle_list))
player.jump()
is_game_over(obstacle_list)
if is_game_over(obstacle_list):
game_over()
done = True
pygame.display.flip()
if __name__ == '__main__':
main()
Thank you in advance!
Answers:
Here, and with e
, you set running
to True, which breaks that loop. The following line pygame.QUIT
does nothing; pygame.QUIT
is a variable, not a function. You probably meant pygame.quit()
.
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
It would, however, be better if game_over()
were to return a restart
bool, then main
handles either restarting or just sets done
to True and lets the main
loop end naturally.
if game_over():
done = True
else:
reset()
In my PyGame game, when the player dies, I run a game_over()
function, which displays a screen with "GAME OVER Press E to exit or R to restart." But, while this is running, if you try to close the window, you have to click multiple times, and same goes for pressing E. Even if you press R and restart, you have to do this, but not before game_over()
has run.
Here is game_over()
:
def game_over():
running = False
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.score = 0
main()
break
if event.key == pygame.K_e:
running = True
pygame.QUIT
WIN.fill(BLACK)
game_over = BIGFONT.render('GAME OVER', False, WHITE)
WIN.blit(game_over, (200, 175))
instructions = SMALLFONT.render(f'You scored {player.score}. Press R to restart or E to exit', False, WHITE)
WIN.blit(instructions, (145, 290))
pygame.display.flip()
And here is the full code:
import pygame, random
pygame.init()
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('game')
BLOCK_MOVEMENT_TIMER_EVENT = pygame.USEREVENT + 1
BLOCK_MOVEMENT_TIME_DELAY = 15
pygame.time.set_timer(BLOCK_MOVEMENT_TIMER_EVENT , BLOCK_MOVEMENT_TIME_DELAY)
BLOCK_CREATE_TIMER_EVENT = pygame.USEREVENT + 2
BLOCK_CREATE_TIME_DELAY = 1500
pygame.time.set_timer(BLOCK_CREATE_TIMER_EVENT, BLOCK_CREATE_TIME_DELAY)
FPS = 60
#colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BIGFONT = pygame.font.Font('Retro.ttf', 65)
SMALLFONT = pygame.font.Font('Retro.ttf', 20)
FLOOR = pygame.Rect(0, 400, 900, 5)
class Player:
def __init__(self):
self.size = 20
self.x = 75
self.y = 380
self.jumping = False
self.fall = False
self.update_rect()
self.score = 0
def update_rect(self):
self.rect = pygame.Rect(self.x, self.y, self.size, self.size)
def jump(self):
pressed = pygame.key.get_pressed()
if pressed[pygame.K_SPACE] and not self.fall:
self.jumping = True
if self.jumping:
self.y -= 3
if self.y < 300:
self.y = 300
self.fall = True
self.jumping = False
if self.fall:
self.y += 3
if self.y > 380:
self.y = 380
self.fall = False
self.update_rect()
player = Player()
class Obstacles:
def __init__(self, width, height):
self.x = 900
self.y = HEIGHT - height - 100
self.width = width
self.height = height
self.update_rect()
def update_rect(self):
self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
def move_obstacles(obstacle_list):
for obstacle in obstacle_list:
obstacle.x -= 3
if obstacle.x < -100:
obstacle_list.pop(0)
player.score += 1
obstacle.update_rect()
def add_obstacle(obstacle_list):
obstacle1 = Obstacles(20, 40)
obstacle2 = Obstacles(75, 20)
obstacle3 = Obstacles(35, 35)
obstacle4 = Obstacles(50, 25)
obstacle5 = Obstacles(80, 10)
obstacle6 = Obstacles(40, 20)
obstacle7 = Obstacles(20, 30)
obstacle_options = [obstacle1, obstacle2, obstacle3, obstacle4, obstacle5, obstacle6, obstacle7]
obstacle_list.append(obstacle_options[random.randint(0, 6)])
def is_game_over(obstacle_list):
for obstacle in obstacle_list:
if player.rect.colliderect(obstacle):
return True
def game_over():
running = False
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
player.score = 0
main()
break
if event.key == pygame.K_e:
running = True
pygame.QUIT
WIN.fill(BLACK)
game_over = BIGFONT.render('GAME OVER', False, WHITE)
WIN.blit(game_over, (200, 175))
instructions = SMALLFONT.render(f'You scored {player.score}. Press R to restart or E to exit', False, WHITE)
WIN.blit(instructions, (145, 290))
pygame.display.flip()
def draw_window(obstacle_list, is_game_over):
WIN.fill(BLACK)
pygame.draw.rect(WIN, WHITE, FLOOR)
pygame.draw.rect(WIN, WHITE, player.rect)
for obstacle in obstacle_list:
pygame.draw.rect(WIN, RED, obstacle.rect)
score_counter = BIGFONT.render(f'SCORE {player.score}', False, (255, 255, 255))
WIN.blit(score_counter, (240, 100))
pygame.display.flip()
def main():
clock = pygame.time.Clock()
obstacle_list = []
done = False
while not done:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
pygame.QUIT
if event.type == BLOCK_MOVEMENT_TIMER_EVENT:
move_obstacles(obstacle_list)
if event.type == BLOCK_CREATE_TIMER_EVENT:
add_obstacle(obstacle_list)
draw_window(obstacle_list, is_game_over(obstacle_list))
player.jump()
is_game_over(obstacle_list)
if is_game_over(obstacle_list):
game_over()
done = True
pygame.display.flip()
if __name__ == '__main__':
main()
Thank you in advance!
Here, and with e
, you set running
to True, which breaks that loop. The following line pygame.QUIT
does nothing; pygame.QUIT
is a variable, not a function. You probably meant pygame.quit()
.
while not running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = True
pygame.QUIT
It would, however, be better if game_over()
were to return a restart
bool, then main
handles either restarting or just sets done
to True and lets the main
loop end naturally.
if game_over():
done = True
else:
reset()