Menu
CoddyTech

Pilihan Berbobot

Termasuk bagian Aturan Game dalam perjalanan Pygame di Coddy. Pelajaran 18 dari 29.

Game menjadi lebih menarik jika tidak semua yang jatuh itu sama. Di sini, setengah dari benda yang jatuh adalah batu kecil, sebagian adalah batu besar, dan beberapa adalah permata bernilai 5 poin. random.choice memilih setiap benda dengan frekuensi yang sama. random.choices menerima weights, yang menentukan seberapa sering setiap benda terpilih:

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

Bobot 5, 3, dan 2 berjumlah 10, jadi dari setiap 10 benda yang jatuh, sekitar 5 adalah batu kecil, 3 batu besar, dan 2 permata. Bobot adalah proporsi, bukan persentase: [50, 30, 20] memiliki arti yang sama.

random.choices dapat memilih beberapa benda sekaligus, jadi fungsi ini selalu mengembalikan sebuah list, bahkan untuk satu pilihan. [0] mengambil benda dari list tersebut.

Setiap jenis kemudian menjadi Rect yang berbeda. Permata masuk ke list tersendiri, gems, karena menyentuhnya adalah kabar baik. Program awal sudah bisa menggerakkan, menggambar, dan menangkap permata, tetapi belum ada yang menjatuhkannya.

challenge icon

Tantangan

Sedang
  1. Tulis pick_kind(): fungsi ini mengembalikan "small", "big" atau "gem" dengan bobot 5, 3, dan 2.
  2. Saat SPAWN, jatuhkan item yang dipilih: batu kecil berukuran 24 kali 24, batu besar berukuran 40 kali 40 (x dari 0 sampai 440, y -40), atau gem berukuran 20 kali 20 (x dari 0 sampai 460, y -20) yang ditambahkan ke gems.

Coba sendiri

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 iconUji dirimu

Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.

Semua pelajaran di Aturan Game

Latihan sendiri: Playground Pygame