using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using TMPro; using UnityEngine.SceneManagement; using Firebase; using Firebase.Database; using Firebase.Extensions; [System.Serializable] public class SoalData { public int id; public string tipe; public string pertanyaan; public string gambar; public string audio_pertanyaan; public string audio_jawaban; public string[] pilihan; public string[] pilihan_gambar; public string jawaban; } [System.Serializable] public class SoalWrapper { public string kategori; public SoalData[] soal; } public class KuisManager : MonoBehaviour { [Header("Panel")] public GameObject panelSoal; public GameObject panelHasil; [Header("Loading")] public GameObject panelLoading; public TextMeshProUGUI textLoading; [Header("Elemen Soal")] public TextMeshProUGUI textSoal; public Image imageSoal; public Button btnA, btnB, btnC; public TextMeshProUGUI textA, textB, textC; public GameObject frameSoal; public GameObject frameSoalGambar; public TextMeshProUGUI textSoalGambar; [Header("Skor")] public TextMeshProUGUI textSkor; [Header("Panel Hasil")] public TextMeshProUGUI textPesan; public TextMeshProUGUI textSkorAkhir; public Button btnUlang, btnMenu, btnNextLevel; public Image imgStikerHasil; public Sprite stikerHasilBagus; public Sprite stikerHasilKurang; [Header("Popup Benar/Salah")] public GameObject panelPopup; public Image imgStiker; public Sprite stikerBenar; public Sprite stikerSalah; [Header("Jawaban Gambar")] public GameObject panelJawabanGambar; public Button btnGambarA, btnGambarB, btnGambarC; [Header("Navigasi")] public Button btnHome; // --- private --- private List daftarSoal = new List(); private int indexSoal = 0; private int skor = 0; private int totalSoal = 5; private string jawabanBenar; private AudioSource audioSource; private AudioClip clipPertanyaan; private string kategoriAktif; private DatabaseReference dbRef; private List listHewan = new List { "anjing","ayam","babi","bebek","buaya","burung", "gajah","harimau","ikan","jerapah","kambing","katak","kelinci", "kepiting","kucing","kupu-kupu","kura","landak","lebah","rubah", "rusa","sapi","singa","ular","ulat","zebra" }; private List listAssetWarna = new List { "bintang_merah","bintang_biru","bintang_hijau","bintang_kuning", "bintang_orange","bintang_ungu","bintang_pink","bintang_coklat","bintang_hitam", "krayon_merah","krayon_biru","krayon_hijau","krayon_kuning", "krayon_orange","krayon_ungu","krayon_pink","krayon_coklat", "lingkaran_merah","lingkaran_biru","lingkaran_hijau","lingkaran_kuning", "lingkaran_orange","lingkaran_ungu","lingkaran_pink","lingkaran_coklat", "persegi_merah","persegi_biru","persegi_hijau","persegi_kuning", "persegi_orange","persegi_ungu","persegi_pink","persegi_coklat", "segitiga_merah","segitiga_biru","segitiga_hijau","segitiga_kuning", "segitiga_orange","segitiga_ungu","segitiga_pink","segitiga_coklat", "tomat","matahari","rumput","payung_biru","payung_merah", "pita","terong","balon","kursi","pelampung" }; void Start() { audioSource = GetComponent(); if (audioSource == null) audioSource = gameObject.AddComponent(); string rawKategori = PlayerPrefs.GetString("kategori", "Hewan"); kategoriAktif = rawKategori.ToLower(); if (btnHome != null) { btnHome.onClick.RemoveAllListeners(); btnHome.onClick.AddListener(KembaliKeMenu); } panelHasil.SetActive(false); panelSoal.SetActive(false); panelPopup.SetActive(false); panelJawabanGambar.SetActive(false); frameSoalGambar.SetActive(false); // Tampilkan loading dulu if (panelLoading != null) panelLoading.SetActive(true); if (textLoading != null) textLoading.text = "Memuat soal..."; // Inisialisasi Firebase lalu muat soal FirebaseApp.CheckAndFixDependenciesAsync().ContinueWithOnMainThread(task => { if (task.Result == DependencyStatus.Available) { dbRef = FirebaseDatabase.DefaultInstance.RootReference; Debug.Log("✅ Firebase siap!"); MuatSoalDariFirebase(); } else { Debug.LogError("❌ Firebase gagal: " + task.Result); if (textLoading != null) textLoading.text = "Gagal konek ke server.\nCek koneksi internet!"; } }); } void MuatSoalDariFirebase() { int level = PlayerPrefs.GetInt("level", 1); string kunci = kategoriAktif + "_level" + level; // contoh: "hewan_level1" Debug.Log("📡 Mengambil soal dari Firebase: soal/" + kunci); dbRef.Child("soal").Child(kunci).GetValueAsync().ContinueWithOnMainThread(task => { if (task.IsFaulted || task.IsCanceled) { Debug.LogError("❌ Gagal ambil data dari Firebase: " + task.Exception); if (textLoading != null) textLoading.text = "Gagal memuat soal.\nCek koneksi internet!"; return; } DataSnapshot snapshot = task.Result; if (!snapshot.Exists) { Debug.LogError("❌ Data tidak ditemukan di Firebase: soal/" + kunci); if (textLoading != null) textLoading.text = "Data soal tidak ditemukan!"; return; } // Parse data dari Firebase ke List List semua = new List(); foreach (DataSnapshot soalSnap in snapshot.Children) { Debug.Log("proses ambil data soal dari firebase"); SoalData s = new SoalData(); s.id = soalSnap.Child("id").Value != null ? int.Parse(soalSnap.Child("id").Value.ToString()) : 0; s.tipe = soalSnap.Child("tipe").Value?.ToString() ?? "pilihan_ganda"; s.pertanyaan = soalSnap.Child("pertanyaan").Value?.ToString() ?? ""; s.gambar = soalSnap.Child("gambar").Value?.ToString() ?? ""; s.audio_pertanyaan = soalSnap.Child("audio_pertanyaan").Value?.ToString() ?? ""; s.audio_jawaban = soalSnap.Child("audio_jawaban").Value?.ToString() ?? ""; s.jawaban = soalSnap.Child("jawaban").Value?.ToString() ?? ""; Debug.Log("pertanyaan : "+s.pertanyaan.ToString()); // Ambil pilihan dari pilihan_0, pilihan_1, pilihan_2 s.pilihan = new string[] { soalSnap.Child("pilihan_0").Value?.ToString() ?? "", soalSnap.Child("pilihan_1").Value?.ToString() ?? "", soalSnap.Child("pilihan_2").Value?.ToString() ?? "" }; // pilihan_gambar kosong (tidak dipakai di struktur Firebase saat ini) //s.pilihan_gambar = new string[0]; if (soalSnap.Child("pilihan_gambar_0").Exists) { s.pilihan_gambar = new string[] { soalSnap.Child("pilihan_gambar_0").Value?.ToString() ?? "", soalSnap.Child("pilihan_gambar_1").Value?.ToString() ?? "", soalSnap.Child("pilihan_gambar_2").Value?.ToString() ?? "" }; } else { s.pilihan_gambar = new string[0]; } // Filter tipe suara_hewan if (s.tipe != "suara_hewan") semua.Add(s); } // Shuffle for (int i = semua.Count - 1; i > 0; i--) { int r = Random.Range(0, i + 1); SoalData tmp = semua[i]; semua[i] = semua[r]; semua[r] = tmp; } daftarSoal.Clear(); indexSoal = 0; skor = 0; totalSoal = Mathf.Min(5, semua.Count); for (int i = 0; i < totalSoal; i++) daftarSoal.Add(semua[i]); Debug.Log("✅ Soal berhasil dimuat: " + totalSoal + " soal dari Firebase"); // Sembunyikan loading, tampilkan soal if (panelLoading != null) panelLoading.SetActive(false); panelSoal.SetActive(true); TampilkanSoal(); }); } string DeteksiFolderGambar(string namaFile) { if (listAssetWarna.Contains(namaFile)) return "warna"; else if (listHewan.Contains(namaFile)) return "hewan"; else return "buah"; } void TampilkanSoal() { if (indexSoal >= totalSoal) { TampilkanHasil(); return; } StartCoroutine(TampilkanSoalCoroutine()); } IEnumerator TampilkanSoalCoroutine() { SoalData s = daftarSoal[indexSoal]; jawabanBenar = s.jawaban; bool adaPilihanGambar = s.tipe == "pilihan_gambar"; bool adaGambar = (s.tipe == "pilihan_ganda" || s.tipe == "drag_drop") && !string.IsNullOrEmpty(s.gambar); // STEP 1: Sembunyikan semua btnA.gameObject.SetActive(false); btnB.gameObject.SetActive(false); btnC.gameObject.SetActive(false); panelJawabanGambar.SetActive(false); imageSoal.gameObject.SetActive(false); frameSoal.SetActive(false); frameSoalGambar.SetActive(false); yield return null; // STEP 2: Set teks soal textSoal.text = s.pertanyaan; textSoalGambar.text = s.pertanyaan; // STEP 3: Aktifkan frame frameSoal.SetActive(!adaPilihanGambar); frameSoalGambar.SetActive(adaPilihanGambar); // STEP 4: Aktifkan panel jawaban if (adaPilihanGambar) { panelJawabanGambar.SetActive(true); } else { btnA.gameObject.SetActive(true); btnB.gameObject.SetActive(true); btnC.gameObject.SetActive(true); } yield return null; // STEP 5: Load gambar soal if (adaGambar) { string folderGambarSoal = kategoriAktif == "warna" ? DeteksiFolderGambar(s.gambar) : kategoriAktif; Sprite sp = Resources.Load("Gambar/" + folderGambarSoal + "/" + s.gambar); if (sp != null) { imageSoal.sprite = sp; imageSoal.gameObject.SetActive(true); } else Debug.LogWarning("⚠️ Gambar tidak ditemukan: Gambar/" + folderGambarSoal + "/" + s.gambar); } // STEP 6: Setup tombol jawaban gambar if (adaPilihanGambar && s.pilihan_gambar != null && s.pilihan_gambar.Length >= 3) { Button[] btns = { btnGambarA, btnGambarB, btnGambarC }; for (int i = 0; i < 3; i++) { Image img = btns[i].GetComponent(); string namaSprite = s.pilihan_gambar[i]; string folderSprite = kategoriAktif == "warna" ? DeteksiFolderGambar(namaSprite) : kategoriAktif; Sprite sp = Resources.Load("Gambar/" + folderSprite + "/" + namaSprite); if (sp != null) img.sprite = sp; string jwb = s.pilihan[i]; btns[i].onClick.RemoveAllListeners(); btns[i].onClick.AddListener(() => CekJawaban(jwb)); btns[i].interactable = true; } } // STEP 7: Isi teks & listener tombol pilihan ganda if (!adaPilihanGambar) { textA.text = s.pilihan != null && s.pilihan.Length > 0 ? s.pilihan[0] : "-"; textB.text = s.pilihan != null && s.pilihan.Length > 1 ? s.pilihan[1] : "-"; textC.text = s.pilihan != null && s.pilihan.Length > 2 ? s.pilihan[2] : "-"; btnA.onClick.RemoveAllListeners(); btnB.onClick.RemoveAllListeners(); btnC.onClick.RemoveAllListeners(); btnA.onClick.AddListener(() => CekJawaban(textA.text)); btnB.onClick.AddListener(() => CekJawaban(textB.text)); btnC.onClick.AddListener(() => CekJawaban(textC.text)); btnA.interactable = true; btnB.interactable = true; btnC.interactable = true; // STEP 8: Force rebuild layout yield return null; Canvas.ForceUpdateCanvases(); RectTransform parentLayout = btnA.transform.parent.GetComponent(); if (parentLayout != null) LayoutRebuilder.ForceRebuildLayoutImmediate(parentLayout); if (parentLayout != null && parentLayout.parent != null) { RectTransform grandParent = parentLayout.parent.GetComponent(); if (grandParent != null) LayoutRebuilder.ForceRebuildLayoutImmediate(grandParent); } } // STEP 9: Audio pertanyaan clipPertanyaan = null; if (!string.IsNullOrEmpty(s.audio_pertanyaan)) { clipPertanyaan = Resources.Load("Audio/" + s.audio_pertanyaan); if (clipPertanyaan != null) StartCoroutine(AutoPlayPertanyaan()); } textSkor.text = "Skor: " + skor; Debug.Log("📝 Soal " + (indexSoal + 1) + " | Tipe: " + s.tipe + " | Jawaban: " + s.jawaban); } IEnumerator AutoPlayPertanyaan() { yield return new WaitForSeconds(0.5f); if (clipPertanyaan != null) { audioSource.Stop(); audioSource.clip = clipPertanyaan; audioSource.Play(); } } void CekJawaban(string jawaban) { btnA.interactable = false; btnB.interactable = false; btnC.interactable = false; btnGambarA.interactable = false; btnGambarB.interactable = false; btnGambarC.interactable = false; audioSource.Stop(); StopCoroutine("AutoPlayPertanyaan"); bool benar = (jawaban == jawabanBenar); if (benar) { skor += 10; textSkor.text = "Skor: " + skor; Debug.Log("✅ Benar! Skor: " + skor); StartCoroutine(BenarDenganAudio()); } else { Debug.Log("❌ Salah! Jawaban benar: " + jawabanBenar); StartCoroutine(PopupOtomatis(false)); } } IEnumerator BenarDenganAudio() { SoalData s = daftarSoal[indexSoal]; if (!string.IsNullOrEmpty(s.audio_jawaban)) { AudioClip clipJawaban = Resources.Load("Audio/" + s.audio_jawaban); if (clipJawaban != null) { audioSource.PlayOneShot(clipJawaban); yield return new WaitForSeconds(clipJawaban.length + 0.3f); } else yield return new WaitForSeconds(0.8f); } else yield return new WaitForSeconds(0.5f); StartCoroutine(PopupOtomatis(true)); } IEnumerator PopupOtomatis(bool benar) { panelPopup.SetActive(true); imgStiker.sprite = benar ? stikerBenar : stikerSalah; string namaAudio = benar ? "suara_benar" : "suara_salah"; AudioClip clip = Resources.Load("Audio/" + namaAudio); if (clip != null) audioSource.PlayOneShot(clip); yield return new WaitForSeconds(1.5f); panelPopup.SetActive(false); btnA.gameObject.SetActive(false); btnB.gameObject.SetActive(false); btnC.gameObject.SetActive(false); btnA.interactable = true; btnB.interactable = true; btnC.interactable = true; btnGambarA.interactable = true; btnGambarB.interactable = true; btnGambarC.interactable = true; panelJawabanGambar.SetActive(false); yield return null; indexSoal++; TampilkanSoal(); } void TampilkanHasil() { panelSoal.SetActive(false); panelHasil.SetActive(true); int skorMax = totalSoal * 10; textSkorAkhir.text = "Skor Akhir : " + skor + " / " + skorMax; bool skorBagus = skor >= 30; if (textPesan != null) textPesan.text = skorBagus ? "Hebat! Kamu Luar Biasa!" : "Jangan Menyerah! Coba Lagi!"; if (imgStikerHasil != null) { Sprite stikerDipilih = skorBagus ? stikerHasilBagus : stikerHasilKurang; if (stikerDipilih != null) imgStikerHasil.sprite = stikerDipilih; } int level = PlayerPrefs.GetInt("level", 1); btnNextLevel.gameObject.SetActive(level < 3); btnUlang.onClick.RemoveAllListeners(); btnMenu.onClick.RemoveAllListeners(); btnNextLevel.onClick.RemoveAllListeners(); btnUlang.onClick.AddListener(() => SceneManager.LoadScene("Kuis")); btnMenu.onClick.AddListener(() => SceneManager.LoadScene("MainMenu")); btnNextLevel.onClick.AddListener(() => { PlayerPrefs.SetInt("level", level + 1); SceneManager.LoadScene("Kuis"); }); } public void KembaliKeMenu() { SceneManager.LoadScene("MainMenu"); } }