using System.Collections; using System.Collections.Generic; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class TetrisTranslationDropMod : MonoBehaviour { [Header("━━━ FALLING BLOCK ━━━━━━━━━━━━━━━━━━━━━")] public RectTransform fallingBlock; public TMP_Text fallingText; [Header("━━━ CONTROLS ━━━━━━━━━━━━━━━━━━━━━━━━━")] public Button btnLeft; public Button btnRight; public Button btnDown; public Button backButton; [Header("━━━ UI ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")] public TMP_Text scoreText; public TMP_Text comboText; public TMP_Text timerText; public TMP_Text feedbackText; [Header("━━━ TRANSLATION SLOTS (4) ━━━━━━━━━━━━━")] public RectTransform[] translationSlots; public TMP_Text[] translationSlotTexts; [Header("━━━ WORD TXT ━━━━━━━━━━━━━━━━━━━━━━━━━")] [Tooltip("Each line: tr,en,es,de,fr,pt")] public TextAsset wordsTxt; [Header("━━━ SCENE SETTINGS ━━━━━━━━━━━━━━━━━━━")] public string backSceneName = "ModSec 7"; public string resultSceneName = "Mod7Resume"; [Header("━━━ GAME SETTINGS ━━━━━━━━━━━━━━━━━━━")] public float baseFallSpeed = 220f; public float maxFallSpeed = 620f; public float fallSpeedIncreaseRate = 12f; public float moveStep = 140f; public float fastFallStep = 350f; public float gameTime = 90f; public float nextWordDelay = 0.75f; public int correctBaseScore = 50; public int comboBonus = 10; public int wrongPenalty = 20; [Header("━━━ SCREEN LIMITS ━━━━━━━━━━━━━━━━━━━━")] public float minX = -420f; public float maxX = 420f; public float spawnY = 650f; public float bottomLimitY = -650f; [Header("━━━ COLORS ━━━━━━━━━━━━━━━━━━━━━━━━━━")] public Color normalSlotColor = new Color32(255, 255, 255, 255); public Color correctSlotColor = new Color32(70, 220, 120, 255); public Color wrongSlotColor = new Color32(240, 80, 80, 255); public Color feedbackCorrectColor = new Color32(70, 220, 120, 255); public Color feedbackWrongColor = new Color32(240, 80, 80, 255); public Color timerNormalColor = new Color32(255, 255, 255, 255); public Color timerWarningColor = new Color32(255, 80, 80, 255); [Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━")] public float blockSpawnScale = 0.82f; public float blockSpawnAnimTime = 0.18f; public float slotPulseScale = 1.08f; public float slotPulseTime = 0.12f; public float shakeAmount = 12f; public float shakeTime = 0.28f; [Header("━━━ SOUND ━━━━━━━━━━━━━━━━━━━━━━━━━━━")] public AudioSource sfxSource; public AudioClip clickClip; public AudioClip correctClip; public AudioClip wrongClip; // INTERNAL private List fullDeck = new List(); private int deckIndex = 0; private WordEntry currentWord; private string correctAnswer = ""; private string lastWordKey = ""; private float timer; private float currentFallSpeed; private float smoothVelocity = 0f; private bool processing = false; private bool gameOver = false; private int score = 0; private int combo = 0; private int bestComboThisRun = 0; private int correctCount = 0; private int wrongCount = 0; private string questionLangCode; private string answerLangCode = "en"; private string uiLangCode; private Vector3[] originalSlotScales; private Vector2[] originalSlotPositions; private Vector3 originalBlockScale = Vector3.one; private Coroutine blockSpawnCo; private Coroutine blockReactCo; private Coroutine feedbackCo; private Coroutine[] slotCoroutines; private string modKey = "Mod7"; private class WordEntry { public string tr; public string en; public string es; public string de; public string fr; public string pt; public string Key => tr + "_" + en; } // ====================================================== void Start() { gameOver = false; processing = false; questionLangCode = GetQuestionLanguage(); answerLangCode = "en"; uiLangCode = GetUILanguage(); PlayerPrefs.SetString("QuestionLangCode", questionLangCode); PlayerPrefs.SetString("AnswerLangCode", answerLangCode); PlayerPrefs.Save(); timer = PlayerPrefs.GetFloat("SelectedGameTime", gameTime); if (timer <= 0) timer = gameTime; currentFallSpeed = baseFallSpeed; CacheSlotData(); LoadWords(); if (fullDeck.Count < 4) { Debug.LogError("Mod7 kelime dosyası en az 4 satır olmalı! Format: tr,en,es,de,fr,pt"); enabled = false; return; } if (!ValidateUI()) { enabled = false; return; } BindButtons(); Shuffle(fullDeck); UpdateUI(); UpdateTimerUI(); SaveProgress(); SpawnNewWord(); } // ====================================================== void Update() { if (gameOver || processing) return; timer -= Time.deltaTime; if (timer <= 0) { timer = 0; UpdateTimerUI(); GameOver(); return; } UpdateTimerUI(); float targetSpeed = baseFallSpeed + (score / 250f) * fallSpeedIncreaseRate; targetSpeed = Mathf.Clamp(targetSpeed, baseFallSpeed, maxFallSpeed); currentFallSpeed = Mathf.SmoothDamp( currentFallSpeed, targetSpeed, ref smoothVelocity, 0.18f ); if (fallingBlock != null) fallingBlock.anchoredPosition += Vector2.down * currentFallSpeed * Time.deltaTime; CheckCollision(); } // ====================================================== bool ValidateUI() { if (fallingBlock == null) { Debug.LogError("fallingBlock atanmadı!"); return false; } if (fallingText == null) { Debug.LogError("fallingText atanmadı!"); return false; } if (translationSlots == null || translationSlots.Length < 4) { Debug.LogError("translationSlots en az 4 olmalı!"); return false; } if (translationSlotTexts == null || translationSlotTexts.Length < 4) { Debug.LogError("translationSlotTexts en az 4 olmalı!"); return false; } return true; } void BindButtons() { if (btnLeft != null) { btnLeft.onClick.RemoveAllListeners(); btnLeft.onClick.AddListener(() => { PlayClick(); Move(-moveStep); }); } if (btnRight != null) { btnRight.onClick.RemoveAllListeners(); btnRight.onClick.AddListener(() => { PlayClick(); Move(+moveStep); }); } if (btnDown != null) { btnDown.onClick.RemoveAllListeners(); btnDown.onClick.AddListener(() => { PlayClick(); FastFall(); }); } if (backButton != null) { backButton.onClick.RemoveAllListeners(); backButton.onClick.AddListener(() => { PlayClick(); SaveProgress(); GoBack(); }); } } void GoBack() { if (!string.IsNullOrEmpty(backSceneName)) SceneManager.LoadScene(backSceneName); else Debug.LogWarning("backSceneName boş!"); } // ====================================================== void CacheSlotData() { if (fallingBlock != null) originalBlockScale = fallingBlock.localScale; if (translationSlots == null) return; originalSlotScales = new Vector3[translationSlots.Length]; originalSlotPositions = new Vector2[translationSlots.Length]; slotCoroutines = new Coroutine[translationSlots.Length]; for (int i = 0; i < translationSlots.Length; i++) { if (translationSlots[i] == null) continue; originalSlotScales[i] = translationSlots[i].localScale; originalSlotPositions[i] = translationSlots[i].anchoredPosition; } } void ResetSlotVisuals() { if (translationSlots == null) return; for (int i = 0; i < translationSlots.Length; i++) { if (translationSlots[i] == null) continue; if (slotCoroutines != null && i < slotCoroutines.Length && slotCoroutines[i] != null) { StopCoroutine(slotCoroutines[i]); slotCoroutines[i] = null; } Image img = translationSlots[i].GetComponent(); if (img != null) img.color = FullAlpha(normalSlotColor); if (originalSlotScales != null && i < originalSlotScales.Length) translationSlots[i].localScale = originalSlotScales[i]; if (originalSlotPositions != null && i < originalSlotPositions.Length) translationSlots[i].anchoredPosition = originalSlotPositions[i]; } } // ====================================================== void LoadWords() { fullDeck.Clear(); if (wordsTxt == null) { Debug.LogError("wordsTxt atanmadı!"); return; } string[] lines = wordsTxt.text.Split('\n'); foreach (string rawLine in lines) { string line = rawLine.Trim(); if (string.IsNullOrWhiteSpace(line)) continue; string[] p = line.Split(','); if (p.Length < 6) { Debug.LogWarning("Eksik satır: " + line); continue; } fullDeck.Add(new WordEntry { tr = p[0].Trim(), en = p[1].Trim(), es = p[2].Trim(), de = p[3].Trim(), fr = p[4].Trim(), pt = p[5].Trim() }); } } // ====================================================== void SpawnNewWord() { if (gameOver) return; processing = false; ResetSlotVisuals(); if (feedbackText != null) feedbackText.text = ""; if (deckIndex >= fullDeck.Count) { Shuffle(fullDeck); deckIndex = 0; lastWordKey = ""; } currentWord = fullDeck[deckIndex]; if (currentWord.Key == lastWordKey && fullDeck.Count > 1) { int rnd = Random.Range(0, fullDeck.Count); currentWord = fullDeck[rnd]; deckIndex = rnd + 1; if (deckIndex >= fullDeck.Count) deckIndex = 0; } else { deckIndex++; } lastWordKey = currentWord.Key; string questionWord = GetWordByLang(currentWord, questionLangCode); correctAnswer = GetWordByLang(currentWord, answerLangCode); // ✅ Yukarıdan soru dili gelir fallingText.text = questionWord; if (fallingBlock != null) { fallingBlock.anchoredPosition = new Vector2(0, spawnY); fallingBlock.localScale = originalBlockScale; } // ✅ Alttaki seçenekler İngilizce gelir SetupTranslationSlots(correctAnswer); if (blockSpawnCo != null) StopCoroutine(blockSpawnCo); if (blockReactCo != null) StopCoroutine(blockReactCo); blockSpawnCo = StartCoroutine(BlockSpawnAnim()); } void SetupTranslationSlots(string correct) { List choices = new List(); choices.Add(correct); int guard = 0; while (choices.Count < 4 && guard < 500) { guard++; WordEntry randomWord = fullDeck[Random.Range(0, fullDeck.Count)]; string candidate = GetWordByLang(randomWord, answerLangCode); if (!string.IsNullOrWhiteSpace(candidate) && !choices.Contains(candidate)) choices.Add(candidate); } while (choices.Count < 4) choices.Add("-"); Shuffle(choices); for (int i = 0; i < 4; i++) { if (translationSlotTexts[i] != null) translationSlotTexts[i].text = choices[i]; if (translationSlots[i] != null) { translationSlots[i].name = choices[i]; Image img = translationSlots[i].GetComponent(); if (img != null) img.color = FullAlpha(normalSlotColor); } } } // ====================================================== void Move(float x) { if (processing || gameOver || fallingBlock == null) return; Vector2 pos = fallingBlock.anchoredPosition; pos.x = Mathf.Clamp(pos.x + x, minX, maxX); fallingBlock.anchoredPosition = pos; } void FastFall() { if (processing || gameOver || fallingBlock == null) return; fallingBlock.anchoredPosition += Vector2.down * fastFallStep; CheckCollision(); } // ====================================================== void CheckCollision() { if (processing || gameOver) return; if (fallingBlock == null || translationSlots == null || translationSlots.Length < 4) return; float slotY = translationSlots[0].anchoredPosition.y; float blockY = fallingBlock.anchoredPosition.y; float halfH = fallingBlock.rect.height * 0.5f; if (blockY - halfH <= slotY) { int idx = DetectSlot(fallingBlock.anchoredPosition.x); if (idx == -1) { Wrong("miss"); return; } Evaluate(idx); return; } if (blockY + halfH < bottomLimitY) Wrong("out"); } int DetectSlot(float x) { for (int i = 0; i < 4; i++) { if (translationSlots[i] == null) continue; float sx = translationSlots[i].anchoredPosition.x; float half = translationSlots[i].rect.width * 0.5f; if (x >= sx - half && x <= sx + half) return i; } return -1; } // ====================================================== void Evaluate(int slotIndex) { if (processing || gameOver) return; processing = true; string selectedAnswer = ""; if (translationSlotTexts[slotIndex] != null) selectedAnswer = translationSlotTexts[slotIndex].text; bool correct = selectedAnswer == correctAnswer; if (correct) HandleCorrect(slotIndex); else HandleWrong(slotIndex); UpdateUI(); SaveProgress(); Invoke(nameof(SpawnNewWord), nextWordDelay); } void HandleCorrect(int slotIndex) { score += correctBaseScore + combo * comboBonus; combo++; correctCount++; if (combo > bestComboThisRun) bestComboThisRun = combo; Image img = translationSlots[slotIndex].GetComponent(); if (img != null) img.color = FullAlpha(correctSlotColor); PlayCorrect(); SetFeedback(LocalizeFeedback("correct") + " +" + correctBaseScore, feedbackCorrectColor); StartSlotAnim(slotIndex, SlotPulse(slotIndex)); if (blockReactCo != null) StopCoroutine(blockReactCo); blockReactCo = StartCoroutine(BlockCorrectAnim()); } void HandleWrong(int slotIndex) { score = Mathf.Max(0, score - wrongPenalty); combo = 0; wrongCount++; Image selectedImg = translationSlots[slotIndex].GetComponent(); if (selectedImg != null) selectedImg.color = FullAlpha(wrongSlotColor); for (int i = 0; i < 4; i++) { if (translationSlotTexts[i] == null || translationSlots[i] == null) continue; if (translationSlotTexts[i].text == correctAnswer) { Image correctImg = translationSlots[i].GetComponent(); if (correctImg != null) correctImg.color = FullAlpha(correctSlotColor); StartSlotAnim(i, SlotPulse(i)); } } PlayWrong(); SetFeedback(LocalizeFeedback("wrong") + " | " + correctAnswer, feedbackWrongColor); StartSlotAnim(slotIndex, ShakeSlot(slotIndex)); if (blockReactCo != null) StopCoroutine(blockReactCo); blockReactCo = StartCoroutine(BlockWrongAnim()); } void Wrong(string reason) { if (processing || gameOver) return; processing = true; score = Mathf.Max(0, score - wrongPenalty); combo = 0; wrongCount++; PlayWrong(); SetFeedback(LocalizeFeedback(reason), feedbackWrongColor); if (blockReactCo != null) StopCoroutine(blockReactCo); blockReactCo = StartCoroutine(BlockWrongAnim()); UpdateUI(); SaveProgress(); Invoke(nameof(SpawnNewWord), nextWordDelay); } // ====================================================== void UpdateUI() { if (scoreText != null) scoreText.text = score.ToString(); if (comboText != null) comboText.text = "x" + combo; } void UpdateTimerUI() { if (timerText == null) return; timerText.text = Mathf.CeilToInt(timer).ToString(); if (timer <= 10f) { timerText.color = FullAlpha(Color.Lerp(timerWarningColor, Color.white, Mathf.PingPong(Time.time * 3f, 1f))); timerText.transform.localScale = Vector3.one * (1f + Mathf.Sin(Time.time * 10f) * 0.05f); } else { timerText.color = FullAlpha(timerNormalColor); timerText.transform.localScale = Vector3.one; } } void SetFeedback(string msg, Color c) { if (feedbackText == null) return; feedbackText.text = msg; feedbackText.color = FullAlpha(c); if (feedbackCo != null) StopCoroutine(feedbackCo); feedbackCo = StartCoroutine(FeedbackPop()); } IEnumerator FeedbackPop() { if (feedbackText == null) yield break; Vector3 normal = Vector3.one; Vector3 big = Vector3.one * 1.14f; float t = 0f; while (t < 1f) { t += Time.deltaTime / 0.12f; feedbackText.transform.localScale = Vector3.Lerp(normal, big, EaseOutBack(t)); yield return null; } t = 0f; while (t < 1f) { t += Time.deltaTime / 0.12f; feedbackText.transform.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t)); yield return null; } feedbackText.transform.localScale = normal; feedbackCo = null; } // ====================================================== void SaveProgress() { PlayerPrefs.SetInt("Mod7Skor", score); PlayerPrefs.SetInt("Mod7Score", score); PlayerPrefs.SetInt("Mod7_LastScore", score); PlayerPrefs.SetInt("Mod7_Correct", correctCount); PlayerPrefs.SetInt("Mod7_Wrong", wrongCount); PlayerPrefs.SetInt("Mod7_LastCombo", combo); PlayerPrefs.SetInt("Mod7_BestComboRun", bestComboThisRun); PlayerPrefs.SetInt("Mod7_LastTimeLeft", Mathf.CeilToInt(timer)); int totalAnswers = correctCount + wrongCount; int accuracy = totalAnswers > 0 ? Mathf.RoundToInt((correctCount / (float)totalAnswers) * 100f) : 0; PlayerPrefs.SetInt("Mod7_LastAccuracy", accuracy); int oldMax = PlayerPrefs.GetInt("Mod7_MaxScore", 0); if (score > oldMax) PlayerPrefs.SetInt("Mod7_MaxScore", score); int oldBestCombo = PlayerPrefs.GetInt("Mod7_BestCombo", 0); if (bestComboThisRun > oldBestCombo) PlayerPrefs.SetInt("Mod7_BestCombo", bestComboThisRun); PlayerPrefs.Save(); } void GameOver() { if (gameOver) return; gameOver = true; processing = true; SaveProgress(); PlayerPrefs.SetString("LastPlayedMod", modKey); PlayerPrefs.SetInt(modKey + "_TotalCorrect", PlayerPrefs.GetInt(modKey + "_TotalCorrect", 0) + correctCount); PlayerPrefs.SetInt(modKey + "_TotalWrong", PlayerPrefs.GetInt(modKey + "_TotalWrong", 0) + wrongCount); PlayerPrefs.SetInt(modKey + "_PlayCount", PlayerPrefs.GetInt(modKey + "_PlayCount", 0) + 1); PlayerPrefs.SetInt("TotalScore", PlayerPrefs.GetInt("TotalScore", 0) + score); PlayerPrefs.Save(); if (!string.IsNullOrEmpty(resultSceneName)) SceneManager.LoadScene(resultSceneName); else Debug.LogWarning("resultSceneName boş!"); } // ====================================================== void StartSlotAnim(int slotIndex, IEnumerator routine) { if (slotCoroutines == null) return; if (slotIndex < 0 || slotIndex >= slotCoroutines.Length) return; if (slotCoroutines[slotIndex] != null) StopCoroutine(slotCoroutines[slotIndex]); slotCoroutines[slotIndex] = StartCoroutine(routine); } IEnumerator SlotPulse(int slotIndex) { if (translationSlots == null) yield break; if (slotIndex < 0 || slotIndex >= translationSlots.Length) yield break; if (translationSlots[slotIndex] == null) yield break; Vector3 normal = originalSlotScales[slotIndex]; Vector3 big = normal * slotPulseScale; float t = 0f; while (t < 1f) { t += Time.deltaTime / Mathf.Max(0.01f, slotPulseTime); translationSlots[slotIndex].localScale = Vector3.Lerp(normal, big, EaseOutQuad(t)); yield return null; } t = 0f; while (t < 1f) { t += Time.deltaTime / Mathf.Max(0.01f, slotPulseTime); translationSlots[slotIndex].localScale = Vector3.Lerp(big, normal, EaseOutQuad(t)); yield return null; } translationSlots[slotIndex].localScale = normal; slotCoroutines[slotIndex] = null; } IEnumerator ShakeSlot(int slotIndex) { if (translationSlots == null) yield break; if (slotIndex < 0 || slotIndex >= translationSlots.Length) yield break; if (translationSlots[slotIndex] == null) yield break; Vector2 origin = originalSlotPositions[slotIndex]; float elapsed = 0f; while (elapsed < shakeTime) { float power = 1f - elapsed / shakeTime; float x = Random.Range(-1f, 1f) * shakeAmount * power; translationSlots[slotIndex].anchoredPosition = origin + new Vector2(x, 0f); elapsed += Time.deltaTime; yield return null; } translationSlots[slotIndex].anchoredPosition = origin; slotCoroutines[slotIndex] = null; } IEnumerator BlockSpawnAnim() { if (fallingBlock == null) yield break; Vector3 target = originalBlockScale; Vector3 small = originalBlockScale * blockSpawnScale; fallingBlock.localScale = small; float t = 0f; while (t < 1f) { t += Time.deltaTime / Mathf.Max(0.01f, blockSpawnAnimTime); fallingBlock.localScale = Vector3.Lerp(small, target, EaseOutBack(t)); yield return null; } fallingBlock.localScale = target; } IEnumerator BlockCorrectAnim() { if (fallingBlock == null) yield break; Vector3 normal = originalBlockScale; Vector3 big = originalBlockScale * 1.08f; float t = 0f; while (t < 1f) { t += Time.deltaTime / 0.10f; fallingBlock.localScale = Vector3.Lerp(normal, big, EaseOutQuad(t)); yield return null; } t = 0f; while (t < 1f) { t += Time.deltaTime / 0.10f; fallingBlock.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t)); yield return null; } fallingBlock.localScale = normal; } IEnumerator BlockWrongAnim() { if (fallingBlock == null) yield break; Vector2 origin = fallingBlock.anchoredPosition; float elapsed = 0f; float duration = 0.28f; while (elapsed < duration) { float power = 1f - elapsed / duration; float x = Random.Range(-1f, 1f) * 14f * power; fallingBlock.anchoredPosition = origin + new Vector2(x, 0f); elapsed += Time.deltaTime; yield return null; } fallingBlock.anchoredPosition = origin; } // ====================================================== void PlayClick() { if (sfxSource != null && clickClip != null) sfxSource.PlayOneShot(clickClip); } void PlayCorrect() { if (sfxSource != null && correctClip != null) sfxSource.PlayOneShot(correctClip); } void PlayWrong() { if (sfxSource != null && wrongClip != null) sfxSource.PlayOneShot(wrongClip); } // ====================================================== string GetQuestionLanguage() { string q = PlayerPrefs.GetString("QuestionLangCode", ""); q = NormalizeLang(q); if (!string.IsNullOrWhiteSpace(q) && q != "en") return q; int appId = PlayerPrefs.GetInt("AppLanguage", -1); if (appId >= 0) { string appLang = LangIdToCode(appId); if (appLang != "en") return appLang; } string appString = NormalizeLang(PlayerPrefs.GetString("AppLanguage", "tr")); if (appString != "en") return appString; return "tr"; } string GetUILanguage() { int appId = PlayerPrefs.GetInt("AppLanguage", -1); if (appId >= 0) return LangIdToCode(appId); return NormalizeLang(PlayerPrefs.GetString("AppLanguage", "en")); } string LangIdToCode(int id) { return id switch { 0 => "tr", 2 => "es", 3 => "de", 4 => "fr", 5 => "pt", _ => "en" }; } string NormalizeLang(string raw) { if (string.IsNullOrEmpty(raw)) return "en"; raw = raw.Trim().ToLower(); if (raw == "tr" || raw == "turkish" || raw == "tr-tr") return "tr"; if (raw == "en" || raw == "english" || raw.StartsWith("en-")) return "en"; if (raw == "es" || raw == "spanish" || raw == "es-es") return "es"; if (raw == "de" || raw == "german" || raw == "de-de") return "de"; if (raw == "fr" || raw == "french" || raw == "fr-fr") return "fr"; if (raw == "pt" || raw == "portuguese" || raw == "pt-pt" || raw == "pt-br") return "pt"; return "en"; } string GetWordByLang(WordEntry w, string lang) { return lang switch { "tr" => w.tr, "es" => w.es, "de" => w.de, "fr" => w.fr, "pt" => w.pt, _ => w.en }; } string LocalizeFeedback(string key) { return key switch { "correct" => uiLangCode switch { "tr" => "Doğru!", "es" => "¡Correcto!", "de" => "Richtig!", "fr" => "Correct!", "pt" => "Correto!", _ => "Correct!" }, "wrong" => uiLangCode switch { "tr" => "Yanlış!", "es" => "¡Incorrecto!", "de" => "Falsch!", "fr" => "Faux!", "pt" => "Errado!", _ => "Wrong!" }, "miss" => uiLangCode switch { "tr" => "Kaçırdın!", "es" => "Fallaste!", "de" => "Verpasst!", "fr" => "Raté!", "pt" => "Perdeu!", _ => "Miss!" }, "out" => uiLangCode switch { "tr" => "Ekran dışı!", "es" => "Fuera!", "de" => "Außerhalb!", "fr" => "Hors écran!", "pt" => "Fora!", _ => "Out!" }, _ => key }; } // ====================================================== Color FullAlpha(Color c) { c.a = 1f; return c; } float EaseOutQuad(float t) { t = Mathf.Clamp01(t); return 1f - (1f - t) * (1f - t); } float EaseOutBack(float t) { t = Mathf.Clamp01(t); float c1 = 1.70158f; float c3 = c1 + 1f; return 1f + c3 * Mathf.Pow(t - 1f, 3f) + c1 * Mathf.Pow(t - 1f, 2f); } void Shuffle(List list) { for (int i = list.Count - 1; i > 0; i--) { int r = Random.Range(0, i + 1); T temp = list[i]; list[i] = list[r]; list[r] = temp; } } }