Membuat Game Sederhana Memory Match

Membuat Game Sederhana Memory Match

PyCoding-ID - Python telah menjadi bahasa pilihan bagi banyak pengembang, tidak hanya untuk machine learning dan analisis data, tetapi juga untuk pengembangan aplikasi desktop. Melalui pustaka antarmuka pengguna grafis (GUI) seperti PyQt5, pengembang dapat menciptakan aplikasi desktop yang fungsional dan menarik secara visual. Artikel ini akan mengupas tuntas proses pengembangan game Memory Match sederhana sebagai studi kasus untuk memahami prinsip-prinsip inti pemrograman GUI dengan Python.


PyCoding - Game Sederhana Memory Match

Dasar-dasar Pengembangan GUI dengan PyQt5

PyQt5 menyediakan kerangka kerja yang solid untuk membangun aplikasi yang cross-platform. Setiap elemen visual dalam aplikasi, seperti tombol, label, dan jendela, direpresentasikan sebagai objek. Logika program diatur melalui event-driven programming, di mana fungsi-fungsi tertentu (slot) dipicu oleh tindakan pengguna (event) seperti klik tombol atau input keyboard.

Dalam proyek ini, kita menggunakan beberapa komponen kunci:

  • QMainWindow: Kelas dasar untuk jendela utama aplikasi.
  • QGridLayout: Manajer tata letak yang menempatkan widget dalam format grid, ideal untuk papan permainan seperti Memory Match.
  • QPushButton: Objek tombol yang mewakili setiap kartu. Sinyal clicked dari tombol ini terhubung ke metode card_clicked untuk memproses logika permainan.
  • QTimer: Digunakan untuk mengontrol jeda waktu, seperti menutup kembali kartu yang tidak cocok setelah beberapa saat. Ini adalah contoh sempurna dari non-blocking operations dalam GUI.

Analisis Kode: Arsitektur dan Implementasi

Kode game Memory Match ini dirancang dengan pendekatan berorientasi objek (OOP) dalam kelas FunMatchGame.

1. Inisialisasi dan Pengacakan Kartu

Pada metode __init__, data kartu (emoji) diinisialisasi dalam sebuah list, digandakan untuk membuat pasangan, lalu diacak menggunakan random.shuffle().

2. Struktur Antarmuka Pengguna (UI)

Metode init_ui bertanggung jawab untuk membangun semua elemen visual.

  • Gaya (Styling): Kode menggunakan stylesheet untuk mengubah tampilan elemen. Properti CSS seperti background-color, border-radius, dan font-size diterapkan langsung ke widget. Pendekatan ini memisahkan logika dari desain, menjadikannya lebih mudah untuk dikelola.
  • Komponen Fungsional: QLabel digunakan untuk menampilkan skor dan status permainan. QPushButton untuk kartu, diatur dalam QGridLayout.

3. Logika Permainan

Logika inti terletak pada metode card_clicked.

  • Penanganan State: Variabel seperti self.first_card dan self.second_card melacak kartu yang dibalik oleh pemain. Variabel self.game_locked berfungsi sebagai flag untuk mencegah input tambahan saat dua kartu sedang diperiksa.
  • Kondisi Pencocokan: Perbandingan dilakukan berdasarkan atribut card_value dari tombol.
  • Umpan Balik Visual: Warna tombol berubah secara dinamis untuk memberikan umpan balik kepada pemain:

Kode Program Lengkap

Berikut adalah kode lengkap untuk game "Fun Match Game!" yang dapat Anda salin, tempel, dan jalankan.

import sys
import random
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget,
QGridLayout
, QPushButton, QVBoxLayout, QLabel
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QFont

class FunMatchGame(QMainWindow):
def __init__(self):
super().__init__()

self.card_size = 80
self.grid_rows = 4
self.grid_cols = 4
self.num_pairs = (self.grid_rows * self.grid_cols) // 2
# Menggunakan emoji sebagai "gambar" kartu
self.card_contents = ['🍎', '🍉', '🍇', '🍊', '🍓', '🍋', '🍒', '🍍'] * 2
random.shuffle(self.card_contents)
self.first_card = None
self.second_card = None
self.matched_pairs = 0
self.game_locked = False
self.score = 0
self.init_ui()

def init_ui(self):
# Mengubah judul aplikasi menjadi lebih fun dan simple
self.setWindowTitle('Fun Match Game!')
self.setGeometry(100, 100, 420, 500)
# Menggunakan background yang lebih cerah dan menarik
self.setStyleSheet("background-color: #f7e1d7;")
central_widget = QWidget()
self.setCentralWidget(central_widget)

main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)

# Mengatur font untuk label
font_style = QFont("Arial Rounded MT Bold", 24)
self.score_label = QLabel(f"Skor: {self.score}")
self.score_label.setAlignment(Qt.AlignCenter)
self.score_label.setFont(font_style)
self.score_label.setStyleSheet("color: #4a4a4a; margin-bottom: 10px;")
main_layout.addWidget(self.score_label)
self.status_label = QLabel("Temukan semua pasangannya!")
self.status_label.setAlignment(Qt.AlignCenter)
font_style.setPointSize(18)
self.status_label.setFont(font_style)
self.status_label.setStyleSheet("color: #8c8c8c; margin-bottom: 10px;")
main_layout.addWidget(self.status_label)

