426 lines
11 KiB
C#
426 lines
11 KiB
C#
using System.Collections;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
|
|
public class MenuCeritaDuaDialogController : MonoBehaviour
|
|
{
|
|
[Header("Dialog Atas")]
|
|
public Image imageAvatarAtas;
|
|
public TMP_Text textNamaAtas;
|
|
public TMP_Text textDialogAtas;
|
|
public CanvasGroup canvasDialogAtas;
|
|
public RectTransform rectDialogAtas;
|
|
|
|
[Header("Dialog Bawah")]
|
|
public Image imageAvatarBawah;
|
|
public TMP_Text textNamaBawah;
|
|
public TMP_Text textDialogBawah;
|
|
public CanvasGroup canvasDialogBawah;
|
|
public RectTransform rectDialogBawah;
|
|
|
|
[Header("Tombol")]
|
|
public Button buttonSebelumnya;
|
|
public Button buttonSelanjutnya;
|
|
|
|
public CanvasGroup canvasButtonSebelumnya;
|
|
public CanvasGroup canvasButtonSelanjutnya;
|
|
|
|
public RectTransform rectButtonSebelumnya;
|
|
public RectTransform rectButtonSelanjutnya;
|
|
|
|
[Header("Pengaturan Animasi")]
|
|
public float kecepatanKetik = 0.03f;
|
|
public float durasiMuncul = 0.2f;
|
|
public float alphaTombolAktif = 1f;
|
|
public float alphaTombolNonaktif = 0.45f;
|
|
|
|
[Header("Data Cerita")]
|
|
public DialogCerita[] daftarCerita;
|
|
|
|
private int indexCerita = 0;
|
|
|
|
// false = sedang berada di dialog atas
|
|
// true = sedang berada di dialog bawah
|
|
private bool sedangDialogBawah = false;
|
|
|
|
private bool sedangAnimasi = false;
|
|
private bool skipAnimasi = false;
|
|
|
|
private Coroutine coroutineAktif;
|
|
|
|
private Vector3 scaleNormal = Vector3.one;
|
|
private Vector3 scaleKecil = new Vector3(0.85f, 0.85f, 0.85f);
|
|
private Vector3 scaleTombolTekan = new Vector3(0.92f, 0.92f, 0.92f);
|
|
|
|
private void Start()
|
|
{
|
|
TampilkanCeritaBaru();
|
|
}
|
|
|
|
public void Selanjutnya()
|
|
{
|
|
if (!BisaSelanjutnya())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (rectButtonSelanjutnya != null)
|
|
{
|
|
StartCoroutine(AnimasiKlikTombol(rectButtonSelanjutnya));
|
|
}
|
|
|
|
// Jika animasi sedang berjalan, klik hanya untuk skip animasi
|
|
if (sedangAnimasi)
|
|
{
|
|
SkipAnimasiDialog();
|
|
return;
|
|
}
|
|
|
|
if (!sedangDialogBawah)
|
|
{
|
|
// Dari dialog atas lanjut ke dialog bawah
|
|
sedangDialogBawah = true;
|
|
JalankanCoroutine(TampilkanDialogBawah());
|
|
}
|
|
else
|
|
{
|
|
// Dari dialog bawah lanjut ke cerita berikutnya
|
|
if (indexCerita < daftarCerita.Length - 1)
|
|
{
|
|
indexCerita++;
|
|
sedangDialogBawah = false;
|
|
TampilkanCeritaBaru();
|
|
}
|
|
}
|
|
|
|
UpdateTombol();
|
|
}
|
|
|
|
public void Sebelumnya()
|
|
{
|
|
if (!BisaSebelumnya())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (rectButtonSebelumnya != null)
|
|
{
|
|
StartCoroutine(AnimasiKlikTombol(rectButtonSebelumnya));
|
|
}
|
|
|
|
// Jika animasi sedang berjalan dan tombol sebelumnya memang aktif,
|
|
// klik hanya untuk skip animasi
|
|
if (sedangAnimasi)
|
|
{
|
|
SkipAnimasiDialog();
|
|
return;
|
|
}
|
|
|
|
if (sedangDialogBawah)
|
|
{
|
|
// Dari dialog bawah kembali ke dialog atas
|
|
sedangDialogBawah = false;
|
|
SembunyikanDialogBawah();
|
|
}
|
|
else
|
|
{
|
|
// Dari dialog atas kembali ke cerita sebelumnya
|
|
if (indexCerita > 0)
|
|
{
|
|
indexCerita--;
|
|
sedangDialogBawah = true;
|
|
TampilkanCeritaSebelumnyaLengkap();
|
|
}
|
|
}
|
|
|
|
UpdateTombol();
|
|
}
|
|
|
|
public void KembaliKeMenuBelajar()
|
|
{
|
|
SceneManager.LoadScene("Menu Belajar");
|
|
}
|
|
|
|
private void TampilkanCeritaBaru()
|
|
{
|
|
if (daftarCerita == null || daftarCerita.Length == 0)
|
|
{
|
|
Debug.LogWarning("Data cerita belum diisi.");
|
|
return;
|
|
}
|
|
|
|
JalankanCoroutine(TampilkanDialogAtas());
|
|
UpdateTombol();
|
|
}
|
|
|
|
private IEnumerator TampilkanDialogAtas()
|
|
{
|
|
sedangAnimasi = true;
|
|
skipAnimasi = false;
|
|
UpdateTombol();
|
|
|
|
DialogCerita data = daftarCerita[indexCerita];
|
|
|
|
textNamaAtas.text = data.namaKarakterAtas;
|
|
textDialogAtas.text = "";
|
|
|
|
if (data.avatarAtas != null)
|
|
{
|
|
imageAvatarAtas.sprite = data.avatarAtas;
|
|
}
|
|
|
|
// Saat mulai cerita baru, dialog bawah disembunyikan dulu
|
|
canvasDialogBawah.alpha = 0;
|
|
textNamaBawah.text = "";
|
|
textDialogBawah.text = "";
|
|
|
|
canvasDialogAtas.alpha = 0;
|
|
rectDialogAtas.localScale = scaleKecil;
|
|
|
|
yield return StartCoroutine(FadeDanScale(canvasDialogAtas, rectDialogAtas, durasiMuncul));
|
|
yield return StartCoroutine(KetikTeks(textDialogAtas, data.dialogAtas));
|
|
|
|
textDialogAtas.text = data.dialogAtas;
|
|
canvasDialogAtas.alpha = 1;
|
|
rectDialogAtas.localScale = scaleNormal;
|
|
|
|
sedangAnimasi = false;
|
|
skipAnimasi = false;
|
|
UpdateTombol();
|
|
}
|
|
|
|
private IEnumerator TampilkanDialogBawah()
|
|
{
|
|
sedangAnimasi = true;
|
|
skipAnimasi = false;
|
|
UpdateTombol();
|
|
|
|
DialogCerita data = daftarCerita[indexCerita];
|
|
|
|
textNamaBawah.text = data.namaKarakterBawah;
|
|
textDialogBawah.text = "";
|
|
|
|
if (data.avatarBawah != null)
|
|
{
|
|
imageAvatarBawah.sprite = data.avatarBawah;
|
|
}
|
|
|
|
canvasDialogBawah.alpha = 0;
|
|
rectDialogBawah.localScale = scaleKecil;
|
|
|
|
yield return StartCoroutine(FadeDanScale(canvasDialogBawah, rectDialogBawah, durasiMuncul));
|
|
yield return StartCoroutine(KetikTeks(textDialogBawah, data.dialogBawah));
|
|
|
|
textDialogBawah.text = data.dialogBawah;
|
|
canvasDialogBawah.alpha = 1;
|
|
rectDialogBawah.localScale = scaleNormal;
|
|
|
|
sedangAnimasi = false;
|
|
skipAnimasi = false;
|
|
UpdateTombol();
|
|
}
|
|
|
|
private void SkipAnimasiDialog()
|
|
{
|
|
skipAnimasi = true;
|
|
|
|
DialogCerita data = daftarCerita[indexCerita];
|
|
|
|
if (!sedangDialogBawah)
|
|
{
|
|
textDialogAtas.text = data.dialogAtas;
|
|
canvasDialogAtas.alpha = 1;
|
|
rectDialogAtas.localScale = scaleNormal;
|
|
}
|
|
else
|
|
{
|
|
textDialogBawah.text = data.dialogBawah;
|
|
canvasDialogBawah.alpha = 1;
|
|
rectDialogBawah.localScale = scaleNormal;
|
|
}
|
|
}
|
|
|
|
private void TampilkanCeritaSebelumnyaLengkap()
|
|
{
|
|
if (daftarCerita == null || daftarCerita.Length == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
HentikanCoroutineAktif();
|
|
|
|
DialogCerita data = daftarCerita[indexCerita];
|
|
|
|
textNamaAtas.text = data.namaKarakterAtas;
|
|
textDialogAtas.text = data.dialogAtas;
|
|
|
|
if (data.avatarAtas != null)
|
|
{
|
|
imageAvatarAtas.sprite = data.avatarAtas;
|
|
}
|
|
|
|
canvasDialogAtas.alpha = 1;
|
|
rectDialogAtas.localScale = scaleNormal;
|
|
|
|
textNamaBawah.text = data.namaKarakterBawah;
|
|
textDialogBawah.text = data.dialogBawah;
|
|
|
|
if (data.avatarBawah != null)
|
|
{
|
|
imageAvatarBawah.sprite = data.avatarBawah;
|
|
}
|
|
|
|
canvasDialogBawah.alpha = 1;
|
|
rectDialogBawah.localScale = scaleNormal;
|
|
|
|
sedangAnimasi = false;
|
|
skipAnimasi = false;
|
|
UpdateTombol();
|
|
}
|
|
|
|
private void SembunyikanDialogBawah()
|
|
{
|
|
canvasDialogBawah.alpha = 0;
|
|
textNamaBawah.text = "";
|
|
textDialogBawah.text = "";
|
|
|
|
UpdateTombol();
|
|
}
|
|
|
|
private IEnumerator FadeDanScale(CanvasGroup canvasGroup, RectTransform rectTransform, float durasi)
|
|
{
|
|
float waktu = 0f;
|
|
|
|
while (waktu < durasi)
|
|
{
|
|
if (skipAnimasi)
|
|
{
|
|
canvasGroup.alpha = 1;
|
|
rectTransform.localScale = scaleNormal;
|
|
yield break;
|
|
}
|
|
|
|
waktu += Time.deltaTime;
|
|
float t = waktu / durasi;
|
|
|
|
canvasGroup.alpha = Mathf.Lerp(0, 1, t);
|
|
rectTransform.localScale = Vector3.Lerp(scaleKecil, scaleNormal, t);
|
|
|
|
yield return null;
|
|
}
|
|
|
|
canvasGroup.alpha = 1;
|
|
rectTransform.localScale = scaleNormal;
|
|
}
|
|
|
|
private IEnumerator KetikTeks(TMP_Text targetText, string isiTeks)
|
|
{
|
|
targetText.text = "";
|
|
|
|
foreach (char huruf in isiTeks)
|
|
{
|
|
if (skipAnimasi)
|
|
{
|
|
targetText.text = isiTeks;
|
|
yield break;
|
|
}
|
|
|
|
targetText.text += huruf;
|
|
yield return new WaitForSeconds(kecepatanKetik);
|
|
}
|
|
|
|
targetText.text = isiTeks;
|
|
}
|
|
|
|
private IEnumerator AnimasiKlikTombol(RectTransform rectTombol)
|
|
{
|
|
rectTombol.localScale = scaleTombolTekan;
|
|
yield return new WaitForSeconds(0.08f);
|
|
rectTombol.localScale = scaleNormal;
|
|
}
|
|
|
|
private void JalankanCoroutine(IEnumerator coroutine)
|
|
{
|
|
HentikanCoroutineAktif();
|
|
coroutineAktif = StartCoroutine(coroutine);
|
|
}
|
|
|
|
private void HentikanCoroutineAktif()
|
|
{
|
|
if (coroutineAktif != null)
|
|
{
|
|
StopCoroutine(coroutineAktif);
|
|
coroutineAktif = null;
|
|
}
|
|
}
|
|
|
|
private bool BisaSebelumnya()
|
|
{
|
|
// Tombol sebelumnya aktif hanya jika:
|
|
// 1. Sudah bukan cerita pertama, atau
|
|
// 2. Sedang berada di dialog bawah.
|
|
// Di awal cerita dan dialog atas sedang animasi, tombol tetap nonaktif.
|
|
return indexCerita > 0 || sedangDialogBawah;
|
|
}
|
|
|
|
private bool BisaSelanjutnya()
|
|
{
|
|
// Tombol selanjutnya aktif jika:
|
|
// 1. Belum cerita terakhir, atau
|
|
// 2. Masih berada di dialog atas, atau
|
|
// 3. Sedang animasi untuk skip.
|
|
return indexCerita < daftarCerita.Length - 1 || !sedangDialogBawah || sedangAnimasi;
|
|
}
|
|
|
|
private void UpdateTombol()
|
|
{
|
|
bool sebelumnyaAktif = BisaSebelumnya();
|
|
bool selanjutnyaAktif = BisaSelanjutnya();
|
|
|
|
if (buttonSebelumnya != null)
|
|
{
|
|
buttonSebelumnya.interactable = sebelumnyaAktif;
|
|
}
|
|
|
|
if (buttonSelanjutnya != null)
|
|
{
|
|
buttonSelanjutnya.interactable = selanjutnyaAktif;
|
|
}
|
|
|
|
if (canvasButtonSebelumnya != null)
|
|
{
|
|
canvasButtonSebelumnya.alpha = sebelumnyaAktif ? alphaTombolAktif : alphaTombolNonaktif;
|
|
canvasButtonSebelumnya.blocksRaycasts = sebelumnyaAktif;
|
|
canvasButtonSebelumnya.interactable = sebelumnyaAktif;
|
|
}
|
|
|
|
if (canvasButtonSelanjutnya != null)
|
|
{
|
|
canvasButtonSelanjutnya.alpha = selanjutnyaAktif ? alphaTombolAktif : alphaTombolNonaktif;
|
|
canvasButtonSelanjutnya.blocksRaycasts = selanjutnyaAktif;
|
|
canvasButtonSelanjutnya.interactable = selanjutnyaAktif;
|
|
}
|
|
}
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class DialogCerita
|
|
{
|
|
[Header("Dialog Atas")]
|
|
public string namaKarakterAtas;
|
|
|
|
[TextArea(2, 4)]
|
|
public string dialogAtas;
|
|
|
|
public Sprite avatarAtas;
|
|
|
|
[Header("Dialog Bawah")]
|
|
public string namaKarakterBawah;
|
|
|
|
[TextArea(2, 4)]
|
|
public string dialogBawah;
|
|
|
|
public Sprite avatarBawah;
|
|
} |