Menu
CoddyTech

Un menu per Corridore del cielo

Fa parte della sezione Regole di gioco del percorso Pygame di Coddy. Lezione 29 di 30.

Sky Runner prende le regole da questa sezione, iniziando con un menu. Una nuova partita deve ripartire da zero, quindi inserisci tutto in reset(): un nuovo runner, un gruppo vuoto, la velocità e il punteggio, e riavvia entrambi i timer.

Ora la barra spaziatrice svolge due funzioni, una per ogni stato:

if state == "play":
    runner.jump()
elif state == "menu":
    reset()
    state = "play"

Il menu ha bisogno di due righe centrate e la schermata di fine partita ne avrà bisogno di tre, quindi una piccola funzione disegna una riga centrata su x 320:

def show(text, text_font, y):
    picture = text_font.render(text, True, INK)
    screen.blit(picture, picture.get_rect(center=(320, y)))

Il punteggio appartiene a una partita, quindi mostralo solo dopo che è iniziata, non nel menu.

challenge icon

Sfida

Medio

Aggiungi un menu a Sky Runner.

  1. Scrivi reset() per il runner, il gruppo, speed, score e i due timer; chiamala prima del ciclo e imposta state = "menu".
  2. Nel menu, usa show() per Sky Runner in big_font e Press Space to start; mostra il punteggio solo fuori dal menu.
  3. Premendo Spazio nel menu, si chiama reset() e si imposta state = "play".

Premi «Gioca»: Spazio avvia una partita. Poi premi «Verifica».

Provalo tu

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((640, 320))
pygame.display.set_caption("Sky Runner")
clock = pygame.time.Clock()
font = pygame.font.Font("assets/fonts/pixel.ttf", 32)

SKY = (140, 200, 240)
GROUND = (90, 160, 80)
GROUND_Y = 260
GRAVITY = 1
SPAWN = pygame.USEREVENT + 1
POINT = pygame.USEREVENT + 2


class Runner(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.frames = [
            pygame.image.load("assets/images/player.png").convert_alpha(),
            pygame.image.load("assets/images/player_walk.png").convert_alpha(),
        ]
        self.image = self.frames[0]
        self.step = 0
        self.rect = self.image.get_rect(midbottom=(100, GROUND_Y))
        self.vy = 0

    def jump(self):
        if self.rect.bottom == GROUND_Y:
            self.vy = -16

    def update(self):
        self.vy += GRAVITY
        self.rect.y += self.vy
        if self.rect.bottom >= GROUND_Y:
            self.rect.bottom = GROUND_Y
            self.vy = 0
        if self.rect.bottom == GROUND_Y:
            self.step += 1
            self.image = self.frames[self.step // 8 % 2]
        else:
            self.image = self.frames[1]


class Obstacle(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = random.choice(obstacle_images)
        self.rect = self.image.get_rect(midbottom=(664, GROUND_Y))

    def update(self):
        self.rect.x -= speed
        if self.rect.right < 0:
            self.kill()


obstacle_images = [
    pygame.image.load("assets/images/spike_ball.png").convert_alpha(),
    pygame.image.load("assets/images/blob.png").convert_alpha(),
]
runner = Runner()
obstacles = pygame.sprite.Group()
speed = 6
pygame.time.set_timer(SPAWN, 1500)
pygame.time.set_timer(POINT, 100)
score = 0
state = "play"

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key in (pygame.K_SPACE, pygame.K_UP):
            if state == "play":
                runner.jump()
        if event.type == SPAWN and state == "play":
            obstacles.add(Obstacle())
            pygame.time.set_timer(SPAWN, random.randint(1000, 2000))
        if event.type == POINT and state == "play":
            score += 1

    if state == "play":
        speed = min(14, 6 + score // 100)
        runner.update()
        obstacles.update()
        if pygame.sprite.spritecollideany(runner, obstacles, pygame.sprite.collide_mask):
            state = "over"

    screen.fill(SKY)
    pygame.draw.rect(screen, GROUND, (0, GROUND_Y, 640, 60))
    screen.blit(runner.image, runner.rect)
    obstacles.draw(screen)
    score_text = font.render(f"{score:05}", True, (40, 50, 80))
    screen.blit(score_text, score_text.get_rect(topright=(630, 10)))
    if state == "over":
        message = font.render("Game over", True, (40, 50, 80))
        screen.blit(message, message.get_rect(center=(320, 140)))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Tutte le lezioni di Regole di gioco

Esercitati da solo: Playground Pygame