Menu
CoddyTech

Menü und Bestpunktzahl

Teil des Abschnitts Spielregeln der Pygame-Journey von Coddy. Lektion 29 von 29.

Sky Runner bezieht die Regeln aus diesem Abschnitt: ein Menü, ein neues Spiel per Tastendruck und der beste Punktestand.

reset() erstellt einen neuen Läufer und eine leere Gruppe, setzt den Punktestand und die Geschwindigkeit zurück und startet beide Timer neu. Das Spiel beginnt mit "menu", und best wird einmal außerhalb von reset() festgelegt.

Die Leertaste erfüllt jetzt drei Aufgaben, eine pro Zustand:

if state == "play":
    runner.jump()
elif state == "menu":
    reset()
    state = "play"
elif pygame.time.get_ticks() - over_time > 500:
    reset()
    state = "play"

Die Leertaste ist die Sprungtaste, deshalb drücken Spieler sie oft genau im Moment eines Zusammenstoßes. Ohne Wartezeit würde das Spiel neu starten, bevor sie das Ergebnis sehen. Speichere den Zeitpunkt des Zusammenstoßes in over_time und akzeptiere die Leertaste auf dem Game-Over-Bildschirm erst 500 ms später.

Eine kleine Funktion show(text, text_font, y) zeichnet eine Zeile zentriert bei x 320, da sowohl das Menü als auch der Game-Over-Bildschirm fünf Zeilen benötigen.

challenge icon

Aufgabe

Schwer
  1. Schreibe reset() für den Runner, die Gruppe, speed, score und beide Timer; rufe die Funktion vor der Schleife auf und setze state = "menu", best = 0 und over_time = 0.
  2. Zeige im Menü Sky Runner (Größe 48) und Press Space to start an; die Leertaste oder die Pfeiltaste nach oben startet ein Spiel.
  3. Aktualisiere bei einem Zusammenstoß best und setze over_time.
  4. Zeige auf dem Game-over-Bildschirm Game over, Best: 00120 (fünf Ziffern) und Press Space to play again an; die Leertaste startet ein neues Spiel, aber erst 500 ms nach dem Zusammenstoß.
  5. Zeige den Punktestand nur während des Spiels und auf dem Game-over-Bildschirm an.

Probier es selbst

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()
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Spielregeln

Übe selbstständig: Pygame-Playground