One Function per State
Part of the Game Rules section of Coddy's Pygame journey. Lesson 5 of 29.
The loop mixed three screens, and each new state would add another layer of if inside the drawing and the update. The starter gives each state its own function instead, and the loop picks one:
if state == "menu":
draw_menu()
elif state == "play":
play_frame()
else:
draw_over()play_frame() moves things, checks the hit and draws. draw_menu() and draw_over() only draw. The game over screen shows the frozen game under its message, so both use a shared draw_game() for the player, the rock and the score.
A function that changes the state or the score needs them after global:
def play_frame():
global score, stateMoving player.x needs no global: it changes the Rect, it does not assign a new one.
With this shape a new state is one function and one elif. Add a pause screen that way.
Challenge
Medium- Add a state
"paused": P during play pauses, P again goes back to play. - Write
draw_paused(): the frozen game withPausedcentred at (240, 160). - Call it from the loop while the state is
"paused", with one moreelif.
Try it yourself
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Meteor Dodge")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 32)
WHITE = (240, 240, 240)
def reset():
global player, rock, score
player = pygame.Rect(220, 300, 40, 40)
rock = pygame.Rect(random.randint(0, 456), -24, 24, 24)
score = 0
def draw_menu():
screen.fill((30, 30, 46))
title = font.render("Meteor Dodge", True, WHITE)
screen.blit(title, title.get_rect(center=(240, 140)))
hint = font.render("Press Enter to play", True, WHITE)
screen.blit(hint, hint.get_rect(center=(240, 200)))
def draw_game():
screen.fill((30, 30, 46))
pygame.draw.rect(screen, (255, 196, 0), player)
pygame.draw.rect(screen, (235, 80, 80), rock)
score_text = font.render(f"Score: {score}", True, WHITE)
screen.blit(score_text, (10, 10))
def play_frame():
global score, state
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 6
if keys[pygame.K_RIGHT]:
player.x += 6
player.clamp_ip(screen.get_rect())
rock.y += 4
if rock.top > 360:
rock.y = -24
rock.x = random.randint(0, 456)
score += 1
if rock.colliderect(player):
state = "over"
draw_game()
def draw_over():
draw_game()
message = font.render("Game over", True, WHITE)
screen.blit(message, message.get_rect(center=(240, 160)))
hint = font.render("Press R to play again", True, WHITE)
screen.blit(hint, hint.get_rect(center=(240, 200)))
reset()
state = "menu"
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN and state == "menu":
state = "play"
elif event.key == pygame.K_r and state == "over":
reset()
state = "play"
if state == "menu":
draw_menu()
elif state == "play":
play_frame()
else:
draw_over()
pygame.display.flip()
clock.tick(60)
pygame.quit()
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Game Rules
1Game States
A State VariableA Menu ScreenPress R to Play AgainA Reset FunctionOne Function per StatePractice on your own: Pygame playground