Belajar membuat game dari nol dengan PyGame

Banyak yang bilang:

“Kalau pakai Linux, nanati gak bisa main Game”

Pernyataan ini ada benarnya, karena Game yang dipublikasikan untuk Linux tidak sebanyak Windows dan Mac.

Mungkin karena Linux kebanyakan digunakan di server dan cloud.

Tapi ini sebenarnya bisa jadi potensi pasar dengan persaingan yang sedikit.

Bayangkan…

Game anda diterbitkan untuk platform Linux, seberapa banyak pengguna Linux (terutama yang baru bermigrasi) akan memainkan Game anda di Linux. Saya kira akan banyak.

Platform game desktop

Ah, saya tidak akan membahas ini lebih dalam. Karena pada artikel ini kita akan belajar cara membuat game di Linux dengan PyGame.

Siap?

Mari kita mulai…

Persiapan Awal yang Harus dilakukan

Sebelum memulai, saya akan menjelaskan dulu persiapan yang harus dilakukan.

Pada tutorial ini, kita akan menggunakan modul PyGame dengan Python 3.

Jadi ada dua hal utama yang harus disiapkan:

  1. Python 3
  2. PyGame

PyGame adalah modul Python yang berisi fungsi dan class yang kita butuhkan untuk membuat game.

Pengetahuan yang dibutuhkan

Setidaknya untuk dapat mengikuti tutorial ini, kamu harus paham dulu dasar-dasar pemrograman Python.

Apabila belum paham, silahkan ikuti: Tutorial Pemrograman Python yang sudah saya buat.

Selain itu pengetahuan tentang grafika komputer dan matematika juga akan sangat membantu.

Matematika di dalam Game

Penasaran kan… bagaimana peranan matematika di dalam Game?

Nanti saja kita lihat di dalam kode.

Lanjutkan baca sampai selesai ya…

Oya, pastikan kamu mengetik sendiri kode yang ada di tutorial ini. Kalau copas nanti bisa error, saoalnya python sangat sensitif dengan tab dan spasi. Selain itu, kamu juga akan menikmati proses coding-nya. Bukan menikmati proses copas-nya ๐Ÿ˜

Instalasi PyGame

PyGame dapat kita install menggunakan pip dengan perintah berikut:

sudo pip install pygame

Atau bisa juga melalui apt:

sudo apt-get install python3-pygame

Maka modul pygame akan terinstal ke dalam lingkungan OS (Sistem Opearsi).

Buat yang menggunakan Virtual Environtment gunakan perintah ini:

# membuat virtual env
virtualenv -p python3 pygame
# pindah ke direktori virtualenv
cd pygmae
# aktifkan virtual env
. bin/activate

# install modul pygame di dalam virtualenv
pip install pygame

Belum tahu tentang virtual environment?

Silahkan baca: Mengenal Virtualenv: Apa Saja yang Harus Kamu Ketahui?

OK, lanjut…

Sekarang kita tes dulu, apakah modul pygame sudah terinstal atau tidak. Silahkan masuk ke shell python dengan mengetik perintah python3 atau python (di virtual env).

Ketik perintah berikut:

>>> import pygame

Kalau tidak terjadi error, maka modul pygame sudah terinstal dengan benar.

Import Modul PyGame Barhasil

Tapi kalau terjadi error, artinya modul pygame belum terinstall.

Import Modul PyGame gagal

Coba install lagi sampai berhasil.

Membuat Proyek Game

Sebelum mulai membuat game, kita tentukan dulu game seperti apa yang akan dibuat.

Pada tutorial ini, kita akan membuat game 2D dengan game play seperti ini:

Rancangan Game

Permainan pada game ini hanya sebatas tembak-tembakan saja dengan pemain utama (player) adalah seekor kelinci. Dia harus melindungi bentengnya dari serangan hewan liar.

Kelinci ini menggnakan panah untuk menebak.

Sederhana bukan…

Mari kita mulai proyek ini dengan membuat direktori baru bernama mygame. Lalu di dalam direktori ini buat file baru bernama game.py.

Ikuti perintah berikut:

mkdir mygame
touch mygame/game.py

