PPB G - Cake Clicker App

Nama : Muhammad Hafidh Rosyadi
NRP : 5025211013
Kelas  : PPB G
 
 
 
 
 
 

Kode : https://github.com/Hfdrsyd/Tugas-PPB/tree/main/DessertClicker


🍰 Membangun Aplikasi Dessert Clicker dengan Kotlin & Jetpack Compose

Dessert Clicker adalah aplikasi game sederhana di mana pengguna mengetuk gambar makanan penutup (dessert) untuk mendapatkan uang virtual. Setiap klik meningkatkan jumlah dessert yang terjual dan total pendapatan. Aplikasi ini menyenangkan, ringan, dan sangat bagus untuk mempelajari dasar pengembangan Android modern.


🎮 Gambaran Umum Aplikasi

Mekanisme Dasar Permainan:

  • Setiap klik pada gambar dessert akan:

    • ✅ Menambah jumlah dessert yang terjual

    • ✅ Menambah pendapatan berdasarkan harga dessert saat ini

  • Seiring peningkatan penjualan:

    • 🎂 Dessert akan berubah (misalnya: dari cupcake menjadi donut hingga oreo)

    • 💰 Harga per klik juga akan meningkat


✨ Fitur Utama

Fitur Penjelasan
🖱️ Klik untuk bermain Tap pada gambar dessert untuk menambah penjualan dan pendapatan
📈 Sistem progresif Dessert berganti otomatis sesuai total penjualan
📊 Statistik real-time Tampilkan jumlah dessert terjual dan total pendapatan
📤 Share hasil permainan Bagikan pencapaian lewat aplikasi lain (WA, IG, dsb.)
🌗 Light & Dark Theme Mendukung tema gelap dan terang sesuai sistem
🧩 UI Material 3 Gunakan Material Design 3 untuk tampilan modern

🏗️ Arsitektur dan Struktur Kode

1. Model Data (Dessert.kt)

data class Dessert(
    val imageId: Int,
    val price: Int,
    val startProductionAmount: Int
)

Setiap Dessert menyimpan:

  • imageId: ID gambar

  • price: Harga per klik

  • startProductionAmount: Total penjualan minimum agar dessert ini muncul


2. Data Source (Datasource.kt)

Berisi daftar dessert secara berurutan berdasarkan startProductionAmount:

val dessertList = listOf(
    Dessert(R.drawable.cupcake, price = 5, startProductionAmount = 0),
    Dessert(R.drawable.donut, price = 50, startProductionAmount = 5),
    Dessert(R.drawable.eclair, price = 100, startProductionAmount = 10),
    ...
    Dessert(R.drawable.oreo, price = 6000, startProductionAmount = 20000)
)

3. Activity Lifecycle (MainActivity.kt)

MainActivity mencatat siklus hidup aplikasi menggunakan log:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    Log.d("DessertClicker", "onCreate")
    setContent { DessertClickerApp() }
}

Lifecycle seperti onStart, onResume, onPause, dan lainnya juga dicatat. Ini berguna untuk debugging dan pemahaman perilaku aplikasi saat berpindah state.


🎨 Komponen UI dengan Jetpack Compose

1. Manajemen State

var revenue by rememberSaveable { mutableStateOf(0) }
var dessertsSold by rememberSaveable { mutableStateOf(0) }
  • rememberSaveable menjaga data tetap aman saat rotasi layar (configuration change).

  • State ini menjadi sumber kebenaran (single source of truth) untuk tampilan.


2. Struktur UI Utama

DessertClickerApp()

Menjadi root composable yang menyatukan semua bagian UI:

@Composable
fun DessertClickerApp() {
    var revenue by rememberSaveable { mutableStateOf(0) }
    var dessertsSold by rememberSaveable { mutableStateOf(0) }

    val currentDessert = determineDessertToShow(dessertList, dessertsSold)

    DessertClickerScreen(
        revenue = revenue,
        dessertsSold = dessertsSold,
        dessertImageId = currentDessert.imageId,
        onDessertClicked = {
            revenue += currentDessert.price
            dessertsSold++
        }
    )
}

DessertClickerScreen()

Tampilan utama berisi:

  • 🧁 Gambar dessert (klik untuk bermain)

  • 📊 Statistik transaksi (penjualan & pendapatan)

  • 🎨 Layout background bakery

@Composable
fun DessertClickerScreen(...) {
    Column {
        AppBarWithShareButton(...)
        Box {
            Image(painterResource(R.drawable.bakery_background), ...)
            Image(painterResource(dessertImageId), Modifier.clickable { onDessertClicked() })
        }
        TransactionInfo(revenue, dessertsSold)
    }
}

TransactionInfo()

Menampilkan statistik secara visual dengan MaterialTheme.typography:

@Composable
fun TransactionInfo(revenue: Int, dessertsSold: Int) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text("Total Revenue: $$revenue", style = MaterialTheme.typography.headlineSmall)
        Text("Desserts Sold: $dessertsSold", style = MaterialTheme.typography.bodyLarge)
    }
}

🔁 Logika Permainan

Fungsi: determineDessertToShow()

fun determineDessertToShow(desserts: List<Dessert>, dessertsSold: Int): Dessert {
    var result = desserts.first()
    for (dessert in desserts) {
        if (dessertsSold >= dessert.startProductionAmount) {
            result = dessert
        } else break
    }
    return result
}
  • Loop dari awal hingga menemukan dessert yang belum bisa diakses

  • Dessert berubah secara otomatis ketika penjualan mencapai batas baru


🎨 Theming & Desain

Material Design 3

  • Warna adaptif dengan dukungan light & dark mode

  • Tipografi terstruktur: headlineSmall, bodyLarge, dll

  • Elevasi, padding, dan spacing konsisten

Responsive Design

  • Gunakan Modifier.padding(WindowInsets...) untuk mendukung layar dengan notch

  • ContentScale.Crop menjaga proporsi gambar tetap estetis di berbagai ukuran layar


🧠 Best Practices & Pembelajaran

Area Praktik
State Management Gunakan rememberSaveable untuk data penting
🎯 Separation of Concerns Pisahkan logika, UI, dan data
📦 Modular Components Komponen seperti DessertClickerScreen, TransactionInfo, dan AppBar dibuat terpisah
🐞 Logging Manfaatkan Log.d untuk memantau lifecycle
🧱 Scaffold & Layout Gunakan Scaffold untuk struktur aplikasi yang rapi
📲 Share Intent Handling Tangani kasus saat share tidak tersedia menggunakan Toast

 
 

Komentar

Postingan populer dari blog ini

ETS - PPB G

Pertemuan 5 - PPB G

Pertemuan 3 - PPB G