Alle 800 ms ein Felsbrocken
Teil des Abschnitts Spielregeln der Pygame-Journey von Coddy. Lektion 12 von 29.
Ein einzelner Felsbrocken ist ein ruhiges Spiel. Mit einem Timer kann alle 800 ms ein neuer Felsbrocken herunterfallen, während die anderen noch fallen. Bewahre die Felsbrocken in einer Liste auf:
SPAWN = pygame.USEREVENT + 2
...
if event.type == SPAWN and state == "play":
rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))Jedes Ereignis hat eine eigene Nummer, also ist SPAWN USEREVENT + 2, eine Nummer höher als POINT. Starte den Timer neben dem anderen und setze rocks = [] in reset().
Bewege in jedem Frame alle Felsbrocken und behalte dann nur diejenigen, die sich noch im Fenster befinden:
for rock in rocks:
rock.y += 4
rocks = [rock for rock in rocks if rock.top <= 360]Ohne diese zweite Zeile bleibt jeder Felsbrocken, der jemals heruntergefallen ist, in der Liste. Das Spiel würde Tausende von Felsbrocken bewegen und überprüfen, die niemand sehen kann, und mit zunehmender Spieldauer langsamer werden.
Auch das Zeichnen und die Kollisionserkennung werden zu Schleifen über rocks.
Aufgabe
Mittel- Ersetze
rockdurch eine Liste namensrocks, die inreset()leer ist. - Füge
SPAWN = pygame.USEREVENT + 2und einen Timer hinzu, der alle 800 ms ausgelöst wird und inreset()gestartet wird. - Füge während des Spiels bei
SPAWNeinen 24 × 24 großen Felsen bei y -24 und einem zufälligen x-Wert von 0 bis 456 hinzu. - Bewege jeden Felsen in jedem Frame um 4 nach unten, entferne diejenigen, deren Oberkante über 360 hinaus ist, zeichne alle und prüfe jeden auf eine Kollision.
Probier es selbst
import random
import pygame
pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Meteor Dodge")
clock = pygame.time.Clock()
heart = pygame.image.load("assets/images/heart.png").convert_alpha()
heart_empty = pygame.image.load("assets/images/heart_empty.png").convert_alpha()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
WHITE = (240, 240, 240)
PLATE = (60, 60, 90)
POINT = pygame.USEREVENT + 1
def reset():
global player, rock, score, lives, hit_time
player = pygame.Rect(220, 300, 40, 40)
rock = pygame.Rect(random.randint(0, 456), -24, 24, 24)
score = 0
lives = 3
hit_time = -2000
pygame.time.set_timer(POINT, 1000)
def draw_menu():
screen.fill((30, 30, 46))
title = big_font.render("Meteor Dodge", True, WHITE)
title_rect = title.get_rect(center=(240, 140))
pygame.draw.rect(screen, PLATE, title_rect.inflate(24, 12))
screen.blit(title, title_rect)
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))
safe = pygame.time.get_ticks() - hit_time < 1000
if not safe or pygame.time.get_ticks() // 100 % 2 == 0:
pygame.draw.rect(screen, (255, 196, 0), player)
pygame.draw.rect(screen, (235, 80, 80), rock)
score_text = font.render(f"{score:05}", True, WHITE)
score_rect = score_text.get_rect(topright=(470, 10))
pygame.draw.rect(screen, PLATE, score_rect.inflate(12, 8))
screen.blit(score_text, score_rect)
for i in range(3):
if i < lives:
screen.blit(heart, (10 + i * 40, 10))
else:
screen.blit(heart_empty, (10 + i * 40, 10))
def play_frame():
global score, lives, state, hit_time
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)
now = pygame.time.get_ticks()
if rock.colliderect(player) and now - hit_time > 1000:
hit_time = now
lives -= 1
if lives == 0:
state = "over"
draw_game()
def draw_over():
draw_game()
message = big_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 == POINT and state == "play":
score += 1
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()
Alle Lektionen in Spielregeln
3Timer und Wellen
Sicher nach einem TrefferEin Timer-EreignisAlle 800 ms ein FelsbrockenWachsende WellenCountdown bis zum StartÜbe selbstständig: Pygame-Playground