MIF_E31230979/Assets/Scripts/MenuBelajar/BelajarManager.cs

464 lines
15 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System.Collections;
using System.Collections.Generic;
public class BelajarManager : MonoBehaviour
{
// ... isi script kamu di bawahnya tetap biarkan saja
[Header("Data Utama")]
public List<DataSayur> listSayur;
[Header("Panel Switcher")]
public GameObject panelBaris;
public GameObject panelKolom;
public GameObject panelMateri;
[Header("Tombol Switcher UI (Image)")]
public Image imgBtnBaris;
public Image imgBtnKolom;
public Image imgBtnMateri;
[Header("Aset Gambar Tombol (Sprite)")]
public Sprite btnBarisColor, btnBarisBW;
public Sprite btnKolomColor, btnKolomBW;
public Sprite btnMateriColor, btnMateriBW;
[Header("Animasi Scale Tombol (Tab)")]
public float scaleAktif = 1.15f;
public float scaleMati = 1.0f;
public float speedAnimasi = 10f;
private Vector3 targetScaleBaris, targetScaleKolom, targetScaleMateri;
[Header("UI Scene Baris")]
public TextMeshProUGUI txtNama;
public Image imgSayur;
public TextMeshProUGUI txtInpo; // Slot untuk teks info kanan atas
public TextMeshProUGUI txtBubble; // Slot untuk teks catatan di dalam bubble
public Image imgBubbleMaskot; // Slot untuk UI Image kepala maskot
public GameObject panelBubbleParent; // Slot untuk objek parent 'Bubble' (biar bisa di-pop up)
private int indexSekarang = 0;
[Header("UI Scene Kolom (Galeri)")]
public KartuSayur[] slotKartu;
private int halamanSekarang = 0;
[Header("UI Scene Materi (Detail)")]
public TextMeshProUGUI txtNamaMateri;
public Image imgSayurMateri;
public TextMeshProUGUI txtRasaMateri;
public TextMeshProUGUI txtManfaatMateri;
private int indexMateri = 0;
[Header("Pengaturan Audio VO")]
public AudioSource sourceVO;
[Header("Pengaturan Efek Juiciness")]
public float floatingSpeed = 2f;
public float floatingAmount = 15f;
private Vector3 posisiAwalSayurBaris;
private Vector3 posisiAwalSayurMateri;
[Header("Pengaturan Auto Next")]
public Image imgBtnAuto;
public Sprite btnAutoOn, btnAutoOff;
public float jedaAuto = 3f;
private bool isAutoActive = false;
private Coroutine autoCoroutine;
[Header("Pengaturan Efek Shake")]
public float durasiShake = 0.2f;
public float kekuatanShake = 5f;
[Header("Pengaturan Ducking Musik")]
public AudioSource sourceBGM;
public float volumeNormal = 0.5f;
public float volumeDucking = 0.1f;
// --- BATAS VARIABEL ATAS ---
void Start() {
targetScaleBaris = targetScaleKolom = targetScaleMateri = Vector3.one * scaleMati;
// Simpan posisi awal untuk efek melayang
posisiAwalSayurBaris = imgSayur.transform.localPosition;
posisiAwalSayurMateri = imgSayurMateri.transform.localPosition;
BukaMenuBaris();
}
void Update() {
// Animasi Scale Tab Menu
imgBtnBaris.transform.localScale = Vector3.Lerp(imgBtnBaris.transform.localScale, targetScaleBaris, Time.deltaTime * speedAnimasi);
imgBtnKolom.transform.localScale = Vector3.Lerp(imgBtnKolom.transform.localScale, targetScaleKolom, Time.deltaTime * speedAnimasi);
imgBtnMateri.transform.localScale = Vector3.Lerp(imgBtnMateri.transform.localScale, targetScaleMateri, Time.deltaTime * speedAnimasi);
// --- EFEK MELAYANG (FLOATING) ---
float sinWave = Mathf.Sin(Time.time * floatingSpeed) * floatingAmount;
if(panelBaris.activeSelf)
imgSayur.transform.localPosition = posisiAwalSayurBaris + new Vector3(0, sinWave, 0);
if(panelMateri.activeSelf)
imgSayurMateri.transform.localPosition = posisiAwalSayurMateri + new Vector3(0, sinWave, 0);
}
// --- FUNGSI SWITCHER PANEL ---
public void BukaMenuBaris() {
panelBaris.SetActive(true);
panelKolom.SetActive(false);
panelMateri.SetActive(false);
imgBtnBaris.sprite = btnBarisColor;
imgBtnKolom.sprite = btnKolomBW;
imgBtnMateri.sprite = btnMateriBW;
imgBtnBaris.transform.SetAsLastSibling();
targetScaleBaris = Vector3.one * scaleAktif;
targetScaleKolom = Vector3.one * scaleMati;
targetScaleMateri = Vector3.one * scaleMati;
UpdateTampilan();
}
public void BukaMenuKolom() {
panelBaris.SetActive(false);
panelKolom.SetActive(true);
panelMateri.SetActive(false);
imgBtnBaris.sprite = btnBarisBW;
imgBtnKolom.sprite = btnKolomColor;
imgBtnMateri.sprite = btnMateriBW;
imgBtnKolom.transform.SetAsLastSibling();
targetScaleBaris = Vector3.one * scaleMati;
targetScaleKolom = Vector3.one * scaleAktif;
targetScaleMateri = Vector3.one * scaleMati;
UpdateTampilanKolom();
}
public void BukaMenuMateri() {
panelBaris.SetActive(false);
panelKolom.SetActive(false);
panelMateri.SetActive(true);
imgBtnBaris.sprite = btnBarisBW;
imgBtnKolom.sprite = btnKolomBW;
imgBtnMateri.sprite = btnMateriColor;
imgBtnMateri.transform.SetAsLastSibling();
targetScaleBaris = Vector3.one * scaleMati;
targetScaleKolom = Vector3.one * scaleMati;
targetScaleMateri = Vector3.one * scaleAktif;
}
// --- LOGIKA SCENE BARIS ---
public void TombolNext() {
indexSekarang = (indexSekarang + 1) % listSayur.Count;
UpdateTampilan();
}
public void TombolPrev() {
indexSekarang = (indexSekarang - 1 + listSayur.Count) % listSayur.Count;
UpdateTampilan();
}
void UpdateTampilan() {
if(listSayur.Count > 0) {
DataSayur sayurAktif = listSayur[indexSekarang];
// Setup data standar
txtNama.text = sayurAktif.namaSayur;
imgSayur.sprite = sayurAktif.gambarSayurVisual;
// --- AKTIFKAN & ISI DATA INFO ---
txtInpo.text = sayurAktif.infoStatusKonsumsi;
// --- LOGIKA PENGECEKAN BUBBLE CHAT ---
if (string.IsNullOrEmpty(sayurAktif.teksBubbleCatatan)) {
// Sembunyikan bubble secara utuh jika datanya dikosongkan
panelBubbleParent.SetActive(false);
} else {
panelBubbleParent.SetActive(true);
txtBubble.text = sayurAktif.teksBubbleCatatan;
// Ganti gambar ekspresi maskot jika disiapkan di asset
if(sayurAktif.spriteEkspresiMaskot != null) {
imgBubbleMaskot.sprite = sayurAktif.spriteEkspresiMaskot;
}
// Jalankan Efek Animasi Pop Up Khusus Bubble
StopCoroutine("EfekPopUpBubble");
StartCoroutine(EfekPopUpBubble());
}
// Putar VO suara
PutarSuara(sayurAktif);
// Animasi Pop Sayur Utama
StopCoroutine("EfekPopSayur");
StartCoroutine(EfekPopSayur(imgSayur));
}
}
// --- LOGIKA SCENE KOLOM (PAGING 5 KARTU) ---
public void TombolNextHalaman() {
// Hitung total halaman yang dibutuhkan
// Misal: 12 sayur / 5 = 2.4, dibulatkan ke atas jadi 3 halaman
int totalHalaman = Mathf.CeilToInt((float)listSayur.Count / 5);
halamanSekarang++;
// JIKA sudah melewati halaman terakhir, BALIK ke halaman pertama (0)
if (halamanSekarang >= totalHalaman) {
halamanSekarang = 0;
}
UpdateTampilanKolom();
}
public void TombolPrevHalaman() {
int totalHalaman = Mathf.CeilToInt((float)listSayur.Count / 5);
halamanSekarang--;
// JIKA sudah mundur sebelum halaman pertama, LOMPAT ke halaman terakhir
if (halamanSekarang < 0) {
halamanSekarang = totalHalaman - 1;
}
UpdateTampilanKolom();
}
void UpdateTampilanKolom() {
int indexMulai = halamanSekarang * 5;
for (int i = 0; i < slotKartu.Length; i++) {
int indexSayurData = indexMulai + i;
if (indexSayurData < listSayur.Count) {
// Jika data ada, aktifkan kartu dan isi datanya
slotKartu[i].gameObject.SetActive(true);
slotKartu[i].Setup(listSayur[indexSayurData]);
} else {
// Jika data habis di halaman tersebut, sembunyikan kartu sisanya
slotKartu[i].gameObject.SetActive(false);
}
}
}
public void AmbilDataDariKartu(DataSayur dataDiterima) {
indexMateri = listSayur.IndexOf(dataDiterima);
// Buka panelnya dulu
BukaMenuMateri();
// Kasih jeda dikit biar panelnya bener-bener "bangun" sebelum keluar suara
StartCoroutine(DelaySuaraMateri());
}
IEnumerator DelaySuaraMateri() {
yield return new WaitForSeconds(0.05f); // Jeda sangat singkat
UpdateTampilanMateri();
}
void UpdateTampilanMateri() {
if (listSayur.Count > 0) {
DataSayur s = listSayur[indexMateri];
txtNamaMateri.text = s.namaSayur;
imgSayurMateri.sprite = s.gambarSayurVisual;
txtRasaMateri.text = s.rasaSayur;
txtManfaatMateri.text = s.manfaatSayur;
// Pastikan ini ada di sini!
PutarSuara(s);
StopCoroutine("EfekPopSayur");
StartCoroutine(EfekPopSayur(imgSayurMateri));
}
}
public void NextMateri() {
indexMateri = (indexMateri + 1) % listSayur.Count;
UpdateTampilanMateri();
}
public void PrevMateri() {
indexMateri = (indexMateri - 1 + listSayur.Count) % listSayur.Count;
UpdateTampilanMateri();
}
// --- COROUTINE ANIMASI POP ---
IEnumerator EfekPopSayur(Image targetImage) {
targetImage.transform.localScale = Vector3.zero;
float timer = 0;
float durasi = 0.3f;
while (timer < durasi) {
timer += Time.deltaTime;
float progress = timer / durasi;
// Rumus bounce sederhana
float curve = Mathf.Sin(progress * Mathf.PI * 0.8f) * 1.15f;
targetImage.transform.localScale = new Vector3(curve, curve, curve);
yield return null;
}
targetImage.transform.localScale = Vector3.one;
}
public void KlikTombolAuto() {
isAutoActive = !isAutoActive; // Switch ON/OFF
if (isAutoActive) {
imgBtnAuto.sprite = btnAutoOn;
// Mulai hitung mundur otomatis
autoCoroutine = StartCoroutine(ProsesAutoNext());
} else {
imgBtnAuto.sprite = btnAutoOff;
// Hentikan hitung mundur
if (autoCoroutine != null) StopCoroutine(autoCoroutine);
}
}
IEnumerator ProsesAutoNext() {
while (isAutoActive) {
yield return new WaitForSeconds(jedaAuto);
// Cek panel mana yang lagi aktif, lalu panggil fungsi Next-nya
if (panelBaris.activeSelf) {
TombolNext();
}
else if (panelKolom.activeSelf) {
TombolNextHalaman();
}
else if (panelMateri.activeSelf) {
NextMateri();
}
}
}
void PutarSuara(DataSayur data) {
// 1. Cek apakah datanya ada dan punya suara
if (data == null || data.suaraNamaSayur == null) return;
// 2. Hentikan suara lama dan mainkan yang baru
sourceVO.Stop();
sourceVO.clip = data.suaraNamaSayur;
sourceVO.Play();
// 3. Efek Ducking Musik (BGM mengecil)
// Kita pastikan sourceBGM tidak kosong sebelum dijalankan
if (sourceBGM != null) {
StopCoroutine("ProsesDucking");
StartCoroutine(ProsesDucking(volumeDucking));
// 4. Kita buat coroutine baru untuk mengembalikan volume musik
// setelah suara selesai (lebih akurat dari Invoke)
StopCoroutine("TungguSuaraSelesai");
StartCoroutine(TungguSuaraSelesai(sourceVO.clip.length));
}
}
// --- FUNGSI FEEDBACK & SHAKE ---
public void KlikGambarSayur() {
if (panelBaris.activeSelf) {
PutarSuara(listSayur[indexSekarang]);
PlayShake(imgSayur.GetComponent<RectTransform>());
}
else if (panelMateri.activeSelf) {
PutarSuara(listSayur[indexMateri]);
PlayShake(imgSayurMateri.GetComponent<RectTransform>());
}
}
public void PlayShake(RectTransform target) {
StopCoroutine("ProsesShake");
StartCoroutine(ProsesShake(target));
}
IEnumerator ProsesShake(RectTransform target) {
Vector3 posisiAsli = target.localPosition;
float timer = 0f;
while (timer < durasiShake) {
timer += Time.deltaTime;
float x = Random.Range(-1f, 1f) * kekuatanShake;
target.localPosition = new Vector3(posisiAsli.x + x, posisiAsli.y, posisiAsli.z);
yield return null;
}
target.localPosition = posisiAsli;
}
// --- FUNGSI AUDIO PENDUKUNG ---
IEnumerator ProsesDucking(float targetVolume) {
if (sourceBGM == null) yield break;
while (Mathf.Abs(sourceBGM.volume - targetVolume) > 0.01f) {
sourceBGM.volume = Mathf.MoveTowards(sourceBGM.volume, targetVolume, Time.deltaTime * 2f);
yield return null;
}
sourceBGM.volume = targetVolume;
}
void ResetMusik() {
if (gameObject.activeInHierarchy) {
StopCoroutine("ProsesDucking");
StartCoroutine(ProsesDucking(volumeNormal));
}
}
// Cukup tulis satu kali saja di sini
IEnumerator TungguSuaraSelesai(float durasi) {
yield return new WaitForSeconds(durasi);
ResetMusik();
}
IEnumerator EfekKedipCatatan() {
if (txtBubble == null) yield break; // <-- Ganti jadi txtBubble
while (panelBaris.activeSelf && txtBubble.gameObject.activeSelf) { // <-- Ganti jadi txtBubble
float timer = 0;
while (timer < 0.5f) {
timer += Time.deltaTime;
txtBubble.alpha = Mathf.Lerp(1f, 0.2f, timer / 0.5f); // <-- Ganti jadi txtBubble
yield return null;
}
timer = 0;
while (timer < 0.5f) {
timer += Time.deltaTime;
txtBubble.alpha = Mathf.Lerp(0.2f, 1f, timer / 0.5f); // <-- Ganti jadi txtBubble
yield return null;
}
yield return new WaitForSeconds(0.3f);
}
}
// --- COROUTINE ANIMASI POP UP BUBBLE CHAT ---
IEnumerator EfekPopUpBubble() {
// Set ukuran awal bubble jadi nol (tidak terlihat)
panelBubbleParent.transform.localScale = Vector3.zero;
float timer = 0;
float durasi = 0.35f;
while (timer < durasi) {
timer += Time.deltaTime;
float progress = timer / durasi;
// Menggunakan rumus matematika Sinus untuk efek bounce (membal) yang kenyal
float bounceCurve = Mathf.Sin(progress * Mathf.PI * 0.85f) * 1.1f;
panelBubbleParent.transform.localScale = new Vector3(bounceCurve, bounceCurve, bounceCurve);
yield return null;
}
// Kunci ukuran akhir ke normal (1,1,1)
panelBubbleParent.transform.localScale = Vector3.one;
}
}