MIF_E31230101/Assets/Script Manager/GameManager.cs

354 lines
11 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
[System.Serializable]
public struct LevelConfig
{
public int pairCount;
public int columnCount;
public Vector2 cellSize;
public float memorizeTime;
public float limitTime;
}
[Header("Pengaturan Level")]
public List<LevelConfig> levelList;
[Header("UI Timer (Bar)")]
public Image timerFill;
public float penaltyTime = 3f;
public float rewardTime = 2f; // FITUR BARU: Tambahan waktu 2 detik kalau tebakan benar
private Color warnaAsliTimer; // Menyimpan warna asli UI hijau timer
[Header("UI Win Popup")]
public GameObject winPopup;
public CanvasGroup dimmerCanvasGroup;
public GameObject gameplayBoard;
public Image[] starImages;
public Sprite activeStar;
public Sprite inactiveStar;
public GameObject nextButton;
[Header("Referensi UI & Objek")]
public GameObject cardPrefab;
public Transform gridParent;
public List<Sprite> cardImages;
public TextMeshProUGUI levelTitleText;
[Header("Audio SFX")]
public AudioSource sfxSource;
public AudioClip klipBenar;
public AudioClip klipSalah;
[HideInInspector] public bool canClick = false;
private List<Card> allCards = new List<Card>();
private List<Vector3> targetPositions = new List<Vector3>();
private Card firstSelected, secondSelected;
private int pairsFound = 0;
private float currentTime;
private float maxTime;
private bool isGameActive = false;
void Start()
{
if (timerFill != null) warnaAsliTimer = timerFill.color; // Simpan warna timer di awal
SetupCurrentLevel();
}
void SetupCurrentLevel()
{
int idx = LevelData.SelectedLevel;
if (levelList == null || idx >= levelList.Count) return;
LevelConfig config = levelList[idx];
maxTime = (config.limitTime > 0) ? config.limitTime : 60f;
currentTime = maxTime;
pairsFound = 0;
winPopup.SetActive(false);
if (dimmerCanvasGroup != null) dimmerCanvasGroup.alpha = 0;
if (gameplayBoard != null) gameplayBoard.SetActive(true);
if (levelTitleText != null) levelTitleText.text = "Level " + (idx + 1);
GridLayoutGroup gridLayout = gridParent.GetComponent<GridLayoutGroup>();
gridLayout.constraintCount = config.columnCount;
gridLayout.cellSize = config.cellSize;
gridLayout.enabled = true;
GenerateCards(config.pairCount);
StartCoroutine(GameOpeningSequence(config.memorizeTime));
}
void Update()
{
if (isGameActive)
{
currentTime -= Time.deltaTime;
// Jaga biar waktu nggak minus
if (currentTime < 0) currentTime = 0;
if (timerFill != null) timerFill.fillAmount = currentTime / maxTime;
if (currentTime <= 0)
{
currentTime = 0;
isGameActive = false; // STOP SEGERA
HandleGameOver(false);
}
}
}
public void CardSelected(Card selected)
{
if (!canClick) return;
if (firstSelected == null)
{
firstSelected = selected;
firstSelected.ShowCard();
}
else if (secondSelected == null && selected != firstSelected)
{
secondSelected = selected;
secondSelected.ShowCard();
StartCoroutine(CheckMatch());
}
}
IEnumerator CheckMatch()
{
canClick = false;
yield return new WaitForSeconds(0.6f);
if (firstSelected.GetSprite() == secondSelected.GetSprite())
{
// --- JIKA TEBAKAN BENAR ---
if (sfxSource != null && klipBenar != null) sfxSource.PlayOneShot(klipBenar);
firstSelected.SetMatched();
secondSelected.SetMatched();
pairsFound++;
// Cek apakah sudah menyelesaikan seluruh level
if (pairsFound >= levelList[LevelData.SelectedLevel].pairCount)
{
HandleGameOver(true);
}
else
{
// --- INTEGRASI BARU: BERIKAN REWARD TAMBAHAN WAKTU ---
currentTime += rewardTime;
if (currentTime > maxTime) currentTime = maxTime; // Kunci agar tidak meluber dari batas maksimum bar
StartCoroutine(AnimasiTimerHijau()); // Jalankan efek kedip hijau sukses
}
}
else
{
// --- JIKA TEBAKAN SALAH ---
if (sfxSource != null && klipSalah != null) sfxSource.PlayOneShot(klipSalah);
currentTime -= penaltyTime; // Kurangi Waktu
StartCoroutine(AnimasiTimerMerah()); // Panggil Efek Kedip Merah
firstSelected.HideCard();
secondSelected.HideCard();
}
firstSelected = null; secondSelected = null;
canClick = true;
}
// --- FITUR ANIMASI KEDIP MERAH (KETIKA SALAH) ---
IEnumerator AnimasiTimerMerah()
{
if (timerFill != null)
{
timerFill.color = Color.red;
yield return new WaitForSeconds(0.2f);
timerFill.color = warnaAsliTimer;
}
}
// --- FITUR BARU: ANIMASI KEDIP HIJAU (REWARD KETIKA BENAR) ---
IEnumerator AnimasiTimerHijau()
{
if (timerFill != null)
{
timerFill.color = Color.green;
yield return new WaitForSeconds(0.2f);
timerFill.color = warnaAsliTimer;
}
}
void HandleGameOver(bool isWin)
{
if (winPopup.activeSelf) return;
isGameActive = false;
canClick = false;
StopAllCoroutines();
StartCoroutine(GameOverSequence(isWin));
}
IEnumerator GameOverSequence(bool isWin)
{
// Munculkan Popup dan Fade Blur
winPopup.SetActive(true);
winPopup.transform.localScale = Vector3.zero;
float fadeTime = 0.3f;
float elapsed = 0;
while (elapsed < fadeTime)
{
elapsed += Time.deltaTime;
float t = elapsed / fadeTime;
if (dimmerCanvasGroup != null) dimmerCanvasGroup.alpha = t;
winPopup.transform.localScale = Vector3.one * Mathf.SmoothStep(0, 1.1f, t);
yield return null;
}
winPopup.transform.localScale = Vector3.one;
if (gameplayBoard != null) gameplayBoard.SetActive(false);
if (nextButton != null) nextButton.SetActive(isWin);
int starCount = 0;
int totalPairs = levelList[LevelData.SelectedLevel].pairCount;
if (isWin)
{
starCount = 3;
int nextIdx = LevelData.SelectedLevel + 2;
if (nextIdx > PlayerPrefs.GetInt("ProgresMemory", 1))
{
PlayerPrefs.SetInt("ProgresMemory", nextIdx);
PlayerPrefs.Save();
}
}
else
{
float progress = (float)pairsFound / totalPairs;
if (progress >= 0.8f) starCount = 2;
else if (progress >= 0.4f) starCount = 1;
else starCount = 0;
}
StartCoroutine(ShowStarSequence(starCount));
}
IEnumerator ShowStarSequence(int count)
{
foreach (var s in starImages)
{
s.sprite = inactiveStar;
s.transform.localScale = Vector3.one;
}
yield return new WaitForSeconds(0.4f);
for (int i = 0; i < count; i++)
{
starImages[i].sprite = activeStar;
starImages[i].transform.localScale = Vector3.zero;
float st = 0;
while (st < 1)
{
st += Time.deltaTime * 7f;
starImages[i].transform.localScale = Vector3.one * Mathf.Lerp(0, 1.25f, st);
yield return null;
}
starImages[i].transform.localScale = Vector3.one;
yield return new WaitForSeconds(0.15f);
}
}
public void ButtonRematch() => SceneManager.LoadScene(SceneManager.GetActiveScene().name);
public void ButtonMenu() => SceneManager.LoadScene("MenuLevel");
public void ButtonNext()
{
if (LevelData.SelectedLevel < levelList.Count - 1)
{
LevelData.SelectedLevel++;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
else ButtonMenu();
}
void GenerateCards(int pairs)
{
foreach (Transform child in gridParent) Destroy(child.gameObject);
allCards.Clear(); targetPositions.Clear();
List<Sprite> pool = new List<Sprite>(cardImages);
List<Sprite> selectedIcons = new List<Sprite>();
int limit = Mathf.Min(pairs, pool.Count);
for (int i = 0; i < limit; i++)
{
int r = Random.Range(0, pool.Count);
selectedIcons.Add(pool[r]); pool.RemoveAt(r);
}
List<Sprite> pairList = new List<Sprite>();
foreach (Sprite s in selectedIcons) { pairList.Add(s); pairList.Add(s); }
for (int i = 0; i < pairList.Count; i++)
{
Sprite temp = pairList[i];
int rand = Random.Range(i, pairList.Count);
pairList[i] = pairList[rand]; pairList[rand] = temp;
}
foreach (Sprite img in pairList)
{
GameObject newCard = Instantiate(cardPrefab, gridParent);
Card cardScript = newCard.GetComponent<Card>();
cardScript.SetCardData(img, this);
allCards.Add(cardScript); newCard.transform.localScale = Vector3.zero;
}
}
IEnumerator GameOpeningSequence(float memTime)
{
canClick = false; isGameActive = false;
yield return new WaitForEndOfFrame();
GridLayoutGroup gridLayout = gridParent.GetComponent<GridLayoutGroup>();
foreach (Card c in allCards)
{
targetPositions.Add(c.transform.localPosition);
c.transform.localPosition = Vector3.zero; c.transform.localScale = Vector3.one;
}
gridLayout.enabled = false;
float dealDuration = 0.4f;
for (int i = 0; i < allCards.Count; i++)
{
StartCoroutine(MoveCardToPosition(allCards[i].transform, targetPositions[i], dealDuration));
yield return new WaitForSeconds(0.06f);
}
yield return new WaitForSeconds(dealDuration + 0.1f);
foreach (Card c in allCards) c.ShowCard();
yield return new WaitForSeconds(memTime);
foreach (Card c in allCards) c.HideCard();
yield return new WaitForSeconds(0.5f);
isGameActive = true; canClick = true;
}
IEnumerator MoveCardToPosition(Transform cardTr, Vector3 target, float duration)
{
Vector3 startPos = cardTr.localPosition;
float elapsed = 0;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
t = t * t * (3f - 2f * t);
cardTr.localPosition = Vector3.Lerp(startPos, target, t);
yield return null;
}
cardTr.localPosition = target;
}
}