Langkah Mudah Membuat Aplikasi Desktop dengan Tkinter di Python

Snake Game With Python + Tkinter

Snake Game With Python + Tkinter

Pengertian, kode, penjelasan baris demi baris, tabel penilaian, dan petunjuk menjalankan di Thonny.

Pendahuluan

Artikel ini menjelaskan secara menyeluruh bagaimana membuat Game Ular (Snake Game) menggunakan Python dan library tkinter. Semua contoh bisa dijalankan offline menggunakan Thonny IDE

Apa yang akan dipelajari

  • Pengenalan tkinter dan import
  • Cara memberi komentar di Python
  • Kode lengkap Game Ular dengan menu, pengaturan kecepatan, rintangan, skor, dan tombol restart
  • Penjelasan setiap bagian kode (baris demi baris)
  • Instruksi menjalankan di Thonny

Pengertian Dasar

1. Apa itu tkinter?

tkinter adalah library bawaan Python yang digunakan untuk membuat aplikasi berbasis GUI (Graphical User Interface). Dengan tkinter kita dapat membuat jendela, tombol, teks, menu, area gambar (Canvas), dan menangani input keyboard/mouse seperti pada aplikasi desktop.

2. Apa itu import?

import dipakai untuk memanggil modul atau library yang akan digunakan di program. Contoh: import random memanggil modul untuk menghasilkan angka acak.

3. Cara memberi komentar di Python

Gunakan # untuk komentar satu baris. Untuk komentar beberapa baris bisa pakai tiga kutip '''...''' atau """...""".

# Ini komentar satu baris
'''
Komentar
lebih dari satu baris
'''
      

Salin & Simpan sebagai snake_game.py

Berikut kode lengkap yang sudah dioptimalkan: menu, pengaturan kecepatan, rintangan, skor, dan restart.

import tkinter as tk
import random

# --- Pengaturan Awal ---
LEBAR = 400
TINGGI = 400
UKURAN_KOTAK = 20
WARNA_LATAR = "lightgreen"

# --- Jendela Utama ---
root = tk.Tk()
root.title("Game Ular Sekolah")
root.resizable(False, False)

# --- Kanvas Utama ---
canvas = tk.Canvas(root, width=LEBAR, height=TINGGI, bg=WARNA_LATAR)
canvas.pack()

# Variabel global
arah = "kanan"
ular = []
makanan = ()
rintangan = []
skor = 0
game_berjalan = False
kecepatan = 150  # default kecepatan (ms)

# --- Fungsi Menggambar ---
def gambar_ular():
    canvas.delete("snake")
    for (x, y) in ular:
        canvas.create_rectangle(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                                fill="green", outline="darkgreen", tags="snake")

def gambar_makanan():
    canvas.delete("food")
    x, y = makanan
    canvas.create_oval(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                       fill="red", tags="food")

def gambar_skor():
    canvas.delete("score")
    canvas.create_text(60, 10, text=f"Skor: {skor}",
                       font=("Arial", 12, "bold"), fill="black", tags="score")

def gambar_rintangan():
    canvas.delete("wall")
    for (x, y) in rintangan:
        canvas.create_rectangle(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                                fill="gray", outline="black", tags="wall")

# --- Fungsi Membuat Objek ---
def buat_makanan():
    x = random.randrange(0, LEBAR, UKURAN_KOTAK)
    y = random.randrange(0, TINGGI, UKURAN_KOTAK)
    return (x, y)

def buat_rintangan():
    daftar_rintangan = []
    for _ in range(8):
        x = random.randrange(0, LEBAR, UKURAN_KOTAK)
        y = random.randrange(0, TINGGI, UKURAN_KOTAK)
        daftar_rintangan.append((x, y))
    return daftar_rintangan

# --- Fungsi Gerak Ular ---
def gerak_ular():
    global makanan, skor, game_berjalan

    if not game_berjalan:
        return

    kepala_x, kepala_y = ular[0]

    if arah == "kanan":
        kepala_x += UKURAN_KOTAK
    elif arah == "kiri":
        kepala_x -= UKURAN_KOTAK
    elif arah == "atas":
        kepala_y -= UKURAN_KOTAK
    elif arah == "bawah":
        kepala_y += UKURAN_KOTAK

    kepala_baru = (kepala_x, kepala_y)

    # --- Cek Tabrakan ---
    if (
        kepala_x < 0 or kepala_x >= LEBAR or
        kepala_y < 0 or kepala_y >= TINGGI or
        kepala_baru in ular or kepala_baru in rintangan
    ):
        game_over()
        return

    ular.insert(0, kepala_baru)

    # --- Makan makanan ---
    if kepala_baru == makanan:
        skor += 10
        makanan_baru = buat_makanan()
        while makanan_baru in ular or makanan_baru in rintangan:
            makanan_baru = buat_makanan()
        makanan = makanan_baru
    else:
        ular.pop()

    gambar_ular()
    gambar_makanan()
    gambar_rintangan()
    gambar_skor()

    root.after(kecepatan, gerak_ular)

