Una roccia ogni 800 ms
Fa parte della sezione Regole di gioco del percorso Pygame di Coddy. Lezione 12 di 29.
Una roccia alla volta rende il gioco tranquillo. Con un timer, può cadere una nuova roccia ogni 800 ms mentre le altre stanno ancora cadendo. Tieni le rocce in una lista:
SPAWN = pygame.USEREVENT + 2
...
if event.type == SPAWN and state == "play":
rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))Ogni evento ha il proprio numero, quindi SPAWN è USEREVENT + 2, uno dopo POINT. Avvia il suo timer accanto all’altro e imposta rocks = [] in reset().
A ogni fotogramma, sposta tutte le rocce, poi tieni solo quelle che sono ancora nella finestra:
for rock in rocks:
rock.y += 4
rocks = [rock for rock in rocks if rock.top <= 360]Senza quella seconda riga, ogni roccia caduta rimane nella lista. Il gioco sposterebbe e controllerebbe migliaia di rocce che nessuno può vedere e rallenterebbe più a lungo giochi.
Anche il disegno e il controllo delle collisioni diventano cicli su rocks.
Sfida
Medio- Sostituisci
rockcon una lista chiamatarocks, vuota inreset(). - Aggiungi
SPAWN = pygame.USEREVENT + 2e un timer per questo evento ogni 800 ms, avviato inreset(). - Durante il gioco, quando si verifica
SPAWN, aggiungi una roccia di 24 per 24 a y -24 e con una x casuale da 0 a 456. - A ogni fotogramma sposta ogni roccia verso il basso di 4, rimuovi quelle la cui parte superiore supera 360, disegnale tutte e verifica se ciascuna colpisce il giocatore.
Provalo tu
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()
Tutte le lezioni di Regole di gioco
3Timer e ondate
Al sicuro dopo un colpoUn evento del timerUna roccia ogni 800 msOnde che cresconoConto alla rovescia per partireEsercitati da solo: Playground Pygame