self.grid_layout = QGridLayout()
self.card_buttons = []
for i in range(self.grid_rows):
for j in range(self.grid_cols):
button = QPushButton("?")
button.setFixedSize(self.card_size, self.card_size)
button.setFont(QFont("Segoe UI Emoji", 30))
button.setStyleSheet("""
QPushButton {
background-color: #ffb6c1; /* Warna pink cerah */
color: #ffffff;
border: 3px solid #ff69b4; /* Border yang lebih tebal
dan mencolok */
border-radius: 15px; /* Border yang lebih membulat */
}
QPushButton:hover {
background-color: #ff91b8;
}
""")
button.card_value = self.card_contents[i * self.grid_cols + j]
button.clicked.connect(self.card_clicked)
self.grid_layout.addWidget(button, i, j)
self.card_buttons.append(button)
main_layout.addLayout(self.grid_layout)
self.close_timer = QTimer(self)
self.close_timer.setSingleShot(True)
self.close_timer.timeout.connect(self.close_mismatched_cards)
restart_button = QPushButton("Mulai Ulang")
restart_button.setStyleSheet("""
QPushButton {
background-color: #ff69b4;
color: white;
border-radius: 10px;
padding: 10px;
font-size: 16px;
font-weight: bold;
}
QPushButton:hover {
background-color: #ff559f;
}
""")
restart_button.clicked.connect(self.restart_game)
main_layout.addWidget(restart_button)
# Tambahkan footer
footer_label = QLabel("Copyright © Noval MR. Daud")
footer_label.setAlignment(Qt.AlignCenter)
footer_label.setStyleSheet("color: #a0a0a0; font-size: 12px; 
margin-top: 20px;")
main_layout.addWidget(footer_label)

def card_clicked(self):
if self.game_locked: return
sender_button = self.sender()
if sender_button.text() != '?' or sender_button == self.first_card: return
sender_button.setText(sender_button.card_value)
sender_button.setStyleSheet("""
QPushButton {
font-size: 30px;
background-color: #ff4500; /* Warna merah oranye */
color: white;
border: 3px solid #e53e00;
border-radius: 15px;
}
""")

if not self.first_card:
self.first_card = sender_button
else:
self.second_card = sender_button
self.game_locked = True
if self.first_card.card_value == self.second_card.card_value:
self.score += 10
self.matched_pairs += 1
self.status_label.setText 
(f"Pasangan ditemukan! Pasangan: {self.matched_pairs}/{self.num_pairs}")
self.score_label.setText(f"Skor: {self.score}")
self.first_card.setStyleSheet("font-size: 30px; 
background-color: #3cb371; color: 
white; border: 3px solid #2e8b57; border-radius: 15px;")
self.second_card.setStyleSheet("font-size: 30px; 
background-color: #3cb371; color: 
white; border: 3px solid #2e8b57; border-radius: 15px;")
self.first_card.setEnabled(False)
self.second_card.setEnabled(False)
self.first_card, self.second_card = None, None
self.game_locked = False
if self.matched_pairs == self.num_pairs:
self.status_label.setText("Selamat, Anda menang!")
else:
self.score = max(0, self.score - 2)
self.status_label.setText("Tidak cocok. Coba lagi!")
self.score_label.setText(f"Skor: {self.score}")
self.close_timer.start(1000)

def close_mismatched_cards(self):
self.first_card.setText("?")
self.first_card.setStyleSheet("font-size: 30px; 
background-color: #ffb6c1; color: #ffffff;
 border: 3px solid #ff69b4; border-radius: 15px;")
self.second_card.setText("?")
self.second_card.setStyleSheet("font-size: 30px; 
background-color: #ffb6c1; color: #ffffff; 
border: 3px solid #ff69b4; border-radius: 15px;")
self.first_card, self.second_card = None, None
self.game_locked = False
self.status_label.setText("Temukan pasangannya!")

def restart_game(self):
self.first_card, self.second_card = None, None
self.matched_pairs, self.game_locked, self.score = 0, False, 0
self.score_label.setText(f"Skor: {self.score}")
random.shuffle(self.card_contents)
for i, button in enumerate(self.card_buttons):
button.card_value = self.card_contents[i]
button.setText("?")
button.setEnabled(True)
button.setStyleSheet("font-size: 30px; 
background-color: #ffb6c1; color: #ffffff; 
border: 3px solid #ff69b4; border-radius: 15px;")
self.status_label.setText("Temukan semua pasangannya!")

def main():
app = QApplication(sys.argv)
game = FunMatchGame()
game.show()
sys.exit(app.exec_())

if __name__ == '__main__':
main()






Proyek game sederhana ini menawarkan banyak keunggulan:

PyCoding - Game Sederhana Memory Match

  • Ringkas dan Mandiri: Seluruh kode terintegrasi dalam satu file, tanpa dependensi eksternal selain pustaka standar Python dan PyQt5. Ini ideal untuk proyek portofolio atau demonstrasi.
  • Fleksibilitas Desain: Penggunaan stylesheet memudahkan kustomisasi desain sesuai kebutuhan. Pengembang dapat mengganti palet warna, border, dan font dengan cepat.
  • Fondasi Pembelajaran: Proyek ini berfungsi sebagai fondasi yang kuat untuk membangun aplikasi PyQt5 yang lebih kompleks, seperti aplikasi manajemen data, utilitas, atau bahkan game yang lebih rumit.

Sebagai kesimpulan, membangun game sederhana dengan Python dan PyQt5 adalah cara yang sangat efektif untuk mempraktikkan keterampilan pemrograman dan memahami arsitektur aplikasi GUI modern. Proyek ini tidak hanya menghasilkan produk yang fungsional, tetapi juga memberikan wawasan berharga ke dalam dunia pengembangan perangkat lunak.

Posting Komentar

0 Komentar