# --- Fungsi Ubah Arah ---
def ubah_arah(event):
    global arah
    key = event.keysym
    if key == "Up" and arah != "bawah":
        arah = "atas"
    elif key == "Down" and arah != "atas":
        arah = "bawah"
    elif key == "Left" and arah != "kanan":
        arah = "kiri"
    elif key == "Right" and arah != "kiri":
        arah = "kanan"
    elif key == "Return":  # ENTER untuk pilih menu
        pilih_menu()
    elif key == "Up" or key == "Down":  # navigasi menu
        ubah_pilihan(key)

# --- Fungsi Game Over ---
def game_over():
    global game_berjalan
    game_berjalan = False
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, TINGGI / 2 - 30,
                       text="GAME OVER", font=("Arial", 24, "bold"), fill="red")
    canvas.create_text(LEBAR / 2, TINGGI / 2,
                       text=f"Skor Akhir: {skor}", font=("Arial", 14), fill="black")

    # Tombol restart
    canvas.create_rectangle(130, 250, 270, 290, fill="yellow", tags="restart_box")
    canvas.create_text(200, 270, text="Main Lagi", font=("Arial", 12, "bold"),
                       fill="black", tags="restart_text")

    canvas.tag_bind("restart_box", "", lambda e: mulai_game())
    canvas.tag_bind("restart_text", "", lambda e: mulai_game())

# --- Fungsi Mulai Game ---
def mulai_game():
    global ular, makanan, arah, skor, game_berjalan, rintangan
    canvas.delete("all")
    ular = [(100, 100), (80, 100), (60, 100)]
    makanan = buat_makanan()
    rintangan = buat_rintangan()
    arah = "kanan"
    skor = 0
    game_berjalan = True
    gambar_ular()
    gambar_makanan()
    gambar_rintangan()
    gambar_skor()
    gerak_ular()

# --- MENU UTAMA ---
pilihan_menu = ["Mulai Game", "Pengaturan", "Keluar"]
indeks_pilihan = 0

def tampilkan_menu():
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, 100, text="🐍 SNAKE GAME 🐍",
                       font=("Arial", 22, "bold"), fill="black")

    for i, teks in enumerate(pilihan_menu):
        warna = "white" if i == indeks_pilihan else "lightgray"
        canvas.create_rectangle(140, 180 + i * 60, 260, 220 + i * 60,
                                fill=warna, outline="black", tags=f"menu{i}")
        canvas.create_text(200, 200 + i * 60, text=teks,
                           font=("Arial", 12, "bold"), fill="black", tags=f"menu{i}")

    canvas.tag_bind("menu0", "", lambda e: mulai_game())
    canvas.tag_bind("menu1", "", lambda e: tampilkan_pengaturan())
    canvas.tag_bind("menu2", "", lambda e: root.destroy())

def ubah_pilihan(key):
    global indeks_pilihan
    if key == "Up":
        indeks_pilihan = (indeks_pilihan - 1) % len(pilihan_menu)
    elif key == "Down":
        indeks_pilihan = (indeks_pilihan + 1) % len(pilihan_menu)
    tampilkan_menu()

def pilih_menu():
    if indeks_pilihan == 0:
        mulai_game()
    elif indeks_pilihan == 1:
        tampilkan_pengaturan()
    elif indeks_pilihan == 2:
        root.destroy()

# --- MENU PENGATURAN ---
def tampilkan_pengaturan():
    global kecepatan
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, 100, text="⚙️ PENGATURAN KECEPATAN ⚙️",
                       font=("Arial", 18, "bold"), fill="black")

    opsi = [("Pelan", 200), ("Sedang", 150), ("Cepat", 100)]
    for i, (teks, nilai) in enumerate(opsi):
        canvas.create_rectangle(140, 180 + i * 60, 260, 220 + i * 60,
                                fill="white", outline="black", tags=f"speed{i}")
        canvas.create_text(200, 200 + i * 60, text=teks,
                           font=("Arial", 12, "bold"), fill="black", tags=f"speed{i}")
        canvas.tag_bind(f"speed{i}", "", lambda e, v=nilai: atur_kecepatan(v))

    # Tombol kembali
    canvas.create_rectangle(140, 360, 260, 400, fill="lightgray", tags="back_box")
    canvas.create_text(200, 380, text="Kembali", font=("Arial", 12, "bold"),
                       fill="black", tags="back_text")
    canvas.tag_bind("back_box", "", lambda e: tampilkan_menu())
    canvas.tag_bind("back_text", "", lambda e: tampilkan_menu())