Sehingga kita akan punya struktur direktori seperti ini:

mygame/
โ””โ”€โ”€ game.py

Untuk aset game seperti game art dan audio sudah saya sediakan.

Tinggal download saja di sini: [Download Game Assets]

Setelah itu ekstrak direktori resources ke dalam direktori mygame.

Ekstrak file resource

Sehingga kita punya struktur direktori seperti ini:

Struktur Direktori Poryek Game

Selanjutnya kita bisa mulai coding

Langkah 1: Membuat Game dengan PyGame

Buka file game.py dengan teks editor, lalu ketik kode berikut:

File: game.py

# 1 - Import Library ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import pygame
from pygame.locals import *

# 2 - Initialize the Game ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))

running = True

playerpos = [100, 100] # initial position for player

# 3 - Load Game Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 3.1 - Load Images
player = pygame.image.load("resources/images/dude.png")

## 4 - The Game Loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
while(running):
    
    # 5 - Clear the screen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    screen.fill(0)
    
    # 6 - Draw the game object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    screen.blit(player, playerpos)

    # 7 - Update the sceeen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pygame.display.flip()

    # 8 - Event Loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    for event in pygame.event.get():
        # event saat tombol exit diklik
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)

Ada 8 langkah awal yang harus kita lakukan dalam membuat game dengan PyGame:

1 - Import Library:

Mmengimpor semua library yang dibutuhkan oleh Game:

import pygame
from pygame.locals import *

Pertama kita impor pygame lalu mengimpor konstanta di dalam pygame.

2 - Initialize Game:

Pada tahapan ini kita melakukan inisialisasi atau deklarasi variabel dan objek yang dibutuhkan.

3 - Load Game Assets:

Pada tahapan ini kita me-load game asset. Pada kode di atas, kita me-load gambar untuk ditampilkan pada Game.

4 - Game Loop:

Game loop akan mengunlang terus mmenerus selama game-nya berjalan.

5 - Clear Screen:

Kita menggunakan fungsi screen.fill(0) untuk mengosongkan layar sebelum digambar.

6 - Draw the game object:

Pada tahapan ini kita menggambar game objek ke layar. Jadi apapun yang akan kita tampilkan ke layar, kita harus menggambarnya di sini.

Fungsi yang digunakan untuk menggambar pada Pygame adalah:

screen.blit(objek, posisi)

parameter posisi adalah sebuah tuple (x,y) yang menyatakan koordinat atau lokasi gambar akan ditampilkan.

7 - Update Screen:

Karena saat ini kita berada di dalam game loop, gambar akan dibuat terus menerus selama gamenya berjalan.

Karena itu, kita perlu update tampilan screenya agar tercipta efek animasi.

Fungsi untuk update di pygame adalah:

pygame.display.flip()

8 - Event Loop:

Event loop berfungsi untuk mengecek event apa saja yang terjadi di dalam game. Misal saat mouse ditekan, saat salah satu keyboard ditekan, dsb.

Nah, sekarang coba eksekusi Gamenya dengan perintah:

python game.py

Maka hasilnya:

Tutorial membuat game dengan pygame

Boom!! kita berhasil menggambar Player di ruang hampa.

Ngomong-ngomong itu posisinya berada di titik (100, 100). Artinya x=100 dan y=100.

Posisi karakter di koordinat

“Kok y ke bawah tidak bernilai negatif?”

Diagram kartesius di komputer dibuat terbalik dengan titik (0,0) berada di pojok kiri atas.

Diagram di layar komputer

Ingat-ingat lagi pelajaran matematika dan grafika komputernya, hehe ๐Ÿ˜„…

Ok, lanjut…

Langkah 2: Menambahkan Background dan Objek yang Lain

Agar game terlihat menarik, kita tambahkan background dan game objek lainnya.

Tambahkan baris ini pada langkah ke #3:

grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")

Sehingga menjadi seperti ini:

load asset di langkah ke-3

