804 lines
22 KiB
C#
804 lines
22 KiB
C#
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using TMPro;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
using UnityEngine.SceneManagement;
|
|||
|
|
|
|||
|
|
public class ClozeGameScene : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
[Header("TXT DOSYASI (6 Dil)")]
|
|||
|
|
public TextAsset questionFile;
|
|||
|
|
|
|||
|
|
[Header("UI")]
|
|||
|
|
public TMP_Text questionText;
|
|||
|
|
public TMP_Text[] answerTexts;
|
|||
|
|
public Button[] answerButtons;
|
|||
|
|
public Button submitButton;
|
|||
|
|
|
|||
|
|
public TMP_Text scoreText;
|
|||
|
|
public TMP_Text comboText;
|
|||
|
|
public TMP_Text timerText;
|
|||
|
|
public TMP_Text feedbackText;
|
|||
|
|
|
|||
|
|
[Header("EXTRA BUTTONS")]
|
|||
|
|
public Button extraTimeButton;
|
|||
|
|
public Button extraHintButton;
|
|||
|
|
public Button extraSkipButton;
|
|||
|
|
|
|||
|
|
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
|
|||
|
|
public Button backButton;
|
|||
|
|
public string backSceneName = "ModSec 4";
|
|||
|
|
|
|||
|
|
[Header("RENKLER")]
|
|||
|
|
public Color normalColor = new Color32(255, 255, 255, 255);
|
|||
|
|
public Color selectedColor = new Color32(60, 110, 200, 255);
|
|||
|
|
public Color correctColor = new Color32(0, 200, 0, 255);
|
|||
|
|
public Color wrongColor = new Color32(200, 0, 0, 255);
|
|||
|
|
public Color hintColor = new Color32(255, 255, 128, 255);
|
|||
|
|
|
|||
|
|
[Header("━━━ FEEDBACK TEXT SETTINGS ━━━━━━━━━━━━━")]
|
|||
|
|
public bool feedbackOnTop = true;
|
|||
|
|
public float feedbackTopY = 400f;
|
|||
|
|
public float feedbackFontSize = 72f;
|
|||
|
|
|
|||
|
|
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
|||
|
|
[Range(0.80f, 1f)] public float selectedScale = 0.94f;
|
|||
|
|
public float selectAnimTime = 0.10f;
|
|||
|
|
public float enterAnimTime = 0.22f;
|
|||
|
|
|
|||
|
|
// ---------------- INTERNAL STATE ----------------
|
|||
|
|
private class ClozeEntry
|
|||
|
|
{
|
|||
|
|
public string[] q = new string[6];
|
|||
|
|
public string[] c = new string[6];
|
|||
|
|
public string[] w1 = new string[6];
|
|||
|
|
public string[] w2 = new string[6];
|
|||
|
|
public string[] w3 = new string[6];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<ClozeEntry> questions = new List<ClozeEntry>();
|
|||
|
|
|
|||
|
|
private int selected = -1;
|
|||
|
|
private int correctIndex = -1;
|
|||
|
|
private int lastQuestionID = -1;
|
|||
|
|
|
|||
|
|
private int score = 0;
|
|||
|
|
private int combo = 0;
|
|||
|
|
private int correctCount = 0;
|
|||
|
|
private int wrongCount = 0;
|
|||
|
|
|
|||
|
|
private float timeLeft = 60f;
|
|||
|
|
private float nextDelay = 1.2f;
|
|||
|
|
|
|||
|
|
private bool locked = false;
|
|||
|
|
private string lang;
|
|||
|
|
|
|||
|
|
private string modKey = "Mod4"; // ✅ Bu modun özel key'i
|
|||
|
|
|
|||
|
|
readonly Color timerNormalColor = Color.white;
|
|||
|
|
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
|||
|
|
|
|||
|
|
Vector3[] originalButtonScales;
|
|||
|
|
Vector3[] originalButtonPositions;
|
|||
|
|
Coroutine[] buttonScaleCoroutines;
|
|||
|
|
Coroutine[] buttonEnterCoroutines;
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void Start()
|
|||
|
|
{
|
|||
|
|
lang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
|||
|
|
|
|||
|
|
if (questionFile == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogError("TXT Dosyası atanmadı!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
LoadTXT(questionFile.text);
|
|||
|
|
|
|||
|
|
CacheButtonData();
|
|||
|
|
ForceButtonTransitionNone();
|
|||
|
|
PrepareFeedbackText();
|
|||
|
|
|
|||
|
|
submitButton.onClick.AddListener(OnSubmit);
|
|||
|
|
extraTimeButton.onClick.AddListener(() => { if (!locked) timeLeft += 5; });
|
|||
|
|
extraHintButton.onClick.AddListener(OnHint);
|
|||
|
|
extraSkipButton.onClick.AddListener(() => NextQuestion());
|
|||
|
|
|
|||
|
|
if (backButton != null)
|
|||
|
|
{
|
|||
|
|
backButton.onClick.RemoveAllListeners();
|
|||
|
|
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scoreText.text = "0";
|
|||
|
|
comboText.text = "0x";
|
|||
|
|
feedbackText.text = "";
|
|||
|
|
|
|||
|
|
NextQuestion();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void Update()
|
|||
|
|
{
|
|||
|
|
if (!locked)
|
|||
|
|
{
|
|||
|
|
timeLeft -= Time.deltaTime;
|
|||
|
|
if (timeLeft <= 0)
|
|||
|
|
{
|
|||
|
|
timeLeft = 0;
|
|||
|
|
GameOver();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateTimerUI();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void CacheButtonData()
|
|||
|
|
{
|
|||
|
|
if (answerButtons == null) return;
|
|||
|
|
|
|||
|
|
int len = answerButtons.Length;
|
|||
|
|
originalButtonScales = new Vector3[len];
|
|||
|
|
originalButtonPositions = new Vector3[len];
|
|||
|
|
buttonScaleCoroutines = new Coroutine[len];
|
|||
|
|
buttonEnterCoroutines = new Coroutine[len];
|
|||
|
|
|
|||
|
|
for (int i = 0; i < len; i++)
|
|||
|
|
{
|
|||
|
|
if (answerButtons[i] == null) continue;
|
|||
|
|
|
|||
|
|
originalButtonScales[i] = answerButtons[i].transform.localScale;
|
|||
|
|
originalButtonPositions[i] = answerButtons[i].transform.localPosition;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ForceButtonTransitionNone()
|
|||
|
|
{
|
|||
|
|
if (answerButtons == null) return;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < answerButtons.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (answerButtons[i] == null) continue;
|
|||
|
|
|
|||
|
|
answerButtons[i].transition = Selectable.Transition.None;
|
|||
|
|
|
|||
|
|
Image img = answerButtons[i].image;
|
|||
|
|
if (img != null)
|
|||
|
|
img.color = FullAlpha(normalColor);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void PrepareFeedbackText()
|
|||
|
|
{
|
|||
|
|
if (feedbackText == null) return;
|
|||
|
|
|
|||
|
|
if (feedbackOnTop)
|
|||
|
|
{
|
|||
|
|
Vector3 pos = feedbackText.transform.localPosition;
|
|||
|
|
pos.y = feedbackTopY;
|
|||
|
|
feedbackText.transform.localPosition = pos;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
feedbackText.alignment = TextAlignmentOptions.Center;
|
|||
|
|
feedbackText.fontSize = Mathf.Max(feedbackText.fontSize, feedbackFontSize);
|
|||
|
|
feedbackText.text = "";
|
|||
|
|
|
|||
|
|
Color c = feedbackText.color;
|
|||
|
|
c.a = 1f;
|
|||
|
|
feedbackText.color = c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void LoadTXT(string raw)
|
|||
|
|
{
|
|||
|
|
foreach (string line in raw.Trim().Split('\n'))
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrWhiteSpace(line)) continue;
|
|||
|
|
|
|||
|
|
string[] p = line.Split('|');
|
|||
|
|
if (p.Length < 30)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("Eksik satır: " + line);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ClozeEntry e = new ClozeEntry();
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 6; i++)
|
|||
|
|
{
|
|||
|
|
e.q[i] = p[i].Trim();
|
|||
|
|
e.c[i] = p[6 + i].Trim();
|
|||
|
|
e.w1[i] = p[12 + i].Trim();
|
|||
|
|
e.w2[i] = p[18 + i].Trim();
|
|||
|
|
e.w3[i] = p[24 + i].Trim();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
questions.Add(e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void NextQuestion()
|
|||
|
|
{
|
|||
|
|
locked = false;
|
|||
|
|
feedbackText.text = "";
|
|||
|
|
selected = -1;
|
|||
|
|
|
|||
|
|
ResetButtons();
|
|||
|
|
|
|||
|
|
// Aynı soru ard arda gelmesin
|
|||
|
|
int id = Random.Range(0, questions.Count);
|
|||
|
|
if (id == lastQuestionID && questions.Count > 1)
|
|||
|
|
id = (id + 1) % questions.Count;
|
|||
|
|
|
|||
|
|
lastQuestionID = id;
|
|||
|
|
|
|||
|
|
ClozeEntry q = questions[id];
|
|||
|
|
int L = GetLangIndex();
|
|||
|
|
|
|||
|
|
questionText.text = q.q[L];
|
|||
|
|
StartCoroutine(FadeInText(questionText));
|
|||
|
|
|
|||
|
|
List<string> opts = new List<string>()
|
|||
|
|
{
|
|||
|
|
q.c[L], q.w1[L], q.w2[L], q.w3[L]
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
Shuffle(opts);
|
|||
|
|
|
|||
|
|
// Şık yerleşimi
|
|||
|
|
correctIndex = opts.IndexOf(q.c[L]);
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 4; i++)
|
|||
|
|
{
|
|||
|
|
answerTexts[i].text = opts[i];
|
|||
|
|
int index = i;
|
|||
|
|
|
|||
|
|
answerButtons[i].onClick.RemoveAllListeners();
|
|||
|
|
answerButtons[i].onClick.AddListener(() => SelectAnswer(index));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < answerButtons.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (answerButtons[i] == null) continue;
|
|||
|
|
|
|||
|
|
if (buttonEnterCoroutines[i] != null)
|
|||
|
|
StopCoroutine(buttonEnterCoroutines[i]);
|
|||
|
|
|
|||
|
|
buttonEnterCoroutines[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], i));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void ResetButtons()
|
|||
|
|
{
|
|||
|
|
if (answerButtons == null) return;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < answerButtons.Length; i++)
|
|||
|
|
{
|
|||
|
|
if (answerButtons[i] == null) continue;
|
|||
|
|
|
|||
|
|
StopButtonCoroutines(i);
|
|||
|
|
|
|||
|
|
answerButtons[i].interactable = true;
|
|||
|
|
answerButtons[i].transition = Selectable.Transition.None;
|
|||
|
|
|
|||
|
|
Image img = answerButtons[i].image;
|
|||
|
|
if (img != null)
|
|||
|
|
img.color = FullAlpha(normalColor);
|
|||
|
|
|
|||
|
|
answerButtons[i].transform.localScale = originalButtonScales[i];
|
|||
|
|
answerButtons[i].transform.localPosition = originalButtonPositions[i];
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void SelectAnswer(int id)
|
|||
|
|
{
|
|||
|
|
if (locked) return;
|
|||
|
|
|
|||
|
|
if (selected == id)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (selected >= 0 && selected < answerButtons.Length)
|
|||
|
|
{
|
|||
|
|
Button oldButton = answerButtons[selected];
|
|||
|
|
|
|||
|
|
if (oldButton != null)
|
|||
|
|
{
|
|||
|
|
Image oldImg = oldButton.image;
|
|||
|
|
if (oldImg != null)
|
|||
|
|
oldImg.color = FullAlpha(normalColor);
|
|||
|
|
|
|||
|
|
StartScaleAnim(selected, originalButtonScales[selected]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
selected = id;
|
|||
|
|
|
|||
|
|
Image img = answerButtons[id].image;
|
|||
|
|
if (img != null)
|
|||
|
|
img.color = FullAlpha(selectedColor);
|
|||
|
|
|
|||
|
|
StartScaleAnim(id, originalButtonScales[id] * selectedScale);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void OnSubmit()
|
|||
|
|
{
|
|||
|
|
if (selected == -1 || locked) return;
|
|||
|
|
locked = true;
|
|||
|
|
|
|||
|
|
foreach (Button b in answerButtons)
|
|||
|
|
b.interactable = false;
|
|||
|
|
|
|||
|
|
bool ok = (selected == correctIndex);
|
|||
|
|
|
|||
|
|
if (ok)
|
|||
|
|
{
|
|||
|
|
correctCount++;
|
|||
|
|
combo++;
|
|||
|
|
score += 50 + combo * 10;
|
|||
|
|
|
|||
|
|
Image img = answerButtons[selected].image;
|
|||
|
|
if (img != null)
|
|||
|
|
img.color = FullAlpha(correctColor);
|
|||
|
|
|
|||
|
|
StartCoroutine(CorrectPulse(answerButtons[selected], selected));
|
|||
|
|
|
|||
|
|
feedbackText.color = FullAlpha(correctColor);
|
|||
|
|
feedbackText.text = combo >= 3 ? $"TRUE {combo}x COMBO!" : "TRUE";
|
|||
|
|
|
|||
|
|
timeLeft += 2f;
|
|||
|
|
|
|||
|
|
if (comboText != null) StartCoroutine(ComboAnim(comboText));
|
|||
|
|
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
wrongCount++;
|
|||
|
|
combo = 0;
|
|||
|
|
|
|||
|
|
Image selImg = answerButtons[selected].image;
|
|||
|
|
if (selImg != null)
|
|||
|
|
selImg.color = FullAlpha(wrongColor);
|
|||
|
|
|
|||
|
|
StartCoroutine(ShakeButton(answerButtons[selected], selected));
|
|||
|
|
|
|||
|
|
Image corImg = answerButtons[correctIndex].image;
|
|||
|
|
if (corImg != null)
|
|||
|
|
corImg.color = FullAlpha(correctColor);
|
|||
|
|
|
|||
|
|
StartScaleAnim(correctIndex, originalButtonScales[correctIndex] * 1.04f);
|
|||
|
|
|
|||
|
|
feedbackText.color = FullAlpha(wrongColor);
|
|||
|
|
feedbackText.text = "FALSE";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
scoreText.text = score.ToString();
|
|||
|
|
comboText.text = combo + "x";
|
|||
|
|
|
|||
|
|
if (feedbackOnTop)
|
|||
|
|
{
|
|||
|
|
Vector3 pos = feedbackText.transform.localPosition;
|
|||
|
|
pos.y = feedbackTopY;
|
|||
|
|
feedbackText.transform.localPosition = pos;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
StartCoroutine(FeedbackAnim(feedbackText));
|
|||
|
|
|
|||
|
|
StartCoroutine(NextDelay());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
IEnumerator NextDelay()
|
|||
|
|
{
|
|||
|
|
yield return new WaitForSeconds(nextDelay);
|
|||
|
|
NextQuestion();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void OnHint()
|
|||
|
|
{
|
|||
|
|
if (locked) return;
|
|||
|
|
|
|||
|
|
Image img = answerButtons[correctIndex].image;
|
|||
|
|
if (img != null)
|
|||
|
|
img.color = FullAlpha(hintColor);
|
|||
|
|
|
|||
|
|
StartCoroutine(CorrectPulse(answerButtons[correctIndex], correctIndex));
|
|||
|
|
|
|||
|
|
feedbackText.color = FullAlpha(selectedColor);
|
|||
|
|
feedbackText.text = "Hint: Correct Answer Highlighted!";
|
|||
|
|
|
|||
|
|
if (feedbackOnTop)
|
|||
|
|
{
|
|||
|
|
Vector3 pos = feedbackText.transform.localPosition;
|
|||
|
|
pos.y = feedbackTopY;
|
|||
|
|
feedbackText.transform.localPosition = pos;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
StartCoroutine(FeedbackAnim(feedbackText));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void GameOver()
|
|||
|
|
{
|
|||
|
|
PlayerPrefs.SetString("LastPlayedMod", modKey);
|
|||
|
|
|
|||
|
|
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
|
|||
|
|
PlayerPrefs.SetInt("Mod4Skor", score);
|
|||
|
|
|
|||
|
|
// Bu oyundaki sonuçlar
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_LastCombo", combo);
|
|||
|
|
|
|||
|
|
// 🔥 En iyi skor (Mod Select / Leaderboard için)
|
|||
|
|
int oldMax = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
|||
|
|
if (score > oldMax)
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
|||
|
|
|
|||
|
|
// 🔥 En iyi combo
|
|||
|
|
int oldBestCombo = PlayerPrefs.GetInt(modKey + "_BestCombo", 0);
|
|||
|
|
if (combo > oldBestCombo)
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_BestCombo", combo);
|
|||
|
|
|
|||
|
|
// 🔥 Doğruluk oranı (%)
|
|||
|
|
int totalAnswers = correctCount + wrongCount;
|
|||
|
|
int accuracy = totalAnswers > 0 ? Mathf.RoundToInt((correctCount / (float)totalAnswers) * 100f) : 0;
|
|||
|
|
PlayerPrefs.SetInt(modKey + "_LastAccuracy", accuracy);
|
|||
|
|
|
|||
|
|
// 🔥 Toplam istatistikler
|
|||
|
|
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);
|
|||
|
|
|
|||
|
|
// 🔥 Genel toplam skor (Mod Select ekranındaki global leaderboard için)
|
|||
|
|
PlayerPrefs.SetInt("TotalScore", PlayerPrefs.GetInt("TotalScore", 0) + score);
|
|||
|
|
|
|||
|
|
PlayerPrefs.Save();
|
|||
|
|
|
|||
|
|
SceneManager.LoadScene("Mod4Resume");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
int GetLangIndex()
|
|||
|
|
{
|
|||
|
|
return lang switch
|
|||
|
|
{
|
|||
|
|
"tr" => 0,
|
|||
|
|
"en" => 1,
|
|||
|
|
"es" => 2,
|
|||
|
|
"de" => 3,
|
|||
|
|
"fr" => 4,
|
|||
|
|
"pt" => 5,
|
|||
|
|
_ => 1
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ------------------------------------------------
|
|||
|
|
void Shuffle<T>(IList<T> arr)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < arr.Count; i++)
|
|||
|
|
{
|
|||
|
|
int r = Random.Range(i, arr.Count);
|
|||
|
|
(arr[i], arr[r]) = (arr[r], arr[i]);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ================== ANIMATION HELPERS ==================
|
|||
|
|
|
|||
|
|
void UpdateTimerUI()
|
|||
|
|
{
|
|||
|
|
if (timerText == null) return;
|
|||
|
|
|
|||
|
|
timerText.text = Mathf.Ceil(timeLeft).ToString();
|
|||
|
|
|
|||
|
|
if (timeLeft <= 10f)
|
|||
|
|
{
|
|||
|
|
timerText.color = FullAlpha(Color.Lerp(timerWarnColor, 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 StartScaleAnim(int index, Vector3 targetScale)
|
|||
|
|
{
|
|||
|
|
if (index < 0 || index >= answerButtons.Length) return;
|
|||
|
|
if (answerButtons[index] == null) return;
|
|||
|
|
|
|||
|
|
if (buttonScaleCoroutines[index] != null)
|
|||
|
|
StopCoroutine(buttonScaleCoroutines[index]);
|
|||
|
|
|
|||
|
|
buttonScaleCoroutines[index] = StartCoroutine(ScaleButton(answerButtons[index], targetScale));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void StopButtonCoroutines(int index)
|
|||
|
|
{
|
|||
|
|
if (buttonScaleCoroutines != null && index < buttonScaleCoroutines.Length && buttonScaleCoroutines[index] != null)
|
|||
|
|
{
|
|||
|
|
StopCoroutine(buttonScaleCoroutines[index]);
|
|||
|
|
buttonScaleCoroutines[index] = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (buttonEnterCoroutines != null && index < buttonEnterCoroutines.Length && buttonEnterCoroutines[index] != null)
|
|||
|
|
{
|
|||
|
|
StopCoroutine(buttonEnterCoroutines[index]);
|
|||
|
|
buttonEnterCoroutines[index] = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator ScaleButton(Button btn, Vector3 targetScale)
|
|||
|
|
{
|
|||
|
|
if (btn == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 startScale = btn.transform.localScale;
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / Mathf.Max(0.01f, selectAnimTime);
|
|||
|
|
btn.transform.localScale = Vector3.Lerp(startScale, targetScale, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
btn.transform.localScale = targetScale;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator ButtonEnterAnim(Button btn, int delayIndex)
|
|||
|
|
{
|
|||
|
|
if (btn == null) yield break;
|
|||
|
|
|
|||
|
|
int idx = System.Array.IndexOf(answerButtons, btn);
|
|||
|
|
if (idx < 0) yield break;
|
|||
|
|
|
|||
|
|
yield return new WaitForSeconds(delayIndex * 0.06f);
|
|||
|
|
|
|||
|
|
Vector3 targetPos = originalButtonPositions[idx];
|
|||
|
|
Vector3 startPos = targetPos + Vector3.up * 35f;
|
|||
|
|
|
|||
|
|
Vector3 targetScale = originalButtonScales[idx];
|
|||
|
|
Vector3 startScale = targetScale * 0.85f;
|
|||
|
|
|
|||
|
|
btn.transform.localPosition = startPos;
|
|||
|
|
btn.transform.localScale = startScale;
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / Mathf.Max(0.01f, enterAnimTime);
|
|||
|
|
|
|||
|
|
float ease = EaseOutBack(t);
|
|||
|
|
|
|||
|
|
btn.transform.localPosition = Vector3.Lerp(startPos, targetPos, ease);
|
|||
|
|
btn.transform.localScale = Vector3.Lerp(startScale, targetScale, ease);
|
|||
|
|
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
btn.transform.localPosition = targetPos;
|
|||
|
|
btn.transform.localScale = targetScale;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator CorrectPulse(Button btn, int idx)
|
|||
|
|
{
|
|||
|
|
if (btn == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 normal = originalButtonScales[idx];
|
|||
|
|
Vector3 big = normal * 1.12f;
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.12f;
|
|||
|
|
btn.transform.localScale = Vector3.Lerp(normal, big, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.12f;
|
|||
|
|
btn.transform.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
btn.transform.localScale = normal;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator ShakeButton(Button btn, int idx)
|
|||
|
|
{
|
|||
|
|
if (btn == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 origin = originalButtonPositions[idx];
|
|||
|
|
|
|||
|
|
float duration = 0.35f;
|
|||
|
|
float magnitude = 12f;
|
|||
|
|
float elapsed = 0f;
|
|||
|
|
|
|||
|
|
while (elapsed < duration)
|
|||
|
|
{
|
|||
|
|
float power = 1f - elapsed / duration;
|
|||
|
|
float x = Random.Range(-1f, 1f) * magnitude * power;
|
|||
|
|
|
|||
|
|
btn.transform.localPosition = origin + new Vector3(x, 0f, 0f);
|
|||
|
|
|
|||
|
|
elapsed += Time.deltaTime;
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
btn.transform.localPosition = origin;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator FeedbackAnim(TMP_Text txt)
|
|||
|
|
{
|
|||
|
|
if (txt == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 originalScale = txt.transform.localScale;
|
|||
|
|
Vector3 bigScale = originalScale * 1.18f;
|
|||
|
|
|
|||
|
|
Color c = FullAlpha(txt.color);
|
|||
|
|
c.a = 0f;
|
|||
|
|
txt.color = c;
|
|||
|
|
|
|||
|
|
Vector3 originalPos = txt.transform.localPosition;
|
|||
|
|
Vector3 startPos = originalPos + Vector3.down * 18f;
|
|||
|
|
|
|||
|
|
txt.transform.localPosition = startPos;
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.16f;
|
|||
|
|
|
|||
|
|
float ease = EaseOutBack(t);
|
|||
|
|
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(originalScale, bigScale, ease);
|
|||
|
|
txt.transform.localPosition = Vector3.Lerp(startPos, originalPos, ease);
|
|||
|
|
|
|||
|
|
c.a = Mathf.Clamp01(t);
|
|||
|
|
txt.color = c;
|
|||
|
|
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
c.a = 1f;
|
|||
|
|
txt.color = c;
|
|||
|
|
txt.transform.localPosition = originalPos;
|
|||
|
|
|
|||
|
|
t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.12f;
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(bigScale, originalScale, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
txt.transform.localScale = originalScale;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator ComboAnim(TMP_Text txt)
|
|||
|
|
{
|
|||
|
|
if (txt == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 original = txt.transform.localScale;
|
|||
|
|
Vector3 big = original * 1.22f;
|
|||
|
|
|
|||
|
|
Color baseColor = FullAlpha(txt.color);
|
|||
|
|
Color highlight = new Color32(255, 220, 50, 255);
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.12f;
|
|||
|
|
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(original, big, EaseOutBack(t));
|
|||
|
|
txt.color = FullAlpha(Color.Lerp(baseColor, highlight, t));
|
|||
|
|
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.14f;
|
|||
|
|
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(big, original, EaseOutQuad(t));
|
|||
|
|
txt.color = FullAlpha(Color.Lerp(highlight, baseColor, t));
|
|||
|
|
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
txt.transform.localScale = original;
|
|||
|
|
txt.color = baseColor;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator ScorePopAnim(TMP_Text txt)
|
|||
|
|
{
|
|||
|
|
if (txt == null) yield break;
|
|||
|
|
|
|||
|
|
Vector3 original = txt.transform.localScale;
|
|||
|
|
Vector3 big = original * 1.18f;
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.10f;
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(original, big, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.12f;
|
|||
|
|
txt.transform.localScale = Vector3.Lerp(big, original, EaseOutQuad(t));
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
txt.transform.localScale = original;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
IEnumerator FadeInText(TMP_Text txt)
|
|||
|
|
{
|
|||
|
|
if (txt == null) yield break;
|
|||
|
|
|
|||
|
|
Color c = FullAlpha(txt.color);
|
|||
|
|
c.a = 0f;
|
|||
|
|
txt.color = c;
|
|||
|
|
|
|||
|
|
float t = 0f;
|
|||
|
|
|
|||
|
|
while (t < 1f)
|
|||
|
|
{
|
|||
|
|
t += Time.deltaTime / 0.18f;
|
|||
|
|
c.a = EaseOutQuad(t);
|
|||
|
|
txt.color = c;
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
c.a = 1f;
|
|||
|
|
txt.color = c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Color FullAlpha(Color c)
|
|||
|
|
{
|
|||
|
|
c.a = 1f;
|
|||
|
|
return c;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
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);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
float EaseOutQuad(float t)
|
|||
|
|
{
|
|||
|
|
t = Mathf.Clamp01(t);
|
|||
|
|
return 1f - (1f - t) * (1f - t);
|
|||
|
|
}
|
|||
|
|
}
|