def atur_kecepatan(nilai):
    global kecepatan
    kecepatan = nilai
    tampilkan_menu()

# --- Jalankan Program ---
root.bind("", ubah_arah)
tampilkan_menu()
root.mainloop()


Catatan: saat mem-paste kode pastikan indentasi (spasi/tabs) tetap sama. Simpan file sebagai snake_game.py lalu jalankan di Thonny (F5).

Penjelasan Kode Dipisah Per Bagian

1) Baris awal: import dan pengaturan awal

import tkinter as tk
import random

# --- Pengaturan Awal ---
LEBAR = 400
TINGGI = 400
UKURAN_KOTAK = 20
WARNA_LATAR = "lightgreen"

Penjelasan:

  • import tkinter as tk — Memanggil library GUI. Kita beri singkatan tk agar pemanggilan fungsi tkinter lebih ringkas (misalnya tk.Tk()).
  • import random — Memanggil modul untuk membuat angka acak (dipakai untuk posisi makanan dan rintangan).
  • Variabel LEBAR, TINGGI, UKURAN_KOTAK, dan WARNA_LATAR berfungsi sebagai pengaturan ukuran layar dan tampilan. Memudahkan jika ingin diubah nanti.

2) Membuat jendela utama (root) dan canvas

# --- Jendela Utama ---
root = tk.Tk()
root.title("Game Ular Sekolah")
root.resizable(False, False)

# --- Kanvas Utama ---
canvas = tk.Canvas(root, width=LEBAR, height=TINGGI, bg=WARNA_LATAR)
canvas.pack()

Penjelasan:

  • root = tk.Tk() — Membuat jendela utama. Semua komponen GUI akan diletakkan di dalam root.
  • root.title() — Menentukan judul jendela.
  • root.resizable(False, False) — Mencegah pengguna mengubah ukuran jendela agar tata letak tetap konsisten.
  • canvas = tk.Canvas(...) — Membuat area gambar (kanvas) untuk menggambar ular, makanan, dan rintangan.
  • canvas.pack() — Memasukkan kanvas ke dalam jendela agar tampil.

3) Variabel global

# Variabel global
arah = "kanan"
ular = []
makanan = ()
rintangan = []
skor = 0
game_berjalan = False
kecepatan = 150  # default kecepatan (ms)

Penjelasan:

  • arah menyimpan arah gerak ular saat ini.
  • ular adalah list berisi posisi bagian tubuh ular (setiap elemen tuple x,y).
  • makanan menyimpan posisi makanan (tuple x,y).
  • rintangan list posisi rintangan (obstacle).
  • skor menyimpan nilai skor pemain.
  • game_berjalan Boolean yang menandakan apakah game sedang berjalan.
  • kecepatan menentukan interval pergerakan ular dalam milidetik (ms).

4) Fungsi gambar (rendering)

def gambar_ular():
    canvas.delete("snake")
    for (x, y) in ular:
        canvas.create_rectangle(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                                fill="green", outline="darkgreen", tags="snake")

Penjelasan:

  • canvas.delete("snake") menghapus semua objek dengan tag snake agar digambar ulang (menghindari jejak).
  • Perulangan menggambar setiap bagian tubuh ular sebagai kotak persegi.
  • Tag snake memudahkan untuk menghapus/menangani objek ular pada kanvas.
def gambar_makanan():
    canvas.delete("food")
    x, y = makanan
    canvas.create_oval(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                       fill="red", tags="food")

Penjelasan: menggambar makanan sebagai lingkaran kecil (oval) berwarna merah.

def gambar_skor():
    canvas.delete("score")
    canvas.create_text(60, 10, text=f"Skor: {skor}",
                       font=("Arial", 12, "bold"), fill="black", tags="score")

Penjelasan: menampilkan teks skor di pojok atas.

def gambar_rintangan():
    canvas.delete("wall")
    for (x, y) in rintangan:
        canvas.create_rectangle(x, y, x + UKURAN_KOTAK, y + UKURAN_KOTAK,
                                fill="gray", outline="black", tags="wall")

Penjelasan: menggambar rintangan sebagai kotak abu-abu dengan tag wall.