Setelah itu kita akan gambar grass dan castle di langkah ke #6. Tambahkan kode berikut di atas kode untuk menggambar player:

   # draw the grass
	for x in range(int(width/grass.get_width()+1)):
		for y in range(int(height/grass.get_height()+1)):
			screen.blit(grass, (x*100, y*100))
	
	# draw the castle
	screen.blit(castle, (0, 30))
	screen.blit(castle, (0, 135))
	screen.blit(castle, (0, 240))
	screen.blit(castle, (0, 345))

Sehingga menjadi seperti ini:

Kode untuk menggambar background dan castle

Oke, sekarang kita punya kode seperti ini:

# 1 - Import Library ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import pygame
from pygame.locals import *

# 2 - Initialize the Game ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pygame.init()
width, height = 640, 480
screen = pygame.display.set_mode((width, height))

running = True

playerpos = [100, 100] # initial position for player

# 3 - Load Game Assets ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# 3.1 - Load Images
player = pygame.image.load("resources/images/dude.png")
grass = pygame.image.load("resources/images/grass.png")
castle = pygame.image.load("resources/images/castle.png")

## 4 - The Game Loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
while(running):
    
    # 5 - Clear the screen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    screen.fill(0)
    
    # 6 - Draw the game object ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # draw the grass
    for x in range(int(width/grass.get_width()+1)):
        for y in range(int(height/grass.get_height()+1)):
            screen.blit(grass, (x*100, y*100))
	
	# draw the castle
    screen.blit(castle, (0, 30))
    screen.blit(castle, (0, 135))
    screen.blit(castle, (0, 240))
    screen.blit(castle, (0, 345))

    screen.blit(player, playerpos)

    # 7 - Update the sceeen ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    pygame.display.flip()

    # 8 - Event Loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    for event in pygame.event.get():
        # event saat tombol exit diklik
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)

Coba eksekusi lagi kode tersebut:

python game.py

Maka hasilnya:

Game dengan background

Mantap… ๐Ÿ‘๐Ÿ‘๐Ÿ‘

Langkah 3: Menggerakan Player

Agar player bisa bergerak, kita harus memindahkan posisinya.

Misal kita ubah posisi x yang awalnya 100 menjadi 300, maka player akan bergerak ke kanan sejauh 100px.

Pada game ini, player akan kita gerakkan saat tombol ini ditekan:

  • a bergerak ke kiri
  • s bergerak ke bawah
  • d bergerak ke kanan
  • w bergerak ke atas

Paham kan maksud saya…?

Sekarang tambahkan kode berikut pada langkah #2 (di atas running = True):

# Key mapping
keys = {
    "top": False, 
    "bottom": False,
    "left": False,
    "right": False 
}

Lalu di langkah ke #8 - Event Loop, tambahkan kode berikut di bawah kode event QUIT:

        # chek the keydown and keyup
        if event.type == pygame.KEYDOWN:
            if event.key == K_w:
                keys["top"] = True
            elif event.key == K_a:
                keys["left"] = True
            elif event.key == K_s:
                keys["bottom"] = True
            elif event.key == K_d:
                keys["right"] = True
        if event.type == pygame.KEYUP:
            if event.key == K_w:
                keys["top"] = False
            elif event.key == K_a:
                keys["left"] = False
            elif event.key == K_s:
                keys["bottom"] = False
            elif event.key == K_d:
                keys["right"] = False
    # - End of event loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    # 9. Move the player ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if keys["top"]:
        playerpos[1] -= 5 # kurangi nilai y
    elif keys["bottom"]:
        playerpos[1] += 5 # tambah nilai y 
    if keys["left"]:
        playerpos[0] -= 5 # kurangi nilai x
    elif keys["right"]:
        playerpos[0] += 5 # tambah nilai x

Sehingga akan menjadi seperti ini:

Kode untuk event key

Event KEYDOWN artinya saat kita menekan tombol di keyboard, sedangkan KEYUP saat kita melepas keyboad.

Key down dan Key Up

Lalu di dalam KEYDOWN dan KEYUP kita melakukan pengecekan tombol yang ditekan dengan konstanta yang sudah disediakan PyGame.

  • K_w untuk tombol w
  • K_a untuk tombol a
  • K_s untuk tombol s
  • K_d untuk tombol d

