Menu
CoddyTech

Sebuah Batu Setiap 800 ms

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

Satu batu setiap kali membuat permainan terasa tenang. Dengan pengatur waktu, batu baru bisa jatuh setiap 800 ms sementara batu-batu lainnya masih berjatuhan. Simpan batu-batu itu dalam sebuah list:

SPAWN = pygame.USEREVENT + 2
...
if event.type == SPAWN and state == "play":
    rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))

Setiap peristiwa memiliki nomornya sendiri, jadi SPAWN adalah USEREVENT + 2, satu angka setelah POINT. Mulai pengatur waktunya bersamaan dengan pengatur waktu lainnya, lalu atur rocks = [] di reset().

Di setiap frame, gerakkan semua batu, lalu sisakan hanya batu yang masih berada di dalam jendela:

for rock in rocks:
    rock.y += 4
rocks = [rock for rock in rocks if rock.top <= 360]

Tanpa baris kedua itu, setiap batu yang pernah jatuh akan tetap berada dalam list. Gim akan menggerakkan dan memeriksa ribuan batu yang tidak dapat dilihat siapa pun, sehingga gim makin lambat semakin lama kamu bermain.

Menggambar dan memeriksa tabrakan juga menjadi perulangan atas rocks.

challenge icon

Tantangan

Sedang
  1. Ganti rock dengan list bernama rocks, yang kosong di reset().
  2. Tambahkan SPAWN = pygame.USEREVENT + 2 dan timer untuk itu setiap 800 ms, yang dimulai di reset().
  3. Saat SPAWN terjadi selama permainan, tambahkan rock berukuran 24 kali 24 di y -24 dan x acak dari 0 hingga 456.
  4. Setiap frame, gerakkan setiap rock ke bawah sejauh 4, hapus rock yang bagian atasnya melewati 360, gambar semuanya, lalu periksa apakah masing-masing terkena benturan.

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


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()

Semua pelajaran di Aturan Game

Latihan sendiri: Playground Pygame