34. Menggerakkan benda — Solusi pekerjaan rumah
Soal 1 — Penggerak terkunci
Soal. Sebuah kotak yang bergerak dengan tombol panah dan tetap berada di dalam jendela.
Cara memikirkannya. Terapkan gerakan
get_pressed, lalu clamp semua empat tepi menggunakan
rect.left, rect.right, rect.top,
rect.bottom.
Solusi.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Clamped Mover")
clock = pygame.time.Clock()
rect = pygame.Rect(370, 270, 60, 60)
speed = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
rect.x -= speed
if keys[pygame.K_RIGHT]:
rect.x += speed
if keys[pygame.K_UP]:
rect.y -= speed
if keys[pygame.K_DOWN]:
rect.y += speed
if rect.left < 0:
rect.left = 0
if rect.right > 800:
rect.right = 800
if rect.top < 0:
rect.top = 0
if rect.bottom > 600:
rect.bottom = 600
screen.fill((20, 20, 40))
pygame.draw.rect(screen, (100, 200, 255), rect)
pygame.display.flip()
clock.tick(60)
pygame.quit()Kesalahan umum.
- Clamp
rect.x < 0tapi tidak mempertimbangkan lebar. Jika kamu memeriksax < 0dan clamp kex = 0, tepi kiri sudah benar. Tapi untuk tepi kanan kamu harus memeriksarect.right > 800(yaiturect.x + rect.width > 800). Menggunakanrect.rightdanrect.leftlebih sederhana daripada melakukan aritmatika secara manual.
Soal 2 — Dua bola memantul
Soal. Dua bola memantul dari semua empat dinding secara independen.
Cara memikirkannya. Gunakan dua set variable posisi dan kecepatan. Logika pantulan sama untuk keduanya; cukup tulis dua kali (atau buat function).
Solusi.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Two Balls")
clock = pygame.time.Clock()
ax, ay, adx, ady = 200, 150, 4, 3
bx, by, bdx, bdy = 600, 400, -3, 5
radius = 20
W, H = 800, 600
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
ax += adx
ay += ady
if ax - radius < 0 or ax + radius > W:
adx = -adx
if ay - radius < 0 or ay + radius > H:
ady = -ady
bx += bdx
by += bdy
if bx - radius < 0 or bx + radius > W:
bdx = -bdx
if by - radius < 0 or by + radius > H:
bdy = -bdy
screen.fill((10, 10, 10))
pygame.draw.circle(screen, (255, 80, 80), (ax, ay), radius)
pygame.draw.circle(screen, (80, 180, 255), (bx, by), radius)
pygame.display.flip()
clock.tick(60)
pygame.quit()Pemeriksaan batas menggunakan ax - radius < 0 karena
posisi adalah pusat lingkaran, dan lingkaran memanjang sejauh
radius piksel ke setiap arah.
Kesalahan umum.
- Memeriksa
ax < 0alih-alihax - radius < 0. Pusat bisa berada di(5, ...)sementara tepi kiri bola sudah keluar dari layar.
Soal 3 — Mengikuti mouse
Soal. Sebuah kotak bergerak menuju posisi mouse setiap frame, satu langkah tetap dalam satu waktu.
Cara memikirkannya. Hitung
dx = mx - rect.centerx dan
dy = my - rect.centery. Ini adalah jarak yang perlu
ditempuh. Setiap frame, gerakkan sebagian dari jarak tersebut (langkah
lebih kecil dari total jarak) atau berhenti saat cukup dekat.
Solusi.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Follow Mouse")
clock = pygame.time.Clock()
rect = pygame.Rect(370, 270, 50, 50)
speed = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
mx, my = pygame.mouse.get_pos()
dx = mx - rect.centerx
dy = my - rect.centery
if abs(dx) > speed:
rect.x += speed if dx > 0 else -speed
else:
rect.centerx = mx
if abs(dy) > speed:
rect.y += speed if dy > 0 else -speed
else:
rect.centery = my
screen.fill((20, 20, 20))
pygame.draw.rect(screen, (255, 200, 50), rect)
pygame.display.flip()
clock.tick(60)
pygame.quit()speed if dx > 0 else -speed bergerak satu langkah ke
arah target. Cabang else meng-snap ke target saat sisa
jarak lebih kecil dari satu langkah, mencegah getaran.
Tantangan — Kumpulkan target
Soal. Pemain bergerak dengan tombol panah. Menyentuh target memindahkannya ke posisi acak.
Cara memikirkannya. Gunakan
pygame.Rect.colliderect untuk tabrakan.
import random untuk memilih posisi baru. Rect target harus
tetap sepenuhnya di dalam jendela — kurangi target.width
dan target.height dari batas atas.
Solusi.
import pygame
import random
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Collect Target")
clock = pygame.time.Clock()
W, H = 800, 600
player = pygame.Rect(370, 270, 50, 50)
target = pygame.Rect(random.randint(0, W - 40), random.randint(0, H - 40), 40, 40)
speed = 5
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= speed
if keys[pygame.K_RIGHT]:
player.x += speed
if keys[pygame.K_UP]:
player.y -= speed
if keys[pygame.K_DOWN]:
player.y += speed
# clamp
player.clamp_ip(pygame.Rect(0, 0, W, H))
if player.colliderect(target):
print("collected!")
target.x = random.randint(0, W - target.width)
target.y = random.randint(0, H - target.height)
screen.fill((20, 20, 30))
pygame.draw.circle(screen, (255, 220, 0),
(target.centerx, target.centery), target.width // 2)
pygame.draw.rect(screen, (100, 200, 255), player)
pygame.display.flip()
clock.tick(60)
pygame.quit()pygame.Rect.clamp_ip(boundary_rect) memindahkan rect
sehingga pas di dalam batas — alternatif bawaan untuk empat pemeriksaan
tepi terpisah.
Kesalahan umum.
- Menempatkan target secara acak hingga x
Wtanpa mengurangitarget.width, memungkinkan sebagian target muncul di luar layar.
Selesai?
Bab 35 menambahkan rendering teks dan pelacakan skor untuk melengkapi game loop dasar.