Terakhir kita memindahkan poisi Player bedasarkan tombol yang ditekan. Player akan bergerak sepanjang 5px dengan menambah dan mengurangi nilai x dan y.

    if keys["top"]:
        playerpos[1] -= 5 # kurangi nilai y
    elif keys["bottom"]:
        playerpos[1] += 5 # tambah nilai y 
    if keys["left"]:
        playerpos[0] -= 5 # kurangi nilai x
    elif keys["right"]:
        playerpos[0] += 5 # tambah nilai x

Hasilnya:

Menggerakkan player

Yeah! kita berhasil! ๐Ÿ‘๐Ÿ‘๐Ÿ‘

Langkah 4: Mengubah Arah Player

Berikutnya kita ingin agar player menghadap ke mana pointer diarahan. Sehingga nanti kita bisa menembak dan membidik musuh.

Untuk melakukan ini, kita harus memutar arah player dengan sudut tertentu lalu menggambar ulang karakternya.

Besar sudut ini bisa kita hitung dengan rumus trigonometri tangen.

Masih ingat dengan sinus (sin), cosinus (cos), dan tangen (tan)?

Lupa pelajaran matematika

Hahaha ๐Ÿ˜„ sama!!

Saya juga lupa…

Tapi setidaknya kita harus paham bagaimana player akan bergerak mengikuti pointer.

Jadi begini…

Teori trigonometri

Anggaplah si player berada di titik (5,3), lalu pointer berada di titik (2,4). Agar player dapat berputar mengikuti arah pergerakan pointer, maka kita harus menghitung besar sudut z.

Setelah itu, baru kita bisa rotasi player dengan besar sudut z.

Nah, untuk mencari besar sudut z, kita bisa menggunakan rumus tangen.

Tenang…

Kita tidak akan membuat fungsi kangen tangen sendiri, karena di Python sudah disediakan dengan nama atan2(). Fungsi ini berada di dalam modul math.

Baiklah, sekarang buka lagi file game.py. Lalu tambahkan kode berikut pada langkah ke #1 - Import Library:

import math

Lalu pada langkah ke #6, ganti kode ini:

    screen.blit(player, playerpos)

Menjadi:

    # draw the player
    mouse_position = pygame.mouse.get_pos()
    angle = math.atan2(mouse_position[1] - (playerpos[1]+32), mouse_position[0] - (playerpos[0]+26))
    player_rotation = pygame.transform.rotate(player, 360 - angle * 57.29)
    new_playerpos = (playerpos[0] - player_rotation.get_rect().width / 2, playerpos[1] - player_rotation.get_rect().height / 2)
    screen.blit(player_rotation, new_playerpos)

Penjelasan:

Pertama kita mengambil posisi pointer dengan fungsi pygame.mouse.get_pos(). Fungsi ini akan menghasilkan sebuah list yang menampung nilai posisi x dan y dari mouse atau pointer.

Setelah itu kita menghitung besar sudut dengan fungsi math.atan2().

angle = math.atan2(mouse_position[1] - (playerpos[1]+32), mouse_position[0] - (playerpos[0]+26))

Setelah mendapatkan besar sudut rotasi, kemudian kita putar (rotasi) player dengan fungsi pygame.transform.rotate():

pygame.transform.rotate(player, 360 - angle * 57.29)

Nilai 57.29 didapatkan dari nilai radius 360/2ฯ€.

Terakhir kita menggambar ulang player dengan posisi baru.

Maka hasilnya:

Rotasi player Matematika dan pemrograman game

Langkah 5: Membuat Tembakan

Berikutnya kita tambahkan kode untuk membuat tembakan.

Logikanya nanti seperti ini:

  1. Gambar panah saat event klik;
  2. Pindahkan panah sesuai arahnya;
  3. Hapus panah kalau sudah mencapai batas layar.

Semua anak panah akan kita simpan di dalam sebuah list.

Baiklah, sekarang tambahkan kode berikut pada langkah #2 tepat di bawah variabel playerpos:

score = 0 
arrows = [] # list of arrows

Variabel score nanti akan kita gunakan untuk menyimpan score yang didapatkan.

Sementara variabel arrows akan menyimpan titik koordinat (x, y) dari anak panah.

