Selecciones ponderadas
Parte de la sección Reglas del juego del Journey de Pygame de Coddy. Lección 18 de 29.
Un juego es más interesante cuando no todo lo que cae es igual. Aquí la mitad de los objetos que caen son rocas pequeñas, algunos son rocas grandes y unos pocos son gemas que valen 5 puntos. random.choice elige cada elemento con la misma frecuencia. random.choices acepta weights, que indica con qué frecuencia aparece cada elemento:
def pick_kind():
return random.choices(["small", "big", "gem"], weights=[5, 3, 2])[0]Los pesos 5, 3 y 2 suman 10, así que, de cada 10 objetos que caen, unos 5 son pequeños, 3 grandes y 2 son gemas. Los pesos son proporciones, no porcentajes: [50, 30, 20] significa lo mismo.
random.choices puede elegir varios elementos a la vez, así que siempre devuelve una lista, incluso si se elige solo uno. [0] extrae el elemento de la lista.
Cada tipo se convierte después en un Rect diferente. Las gemas van en su propia lista, gems, porque tocar una es una buena noticia. El código inicial ya mueve, dibuja y recoge gemas; todavía no cae ninguna.
Desafío
Intermedio- Escribe
pick_kind(): devuelve"small","big"o"gem"con pesos de 5, 3 y 2. - Al producirse
SPAWN, deja caer lo que elija: una roca pequeña de 24 por 24, una roca grande de 40 por 40 (x de 0 a 440, y -40) o una gema de 20 por 20 (x de 0 a 460, y -20) añadida agems.
Pruébalo tú mismo
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
SPAWN = pygame.USEREVENT + 2
def reset():
global player, rocks, gems, score, lives
player = pygame.Rect(220, 300, 40, 40)
rocks = []
gems = []
score = 0
lives = 3
pygame.time.set_timer(POINT, 1000)
pygame.time.set_timer(SPAWN, 500)
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))
pygame.draw.rect(screen, (255, 196, 0), player)
for rock in rocks:
pygame.draw.rect(screen, (235, 80, 80), rock)
for gem in gems:
pygame.draw.rect(screen, (90, 220, 120), gem)
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 rocks, gems, score, lives, 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())
kept = []
for rock in rocks:
rock.y += 3
if rock.colliderect(player):
lives -= 1
elif rock.top <= 360:
kept.append(rock)
rocks = kept
kept = []
for gem in gems:
gem.y += 3
if gem.colliderect(player):
score += 5
elif gem.top <= 360:
kept.append(gem)
gems = kept
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 == SPAWN and state == "play":
rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN and state == "menu":
reset()
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()
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Reglas del juego
1Estados del juego
Una variable de estadoUna pantalla de menúPulsa R para volver a jugarUna función de reinicioUna función por estado4Dificultad
Velocidad que aumentaUn límite mínimo para el huecoNormal o difícilSelecciones ponderadasPractica por tu cuenta: Playground de Pygame