5) Fungsi membuat objek acak

def buat_makanan():
    x = random.randrange(0, LEBAR, UKURAN_KOTAK)
    y = random.randrange(0, TINGGI, UKURAN_KOTAK)
    return (x, y)

Penjelasan: random.randrange(0, LEBAR, UKURAN_KOTAK) memilih posisi grid yang sesuai ukuran kotak.

def buat_rintangan():
    daftar_rintangan = []
    for _ in range(8):
        x = random.randrange(0, LEBAR, UKURAN_KOTAK)
        y = random.randrange(0, TINGGI, UKURAN_KOTAK)
        daftar_rintangan.append((x, y))
    return daftar_rintangan

Penjelasan: membuat beberapa rintangan acak pada grid.

6) Fungsi utama: gerak_ular()

def gerak_ular():
    global makanan, skor, game_berjalan

    if not game_berjalan:
        return

    kepala_x, kepala_y = ular[0]

    if arah == "kanan":
        kepala_x += UKURAN_KOTAK
    elif arah == "kiri":
        kepala_x -= UKURAN_KOTAK
    elif arah == "atas":
        kepala_y -= UKURAN_KOTAK
    elif arah == "bawah":
        kepala_y += UKURAN_KOTAK

    kepala_baru = (kepala_x, kepala_y)

    # --- Cek Tabrakan ---
    if (
        kepala_x < 0 or kepala_x >= LEBAR or
        kepala_y < 0 or kepala_y >= TINGGI or
        kepala_baru in ular or kepala_baru in rintangan
    ):
        game_over()
        return

    ular.insert(0, kepala_baru)

    # --- Makan makanan ---
    if kepala_baru == makanan:
        skor += 10
        makanan_baru = buat_makanan()
        while makanan_baru in ular or makanan_baru in rintangan:
            makanan_baru = buat_makanan()
        makanan = makanan_baru
    else:
        ular.pop()

    gambar_ular()
    gambar_makanan()
    gambar_rintangan()
    gambar_skor()

    root.after(kecepatan, gerak_ular)

Penjelasan utama (ringkasan):

  • Menghitung posisi kepala baru berdasarkan arah.
  • Mengecek apakah kepala menabrak dinding, dirinya sendiri, atau rintangan — jika ya maka game_over().
  • Jika kepala berada di posisi makanan, skor bertambah dan tubuh ular tidak dihapus (sehingga panjang bertambah).
  • Jika tidak makan, bagian ekor dihapus (ular.pop()) sehingga efeknya ular terlihat bergerak tanpa bertambah panjang.
  • root.after(kecepatan, gerak_ular) memanggil fungsi ini berulang sesuai interval kecepatan.

7) Mengubah arah (input keyboard)

def ubah_arah(event):
    global arah
    key = event.keysym
    if key == "Up" and arah != "bawah":
        arah = "atas"
    elif key == "Down" and arah != "atas":
        arah = "bawah"
    elif key == "Left" and arah != "kanan":
        arah = "kiri"
    elif key == "Right" and arah != "kiri":
        arah = "kanan"
    elif key == "Return":  # ENTER untuk pilih menu
        pilih_menu()
    elif key == "Up" or key == "Down":  # navigasi menu
        ubah_pilihan(key)

Penjelasan: event event.keysym memberi nama tombol yang ditekan. Fungsi ini mencegah balik arah 180° langsung (misal dari kanan langsung ke kiri) agar tidak tabrakan sendiri tiba-tiba.

8) Game Over & Restart

def game_over():
    global game_berjalan
    game_berjalan = False
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, TINGGI / 2 - 30,
                       text="GAME OVER", font=("Arial", 24, "bold"), fill="red")
    canvas.create_text(LEBAR / 2, TINGGI / 2,
                       text=f"Skor Akhir: {skor}", font=("Arial", 14), fill="black")

    # Tombol restart
    canvas.create_rectangle(130, 250, 270, 290, fill="yellow", tags="restart_box")
    canvas.create_text(200, 270, text="Main Lagi", font=("Arial", 12, "bold"),
                       fill="black", tags="restart_text")

    canvas.tag_bind("restart_box", "", lambda e: mulai_game())
    canvas.tag_bind("restart_text", "", lambda e: mulai_game())

Penjelasan: pada saat game over, semua objek dihapus, pesan muncul, dan dibuat tombol restart dengan fungsi klik mouse.

9) Memulai game