Berikutnya silahkan tambahkan objek arrow pada langkah #3.1:

arrow = pygame.image.load("resources/images/bullet.png")

Sehingga menjadi seperti ini:

Kode objek panah

Setelah itu, tambahkan kode untuk event MOUSEBUTTONDOWN pada langkah ke #8 di bawah event QUIT:

        # Fire!!
        if event.type == pygame.MOUSEBUTTONDOWN:
            arrows.append([angle, new_playerpos[0]+32, new_playerpos[1]+32])

Sehigga menjadi seperti ini:

Kode untuk event klik

Kita akan menambahkan koordinat arrow baru ke dalam list arrows. Koordinat tersebut akan menjadi titik start untuk menggambar panah.

Selanjutnya tambahkan kode ini untuk menggambar panahnya di langkah ke #6 tepat di bawah kode # draw player:

    # 6.1 - Draw arrows
    for bullet in arrows:
        arrow_index = 0
        velx=math.cos(bullet[0])*10
        vely=math.sin(bullet[0])*10
        bullet[1]+=velx
        bullet[2]+=vely
        if bullet[1] < -64 or bullet[1] > width or bullet[2] < -64 or bullet[2] > height:
            arrows.pop(arrow_index)
        arrow_index += 1
        # draw the arrow
        for projectile in arrows:
            new_arrow = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
            screen.blit(new_arrow, (projectile[1], projectile[2]))

Sehingga akan menjadi seperti ini:

Kode untuk menggambar panah

Perhatikan!

Variabel velx (velocity x) dan vely (velocity y) kita hitung dengan rumus trigonomotri math.sin() dan math.cos(). Dua variabel ini akan menentukan kecepatan panah berpindah dari titik awal ke titik akhir.

Selanjutnya kita cek, apakah panah sudah mencapai batas layar atau tidak?

if bullet[1] < -64 or bullet[1] > width or bullet[2] < -64 or bullet[2] > height:
    arrows.pop(index)

Kalau sudah mencapai batas layar, kita hapus panahnya dari list dengan fungsi pop() agar tidak memakan banyak memori.

Setelah itu kita increment nilai index panah (arrow_index) dan mulai menggambar berdasarkan angle player.

        # draw the arrow
        for projectile in arrows:
            new_arrow = pygame.transform.rotate(arrow, 360-projectile[0]*57.29)
            screen.blit(new_arrow, (projectile[1], projectile[2]))

Variabel projectile akan berisi nilai koordinat awal panah yang didapatkan dari list arrows.

Sekarang coba eksekusi lagi Game-nya:

python game.py

Maka hasilnya:

Game Player mendembak!!

Wohooo~ ๐Ÿ˜ keren!!

Lesquee

Wah, kamu sudah mengikuti 50% dari tutorial ini. Sisanya tinggal menambahkan musuh, collision, UI, dan audio.

Langkah 6: Membuat Musuh

Sekarang saatnya kita menggambar musuh. Caranya hampir sama dengan menggambar obejk yang lain.

Bedanya, kita akan menggambar pada titik y secara acak.

Lokasi gambar musuh

Untuk menggambar secara acak, kita bisa menggunakan fungsi randint() (random integer) untuk membuat bilangan acak.

Tujuan utama musuh adalah menyerang markas kelinci yang sudah kita buat.

Jadi nanti langkahnya akan menjadi seperti ini:

  1. Buat list untuk nampung musuh.
  2. Gambar musuh berdasarkan koordinat pada list.
  3. Buat musuh agar bergerak menuju markas kelinci.
  4. Hapus musuh saat sudah mencapai markas kelinci.

Baiklah, sekarang buka kembali file game.py. Lalu di langkah #1 tambahkan kode berikut untuk mengimpor fungsi randint():

from random import randin

Setelah itu buat variabel global yang diperlukan untuk musuh, seperti list, dan waktu ia akan muncul.

Pada langkah ke #2 tambahkan kode ini:

enemy_timer = 100 # waktu kemunculan
enemies = [[width, 100]] # list yang menampung koordinat musuh

Sehingga akan menjadi seperti ini:

Variabel global untuk musuh

