32. Menggambar di layar — Solusi pekerjaan rumah

Setiap solusi adalah program pygame lengkap yang bisa dijalankan. Jalankan dengan:

python exercises/32/homework/solutions/01-flag.py

Soal 1 — Bendera

Soal. Gambar bendera tiga garis yang mengisi sebagian besar jendela.

Cara memikirkannya. Bagi tinggi jendela dengan 3. Setiap garis adalah persegi panjang yang membentang selebar penuh di posisi y yang berbeda.

Solusi.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Flag")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((255, 255, 255))

    stripe_height = 600 // 3
    pygame.draw.rect(screen, (0, 57, 166),  (0, 0,              800, stripe_height))
    pygame.draw.rect(screen, (255, 255, 255),(0, stripe_height,  800, stripe_height))
    pygame.draw.rect(screen, (255, 0, 0),   (0, stripe_height * 2, 800, stripe_height))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Tiga warna apa pun bisa diterima. Kuncinya adalah menghitung offset y setiap garis sebagai stripe_height * stripe_index.

Kesalahan umum.

  • Menulis posisi piksel secara langsung seperti 0, 200, 400 alih-alih menghitungnya dari 600 // 3. Jika ukuran jendela berubah, posisi yang ditulis langsung akan rusak; posisi yang dihitung akan menyesuaikan.

Soal 2 — Sasaran

Soal. Tiga lingkaran konsentris dengan warna bergantian.

Cara memikirkannya. Gambar lingkaran terbesar dulu, lalu yang sedang di atasnya, lalu yang terkecil. Ketiganya berbagi pusat yang sama. Menggunakan radius berbeda dengan pusat yang sama menghasilkan cincin-cincin konsentris.

Solusi.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Target")
clock = pygame.time.Clock()

cx, cy = 400, 300   # centre

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((200, 200, 200))

    pygame.draw.circle(screen, (220, 0, 0),     (cx, cy), 150)
    pygame.draw.circle(screen, (255, 255, 255), (cx, cy), 100)
    pygame.draw.circle(screen, (220, 0, 0),     (cx, cy), 50)

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Kesalahan umum.

  • Menggambar yang terkecil dulu. Lingkaran terbesar akan menimpa yang lebih kecil, menyisakan hanya satu lingkaran terisi. Selalu gambar dari belakang ke depan.

Soal 3 — Grid

Soal. Grid 4x4 kotak bertepi menggunakan nested loop.

Cara memikirkannya. Bagi jendela menjadi 4 kolom dan 4 baris yang sama. Sudut kiri atas setiap sel berada di (col * cell_w, row * cell_h).

Solusi.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Grid")
clock = pygame.time.Clock()

cols = 4
rows = 4
cell_w = 800 // cols
cell_h = 600 // rows

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((30, 30, 30))

    for row in range(rows):
        for col in range(cols):
            x = col * cell_w
            y = row * cell_h
            pygame.draw.rect(screen, (180, 180, 180), (x, y, cell_w, cell_h), 2)

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Argumen ketebalan 2 hanya menggambar batas. Mengaturnya ke 0 akan mengisi setiap sel.

Kesalahan umum.

  • Menggunakan range(1, 5) alih-alih range(4). Keduanya menghasilkan empat nilai tapi range(4) dimulai dari 0, yang dengan benar dipetakan ke posisi piksel melalui perkalian.

Tantangan — Papan catur

Soal. Papan catur 8x8 di mana (row + col) % 2 == 0 adalah putih dan sisanya gelap.

Cara memikirkannya. Struktur yang sama seperti grid, tapi warna isian tergantung pada (row + col) % 2. Gunakan persegi panjang terisi (ketebalan 0).

Solusi.

import pygame

pygame.init()
SIZE = 600
screen = pygame.display.set_mode((SIZE, SIZE))
pygame.display.set_caption("Chessboard")
clock = pygame.time.Clock()

LIGHT = (240, 217, 181)
DARK  = (181, 136, 99)
CELLS = 8
cell = SIZE // CELLS

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((0, 0, 0))

    for row in range(CELLS):
        for col in range(CELLS):
            color = LIGHT if (row + col) % 2 == 0 else DARK
            x = col * cell
            y = row * cell
            pygame.draw.rect(screen, color, (x, y, cell, cell))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Menggunakan jendela persegi (600x600) dan membaginya dengan 8 menghasilkan sel yang sama tanpa error pembulatan (600 / 8 = 75 persis).

Kesalahan umum.

  • Menggunakan jendela non-persegi (misalnya 800x600). 800 / 8 = 100 tapi 600 / 8 = 75, sehingga sel akan berbentuk persegi panjang bukan persegi. Gunakan jendela persegi atau gunakan cell_w dan cell_h yang terpisah.

Selesai?

Bab 33 menambahkan input keyboard dan mouse sehingga program bisa merespons apa yang dilakukan pemain.