def mulai_game():
    global ular, makanan, arah, skor, game_berjalan, rintangan
    canvas.delete("all")
    ular = [(100, 100), (80, 100), (60, 100)]
    makanan = buat_makanan()
    rintangan = buat_rintangan()
    arah = "kanan"
    skor = 0
    game_berjalan = True
    gambar_ular()
    gambar_makanan()
    gambar_rintangan()
    gambar_skor()
    gerak_ular()

Penjelasan: fungsi ini mengatur ulang kondisi awal game sebelum dimainkan.

10) Menu utama & pengaturan

# --- MENU UTAMA ---
pilihan_menu = ["Mulai Game", "Pengaturan", "Keluar"]
indeks_pilihan = 0

def tampilkan_menu():
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, 100, text="🐍 SNAKE GAME 🐍",
                       font=("Arial", 22, "bold"), fill="black")

    for i, teks in enumerate(pilihan_menu):
        warna = "white" if i == indeks_pilihan else "lightgray"
        canvas.create_rectangle(140, 180 + i * 60, 260, 220 + i * 60,
                                fill=warna, outline="black", tags=f"menu{i}")
        canvas.create_text(200, 200 + i * 60, text=teks,
                           font=("Arial", 12, "bold"), fill="black", tags=f"menu{i}")

    canvas.tag_bind("menu0", "", lambda e: mulai_game())
    canvas.tag_bind("menu1", "", lambda e: tampilkan_pengaturan())
    canvas.tag_bind("menu2", "", lambda e: root.destroy())

def ubah_pilihan(key):
    global indeks_pilihan
    if key == "Up":
        indeks_pilihan = (indeks_pilihan - 1) % len(pilihan_menu)
    elif key == "Down":
        indeks_pilihan = (indeks_pilihan + 1) % len(pilihan_menu)
    tampilkan_menu()

def pilih_menu():
    if indeks_pilihan == 0:
        mulai_game()
    elif indeks_pilihan == 1:
        tampilkan_pengaturan()
    elif indeks_pilihan == 2:
        root.destroy()

Penjelasan: membuat menu interaktif yang bisa dipilih dengan keyboard atau mouse.

def tampilkan_pengaturan():
    global kecepatan
    canvas.delete("all")
    canvas.create_text(LEBAR / 2, 100, text="⚙️ PENGATURAN KECEPATAN ⚙️",
                       font=("Arial", 18, "bold"), fill="black")

    opsi = [("Pelan", 200), ("Sedang", 150), ("Cepat", 100)]
    for i, (teks, nilai) in enumerate(opsi):
        canvas.create_rectangle(140, 180 + i * 60, 260, 220 + i * 60,
                                fill="white", outline="black", tags=f"speed{i}")
        canvas.create_text(200, 200 + i * 60, text=teks,
                           font=("Arial", 12, "bold"), fill="black", tags=f"speed{i}")
        canvas.tag_bind(f"speed{i}", "", lambda e, v=nilai: atur_kecepatan(v))

    # Tombol kembali
    canvas.create_rectangle(140, 360, 260, 400, fill="lightgray", tags="back_box")
    canvas.create_text(200, 380, text="Kembali", font=("Arial", 12, "bold"),
                       fill="black", tags="back_text")
    canvas.tag_bind("back_box", "", lambda e: tampilkan_menu())
    canvas.tag_bind("back_text", "", lambda e: tampilkan_menu())

def atur_kecepatan(nilai):
    global kecepatan
    kecepatan = nilai
    tampilkan_menu()

Penjelasan: menu pengaturan berisi opsi pelan/sedang/cepat. Saat pilih, fungsi atur_kecepatan mengubah nilai global kecepatan.

11) Menjalankan program

# --- Jalankan Program ---
root.bind("", ubah_arah)
tampilkan_menu()
root.mainloop()

Penjelasan: root.bind("<Key>", ubah_arah) menghubungkan fungsi keyboard. tampilkan_menu() menampilkan menu awal. root.mainloop() menjalankan aplikasi.

Tabel Penilaian & Tugas Siswa

AspekBobotKriteria
Fungsionalitas40%Program berjalan, kontrol, skor, rintangan
Tampilan (UI)25%Menu jelas, teks terbaca, warna sesuai
Kreativitas & Ekstensi20%Penambahan fitur: level, suara, dsb.
Dokumentasi15%Penjelasan kode & komentar dalam kode

Tugas

  1. Jalankan dan pahami seluruh kode.
  2. Tambahkan komentar pada setiap fungsi yang kamu buat.
  3. Tambahkan fitur: skor tertinggi (high score) atau level.
  4. Ubah warna/tata letak lalu kumpulkan hasil dengan screenshot.

Post a Comment

0 Comments