Variabel enemy_timer akan kita kurangi -1 disetiap perulangan game loop. Lalu saat variabel ini mencapai nilai 0 musuh akan keluar.

Berikutnya tambahkan kode ini untuk mengimpor gambar enemy di langkah # 3.1:

enemy_img = pygame.image.load("resources/images/badguy.png")

Berikutnya silahkan tambahkan kode ini di bawah langkah # 6.1:

    # 6.2 - Draw Enemy
    # waktu musuh akan muncul
    enemy_timer -= 1
    if enemy_timer == 0:
        # buat musuh baru
        enemies.append([width, randint(50, height-32)])
        # reset enemy timer to random time
        enemy_timer = randint(1, 100)

    index = 0
    for enemy in enemies:
        # musuh bergerak dengan kecepatan 5 pixel ke kiri
        enemy[0] -= 5
        # hapus musuh saat mencapai batas layar sebelah kiri
        if enemy[0] < -64:
            enemies.pop(index)

    # gambar musuh ke layar
    for enemy in enemies:
        screen.blit(enemy_img, enemy)

Sehingga akan menjadi seperti ini:

Kode untuk menggambar musuh

Setelah itu, coba eksekusi lagi.

python game.py

Maka hasilnya:

Enemy

Yap! kita sudah berhasil menggambar musuh secara acak di titik y dan waktu kemunculannya juga kita tentukan secara acak.

Saat ini musuh tidak bisa ditembak, karena kita belum membuat kode untuk menghapus musuh saat berbenturan dengan anak panah.

Langkah 7: Collision Detection

Kita sudah berhasil menambahkan player dan juga musuhnya. Namun, sayang musuh belum bisa ditembak.

Ini karena kita belum membuat kode untuk collision detection atau pendeteksian benturan.

Ada dua benturan yang harus kita buat:

  1. Benturan antara anak panah dengan musuh (muduh ditembak)
  2. Benturan antara musuh dengan markas kelinci (player di serang)

Mari kita buat…

Pada langkan ke #6 di bagian #6.2 tambahkan kode ini dibawah hapus musuh:


        # 6.2.1 collision between enemies and castle 
        enemy_rect = pygame.Rect(enemy_img.get_rect())
        enemy_rect.top = enemy[1] # ambil titik y 
        enemy_rect.left = enemy[0] # ambil titik x
        # benturan musuh dengan markas kelinci
        if enemy_rect.left < 64:
            enemies.pop(index)
            print("Oh tidak, kita diserang!!")
        
        # 6.2.2 Check for collisions between enemies and arrows
        index_arrow = 0
        for bullet in arrows:
            bullet_rect = pygame.Rect(arrow.get_rect())
            bullet_rect.left = bullet[1]
            bullet_rect.top = bullet[2]
            # benturan anak panah dengan musuh
            if enemy_rect.colliderect(bullet_rect):
                score += 1
                enemies.pop(index)
                arrows.pop(index_arrow)
                print("Boom! mati kau!")
                print("Score: {}".format(score))
            index_arrow += 1
        index += 1

Sehingga akan menjadi seperti ini:

kode untuk mendeteksi benturan

Setelah itu, coba eksekusi lagi dan perhatikanlah hasilnya:

Collision detection PyGame

Penjelasan:

Pertama kita membuat objek rectangle (segi emapat) dari objek-objek yang akan berbenturan:

  • enemy_rect adalah objek rectangle untuk musuh;
  • bullet_rect adalah objek rectangle untuk anak panah.

Kalau kita gambarkan akan terlihat seperti ini:

Objek rectangle pada game

Setelah itu, kita buat kondisi saat musuh menabrak markas kelinci.

 if enemy_rect.left < 64:
    enemies.pop(index)
    print("Oh tidak, kita diserang!!")

Angka 64 itu maksudnya saat musuh sudah mencapai titik x = 64, maka dia harus menghilang dan itu artinya benteng atau markas player sedang diserang.

Batas markas

