34. Menggerakkan benda
Bab 32 dan 33 membahas menggambar dan input. Bab ini menghubungkan keduanya: objek yang bergerak sebagai respons terhadap input, memantul dari dinding, dan bertabrakan satu sama lain.
Posisi sebagai variable
Cara paling sederhana untuk menggerakkan apa pun adalah menyimpan posisinya dalam variable dan memperbaruinya setiap frame. Di bagian gambar, gunakan variable tersebut untuk memposisikan bentuk:
x = 100
y = 100
# In the game loop update section:
x += 3 # move 3 pixels right every frame
# In the draw section:
pygame.draw.rect(screen, (255, 100, 0), (x, y, 40, 40))Pada 60 fps, menambahkan 3 setiap frame menggerakkan objek 180 piksel per detik.
Kecepatan
Kecepatan adalah perubahan posisi per frame. Simpan dalam variable
dx (perubahan x) dan dy (perubahan y):
x = 100
y = 100
dx = 3
dy = 2
# Update section each frame:
x += dx
y += dyUntuk membalik arah, negasikan kecepatan: dx = -dx. Ini
adalah pola "pantul" — digunakan untuk bola yang memantul.
pygame.Rect
pygame.Rect(x, y, width, height) adalah objek persegi
panjang yang disediakan pygame untuk pemosisian dan deteksi tabrakan
yang mudah.
rect = pygame.Rect(100, 200, 60, 60)Atribut yang berguna:
| Atribut | Arti |
|---|---|
rect.x |
Posisi x tepi kiri |
rect.y |
Posisi y tepi atas |
rect.width |
Lebar dalam piksel |
rect.height |
Tinggi dalam piksel |
rect.centerx |
Koordinat x pusat |
rect.centery |
Koordinat y pusat |
rect.right |
Koordinat x tepi kanan |
rect.bottom |
Koordinat y tepi bawah |
Gerakkan rect dengan menugaskan ke rect.x dan
rect.y. Gunakan langsung dalam pemanggilan draw —
pygame.draw.rect menerima sebuah Rect:
rect = pygame.Rect(100, 200, 60, 60)
rect.x += 3
pygame.draw.rect(screen, (255, 0, 0), rect)Mengatur rect.centerx dan rect.centery
memindahkan rect sehingga pusatnya berada di posisi tersebut:
rect.centerx = 400
rect.centery = 300
# rect is now centred in an 800x600 windowMengontrol frame rate
clock.tick(60) membatasi loop ke 60 frame per detik.
Tanpa itu, CPU yang cepat menjalankan ribuan frame per detik dan objek
terbang melintasi layar terlalu cepat. Dengan itu, kecepatan gerakan
bisa diprediksi: menambahkan 4 ke x setiap frame
menggerakkan objek 4 * 60 = 240 piksel per detik, di mesin
mana pun.
Pada mesin yang sangat lambat, clock.tick(60) tidak bisa
memaksa loop berjalan lebih cepat dari kecepatan alaminya. Frame rate
sebenarnya mungkin lebih rendah dari 60 pada hardware yang lambat. Untuk
tujuan buku ini, 60 fps sudah cukup andal.
Pemeriksaan batas
Objek yang bergerak keluar dari layar perlu dihentikan atau dipantulkan kembali. Periksa tepi secara manual setiap frame.
Berhenti di dinding:
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 = 600rect.left < 0 berarti tepi kiri telah melewati
dinding kiri. Mengatur rect.left = 0 mendorongnya
kembali.
Memantul dari dinding:
if rect.left < 0 or rect.right > 800:
dx = -dx
if rect.top < 0 or rect.bottom > 600:
dy = -dyMembalik kecepatan mengirim objek kembali ke arah asalnya.
Deteksi tabrakan dengan Rect.colliderect
Rect.colliderect(other_rect) mengembalikan
True jika dua persegi panjang saling tumpang tindih:
player_rect = pygame.Rect(100, 100, 50, 50)
coin_rect = pygame.Rect(120, 110, 30, 30)
if player_rect.colliderect(coin_rect):
print("collected!")Gunakan ini untuk mendeteksi saat pemain menyentuh koin, musuh, atau objek lainnya.
Contoh lengkap: kotak tombol panah yang memantul
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Moving Square")
clock = pygame.time.Clock()
rect = pygame.Rect(370, 270, 60, 60)
speed = 4
running = True
while running:
# 1. Events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 2. Update
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
# Clamp to window edges
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
# 3. Draw
screen.fill((30, 30, 30))
pygame.draw.rect(screen, (255, 100, 50), rect)
# 4. Flip
pygame.display.flip()
clock.tick(60)
pygame.quit()Buka exercises/34/01-bouncing-ball.py. Tambahkan bola
(lingkaran) yang bergerak sendiri menggunakan dx dan
dy. Setiap frame, tambahkan dx ke x dan
dy ke y. Saat bola menyentuh tepi kiri atau kanan jendela,
negasikan dx. Saat menyentuh atas atau bawah, negasikan
dy. Mulai dengan dx = 3, dy = 2.
Pekerjaan Rumah
Soal 1 — Penggerak terkunci
Buka exercises/34/homework/01-clamped-mover.py. Sebuah
kotak bergerak dengan tombol panah. Kotak tersebut tidak boleh keluar
dari jendela — clamp ke semua empat tepi.
Soal 2 — Dua bola memantul
Buka exercises/34/homework/02-two-balls.py. Dua bola
dimulai di posisi berbeda dengan kecepatan berbeda. Keduanya memantul
dari semua empat dinding secara independen. Setiap bola harus berwarna
berbeda.
Soal 3 — Mengikuti mouse
Buka exercises/34/homework/03-follow-mouse.py. Sebuah
kotak bergerak menuju posisi mouse saat ini setiap frame. Kotak tidak
langsung melompat ke kursor; ia bergerak sejumlah piksel tetap ke
arahnya per frame, berhenti saat tiba. Petunjuk: hitung perbedaan x dan
y, dan gerakkan sebagian dari perbedaan itu.
Tantangan — Kumpulkan target
Buka exercises/34/homework/04-collect-target.py. Kotak
pemain bergerak dengan tombol panah. Lingkaran target stasioner digambar
di suatu tempat di layar. Saat rect pemain tumpang tindih dengan target
(gunakan colliderect atau pemeriksaan jarak untuk
lingkaran), pindahkan target ke posisi acak baru dan cetak
"collected!" ke terminal.
Macet atau sudah selesai? Buka halaman solusi pekerjaan rumah.