Menu
CoddyTech

Tirages pondérés

Fait partie de la section Règles du jeu du Journey Pygame de Coddy. Leçon 18 sur 29.

Un jeu est plus intéressant lorsque tout ce qui tombe n’est pas identique. Ici, la moitié des objets qui tombent sont de petites pierres, certains sont de grosses pierres et quelques-uns sont des gemmes valant 5 points. random.choice choisit chaque élément aussi souvent que les autres. random.choices prend des weights, qui indiquent la fréquence d’apparition de chacun :

def pick_kind():
    return random.choices(["small", "big", "gem"], weights=[5, 3, 2])[0]

Les poids 5, 3 et 2 totalisent 10, donc, sur 10 objets qui tombent, environ 5 sont de petites pierres, 3 de grosses pierres et 2 des gemmes. Les poids sont des proportions, pas des pourcentages : [50, 30, 20] signifie la même chose.

random.choices peut faire plusieurs choix à la fois, donc il renvoie toujours une liste, même pour un seul choix. [0] en extrait l’élément.

Chaque type devient ensuite un Rect différent. Les gemmes sont placées dans leur propre liste, gems, car en toucher une est une bonne nouvelle. Le code de départ sait déjà déplacer, dessiner et attraper les gemmes ; aucune n’est encore lâchée.

challenge icon

Défi

Moyen
  1. Écrivez pick_kind() : elle renvoie "small", "big" ou "gem" avec des poids de 5, 3 et 2.
  2. À l’événement SPAWN, faites tomber ce qu’il sélectionne : un petit rocher de 24 sur 24, un gros rocher de 40 sur 40 (x de 0 à 440, y -40), ou une gemme de 20 sur 20 (x de 0 à 460, y -20), ajoutée à gems.

Essayez vous-même

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()
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Règles du jeu

Entraînez-vous par vous-même : Playground Pygame