Lalu benturan beikutnya akan terjadi antara anak panah dengan musuh.

        # 6.2.2 Check for collisions between enemies and arrows
        index_arrow = 0
        for bullet in arrows:
            bullet_rect = pygame.Rect(arrow.get_rect())
            bullet_rect.left = bullet[1]
            bullet_rect.top = bullet[2]
            # benturan anak panah dengan musuh
            if enemy_rect.colliderect(bullet_rect):
                score += 1
                enemies.pop(index)
                arrows.pop(index_arrow)
                print("Boom! mati kau!")
                print("Score: {}".format(score))
            index_arrow += 1

Kita menggunakan fungsi colliderect() untuk mendeteksi apakah anak panah berbenturan dengan musuh atau tidak.

Kenapa menggunakan fungsi ini?

Karena yang mau kita cek tidak hanya benturan dari satu sisi saja. Melainkan juga dari semua sisi rectangle musuh.

Misalkan kita tembak musuh dari belakang, maka itu akan dianggap benturan yang sah atau valid.

Kemudian, saat terjadi benturan, kita menambahkan +1 untuk nilai score. Lalu menghapus anak panah dan musuh tersebut.

Langkah 8: Membuat HUD untuk Waktu dan Health Point

HUD (Heads Up Display) adalah sebuah tampilan untuk menyajikan data. Pada HUD, kita akan menampilkan data waktu dan health point untuk markas.

Silahkan buka file game.py lalu tambahkan variabel ini di bawah variabel score di langkah ke #2:

health_point = 194 # default health point for castle
countdown_timer = 90000 # 90 detik

Dua variabel di atas akan mnyimpan nilai awal untuk health_point dan waktu game. Nilai 194 kita berikan, karena di game asset healthbar.png memiliki lebar 194px.

Berikutnya tambahkan kode ini di langkah #3.1:

healthbar = pygame.image.load("resources/images/healthbar.png")
health = pygame.image.load("resources/images/health.png")

Sehingga akan menjadi seperti ini:

Kode untuk Health bar

Setelah itu tambahkan kode ini pada langkah ke # 6.2.1 saat musuh menyentuh markas kelinci:

health_point -= randint(5,20)

Shingga akan menjadi seperti ini:

Kode untuk mengurangi hp

Maksud kode di atas adalah mengurangi nilai health_value saat markas diserang. Kurangi dengan bilangan acak dari 5 sampai 20.

Berikutnya kita akan gambar health bar dan waktu. Silahkan tambahkan kode ini pada langkah #6 tepat setelah menggambar musuh:

    # 6.3 - Draw Health bar
    screen.blit(healthbar, (5,5))
    for hp in range(health_point):
        screen.blit(health, (hp+8, 8))

    # 6.4 - Draw clock
    font = pygame.font.Font(None, 24)
    minutes = int((countdown_timer-pygame.time.get_ticks())/60000) # 60000 itu sama dengan 60 detik
    seconds = int((countdown_timer-pygame.time.get_ticks())/1000%60)
    time_text = "{:02}:{:02}".format(minutes, seconds)
    clock = font.render(time_text, True, (255,255,255))
    textRect = clock.get_rect()
    textRect.topright = [635, 5]
    screen.blit(clock, textRect)

Sehingga akan menjadi seperti ini:

Kode untuk menggambar health bar dan timer

Untuk membuat teks di PyGame, kita bisa memanfaatkan objek font. Lalu nilai waktu count down untuk gamenya bisa kita dapatkan dari fungsi pygame.time.get_ticks().

Objek font memiliki method render() untuk me-render teks ke layar game. Method ini memiliki tiga paramater yaitu:

  1. text teks string yang akan ditampilkan, pada kode di atas kita memberikan time_text;
  2. antialias agar teksnya terlihat mulus, pada kode di atas kita memberikan nilai True;
  3. Terakhir paramternya dalah nilai warna. Kita memberikan (255, 255, 255) untuk warna putih.

Maka hasilnya akan seperti ini:

Membuat HUD Game

Langkah 9: Membuat Screen untuk Game Over

Sejauh ini game kita sudah berjalan dengan baik. Namun game-nya tidak akan pernah selesai alias Game Over.

Ada dua event yang akan menghakhiri game:

  1. Saat waktu habis (player menang)
  2. Saay health_point bernilai 0 (player kalah)

Mari kita buat…

Silahkan tambahkan kode berikut di atas variabel socre:

# exit code for game over and win codition
exitcode = 0
EXIT_CODE_GAME_OVER = 0
EXIT_CODE_WIN = 1

Kemudian pada langkah #3.1 tambahkan kode berikut:

gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")

Sehingga akan menjadi seperti ini:

Variabel untuk layar Game Over

Lalu di bagian akhir, di bawah langkah #9 tambahkan kode ini:

    # 10 - Win/Lose check ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    if pygame.time.get_ticks() > countdown_timer:
        running = False
        exitcode = EXIT_CODE_WIN
    if health_point <= 0:
        running = False
        exitcode = EXIT_CODE_GAME_OVER

# - End of Game Loop ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



# 11 - Win/lose display ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if exitcode == EXIT_CODE_GAME_OVER:
    screen.blit(gameover, (0, 0))
else:
    screen.blit(youwin, (0, 0))

# Tampilkan score
text = font.render("Score: {}".format(score), True, (255, 255, 255))
textRect = text.get_rect()
textRect.centerx = screen.get_rect().centerx
textRect.centery = screen.get_rect().centery + 24
screen.blit(text, textRect)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit(0)
    pygame.display.flip()

Kode di atas berfungsi untuk mengecek apakah game sudah selesai atau tidak. Lalu menampilkan hasilnya.

Game Over

Langkah 10: Menambahkan Musik dan Effek Suara

Wohoo… kita sudah sampai di langkah terakhir.

Nah, sekarang biar game-nya tidak sepi dan sunyi. Kita tambahkan background musik dan efek suara saat event tertentu.

Silahkan tambahkan kode berikut di langkah #3, tepatnya di bawah objek youwin:

# 3.1 - Load audio
pygame.mixer.init()
hit_sound = pygame.mixer.Sound("resources/audio/explode.wav")
enemy_hit_sound = pygame.mixer.Sound("resources/audio/enemy.wav")
shoot_sound = pygame.mixer.Sound("resources/audio/shoot.wav")
hit_sound.set_volume(0.05)
enemy_hit_sound.set_volume(0.05)
shoot_sound.set_volume(0.05)

# background music
pygame.mixer.music.load("resources/audio/moonlight.wav")
pygame.mixer.music.play(-1, 0.0)
pygame.mixer.music.set_volume(0.25)

Sehingga akan menjadi seperti ini:

Kode untuk musik

Pada kode di atas, kita membuat objek audio berdasrakan file wav di asset.

Background music akan diputar terus menerus selama game dimainkan. Sedangkan efek suara akan diputar saat terjadi event teretntu.

Misalnya: saat musuh ditembak, saat musuh menyerang benteng, dll.

Untuk memutar efek suara, kita tinggal panggil fungsi play() pada objek audio.

Sekarang, tambahkan kode untuk memutar efek suara pada event:

  1. Saat musuh menyentuh benteng atau markas kelinci
  2. Saat musuh terkena tembakan.

Pergi ke kode di bagian collision detection, lalu tambahkan kode ini:

# collision enemy dengan castle
hit_sound.play()

# collision arrow dengan enemy
enemy_hit_sound.play()

Sehingga akan menjadi seperti ini:

Kode untuk effek suara

Satu lagi, tambahkan shoot_sound.play() saat event MOUSEBUTTONDOWN:

Kode untuk suara saat mendembak

Selesai.

…dan coba mainkan lagi gamenya.

๐ŸŽ Source Code tutorial ini dapat kamu download di Github

Apa Selanjutnya?

Bisa dibilang, kita sudah selesai membuat gamenya.

Tapi…

Masih banyak kekurangannya dan bug, seperti:

  • Player saat melewati batas layar, ia akan menghilang;
  • Jumlah anak panah yang dimiliki player tak terbatas;
  • Score belum ditampilkan saat permainan berlangsung;
  • Source code masih berantakan kerena tidak menggunakan fungsi dan class.
  • dll.

Selanjutnya silahkan kamu lengkapi kekurangannya.

Selamat belajar.

P.S: Tutorial ini dibuat ulang berdsarkan tutorial dari raywenderlich.com