Snapshot of the existing Unity 6 language-learning word game before any refactoring. Adds Unity .gitignore and .gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1127 lines
No EOL
31 KiB
C#
1127 lines
No EOL
31 KiB
C#
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using TMPro;
|
||
using UnityEngine.SceneManagement;
|
||
using System.Collections.Generic;
|
||
using System.Collections;
|
||
|
||
public class GalaxyGameScene : MonoBehaviour
|
||
{
|
||
[Header("━━━ TXT DOSYASI ━━━━━━━━━━━━━━━━━━━━━━━")]
|
||
public TextAsset wordFile;
|
||
|
||
[Header("━━━ UI ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")]
|
||
public TMP_Text questionText;
|
||
public Button[] answerButtons;
|
||
public TMP_Text[] answerTexts;
|
||
public TMP_Text feedbackText;
|
||
public Button submitButton;
|
||
public TMP_Text scoreText;
|
||
public TMP_Text comboText;
|
||
public TMP_Text timerText;
|
||
|
||
[Header("━━━ EXTRA BUTONLAR ━━━━━━━━━━━━━━━━━━━━")]
|
||
public Button extraTimeButton;
|
||
public Button extraHintButton;
|
||
public Button extraSkipButton;
|
||
public TMP_Text extraTimeCooldownText;
|
||
public TMP_Text extraHintCooldownText;
|
||
public TMP_Text extraSkipCooldownText;
|
||
|
||
[Header("━━━ BACK BUTONU ━━━━━━━━━━━━━━━━━━━━━━━")]
|
||
public Button backButton;
|
||
public string backSceneName = "ModSec 3";
|
||
|
||
[Header("━━━ RESULT SAHNESİ ━━━━━━━━━━━━━━━━━━━━")]
|
||
public string resultSceneName = "GalaxyResultScene";
|
||
|
||
[Header("━━━ GAME SETTINGS ━━━━━━━━━━━━━━━━━━━━━")]
|
||
public float startTime = 60f;
|
||
public int basePoints = 50;
|
||
public int wrongPenalty = 50;
|
||
public float correctTimeBonus = 2f;
|
||
|
||
[Header("━━━ COMBO ÇARPANLARI ━━━━━━━━━━━━━━━━━")]
|
||
public float mult_1to2 = 1f;
|
||
public float mult_3to4 = 1.15f;
|
||
public float mult_5to7 = 1.3f;
|
||
public float mult_8plus = 1.5f;
|
||
|
||
[Header("━━━ RENK AYARLARI ━━━━━━━━━━━━━━━━━━━━━")]
|
||
public Color normalButtonColor = new Color32(120, 70, 220, 255);
|
||
public Color selectedButtonColor = new Color32(155, 105, 255, 255);
|
||
public Color correctButtonColor = new Color32(70, 240, 130, 255);
|
||
public Color wrongButtonColor = new Color32(255, 80, 95, 255);
|
||
public Color disabledButtonColor = new Color32(90, 75, 120, 255);
|
||
|
||
[Header("━━━ BUTON TASARIM AYARI ━━━━━━━━━━━━━━")]
|
||
public bool butonRenginiKoru = true;
|
||
|
||
[Header("━━━ FEEDBACK YAZISI AYARLARI ━━━━━━━━━")]
|
||
public bool feedbackUsteAl = true;
|
||
public float feedbackTopY = 320f;
|
||
public float feedbackFontSize = 46f;
|
||
|
||
[Header("━━━ ANİMASYON AYARLARI ━━━━━━━━━━━━━━━━")]
|
||
[Range(0.80f, 1f)] public float selectedScale = 0.94f;
|
||
public float selectAnimTime = 0.10f;
|
||
public float enterAnimTime = 0.22f;
|
||
public float nextQuestionDelay = 1.15f;
|
||
|
||
float timeLeft;
|
||
bool gameOver = false;
|
||
bool waitingNextQuestion = false;
|
||
|
||
bool extraTimeReady = true;
|
||
bool extraHintReady = true;
|
||
bool extraSkipReady = true;
|
||
|
||
int correctAnswerIndex;
|
||
int selectedAnswer = -1;
|
||
|
||
int score = 0;
|
||
int combo = 0;
|
||
int correctCount = 0;
|
||
int wrongCount = 0;
|
||
|
||
readonly List<WordPair> wordPool = new List<WordPair>();
|
||
|
||
string questionLang;
|
||
string answerLang;
|
||
int wordIndex = 0;
|
||
|
||
Vector3[] originalButtonScales;
|
||
Vector3[] originalButtonPositions;
|
||
Coroutine[] buttonScaleCoroutines;
|
||
Coroutine[] buttonEnterCoroutines;
|
||
|
||
Color timerNormalColor = Color.white;
|
||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||
|
||
void Awake()
|
||
{
|
||
LoadWords();
|
||
}
|
||
|
||
void Start()
|
||
{
|
||
questionLang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||
answerLang = PlayerPrefs.GetString("AnswerLangCode", "tr");
|
||
|
||
timeLeft = PlayerPrefs.GetFloat("SelectedGameTime", startTime);
|
||
if (timeLeft <= 0) timeLeft = startTime;
|
||
|
||
if (wordPool.Count < 4)
|
||
{
|
||
Debug.LogError("Galaxy kelime sayısı yetersiz! En az 4 kelime olmalı.");
|
||
return;
|
||
}
|
||
|
||
HideCooldownTexts();
|
||
CacheButtonData();
|
||
ForceButtonTransitionNone();
|
||
PrepareFeedbackText();
|
||
BindMainButtons();
|
||
|
||
Shuffle(wordPool);
|
||
|
||
UpdateScore();
|
||
UpdateCombo();
|
||
UpdateTimerUI();
|
||
|
||
NextQuestion();
|
||
}
|
||
|
||
void Update()
|
||
{
|
||
if (gameOver) return;
|
||
|
||
timeLeft -= Time.deltaTime;
|
||
|
||
if (timeLeft <= 0)
|
||
{
|
||
timeLeft = 0;
|
||
UpdateTimerUI();
|
||
GameOver();
|
||
return;
|
||
}
|
||
|
||
UpdateTimerUI();
|
||
}
|
||
|
||
void LoadWords()
|
||
{
|
||
wordPool.Clear();
|
||
|
||
if (wordFile == null)
|
||
{
|
||
Debug.LogError("Galaxy wordFile atanmadı!");
|
||
return;
|
||
}
|
||
|
||
string[] lines = wordFile.text.Split(new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries);
|
||
|
||
foreach (string raw in lines)
|
||
{
|
||
string line = raw.Trim();
|
||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||
|
||
string[] p = line.Split(',');
|
||
|
||
if (p.Length < 6)
|
||
{
|
||
Debug.LogWarning("Eksik Galaxy kelime satırı atlandı: " + line);
|
||
continue;
|
||
}
|
||
|
||
wordPool.Add(new WordPair(
|
||
p[0].Trim(),
|
||
p[1].Trim(),
|
||
p[2].Trim(),
|
||
p[3].Trim(),
|
||
p[4].Trim(),
|
||
p[5].Trim()
|
||
));
|
||
}
|
||
}
|
||
|
||
void HideCooldownTexts()
|
||
{
|
||
if (extraTimeCooldownText != null) extraTimeCooldownText.gameObject.SetActive(false);
|
||
if (extraHintCooldownText != null) extraHintCooldownText.gameObject.SetActive(false);
|
||
if (extraSkipCooldownText != null) extraSkipCooldownText.gameObject.SetActive(false);
|
||
}
|
||
|
||
void BindMainButtons()
|
||
{
|
||
if (submitButton != null)
|
||
{
|
||
submitButton.onClick.RemoveAllListeners();
|
||
submitButton.onClick.AddListener(OnSubmit);
|
||
}
|
||
|
||
if (extraTimeButton != null)
|
||
{
|
||
extraTimeButton.onClick.RemoveAllListeners();
|
||
extraTimeButton.onClick.AddListener(OnExtraTime);
|
||
}
|
||
|
||
if (extraHintButton != null)
|
||
{
|
||
extraHintButton.onClick.RemoveAllListeners();
|
||
extraHintButton.onClick.AddListener(OnExtraHint);
|
||
}
|
||
|
||
if (extraSkipButton != null)
|
||
{
|
||
extraSkipButton.onClick.RemoveAllListeners();
|
||
extraSkipButton.onClick.AddListener(OnExtraSkip);
|
||
}
|
||
|
||
if (backButton != null)
|
||
{
|
||
backButton.onClick.RemoveAllListeners();
|
||
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
||
}
|
||
}
|
||
|
||
void CacheButtonData()
|
||
{
|
||
if (answerButtons == null) return;
|
||
|
||
originalButtonScales = new Vector3[answerButtons.Length];
|
||
originalButtonPositions = new Vector3[answerButtons.Length];
|
||
buttonScaleCoroutines = new Coroutine[answerButtons.Length];
|
||
buttonEnterCoroutines = new Coroutine[answerButtons.Length];
|
||
|
||
for (int i = 0; i < answerButtons.Length; 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(normalButtonColor);
|
||
|
||
CanvasGroup cg = answerButtons[i].GetComponent<CanvasGroup>();
|
||
if (cg != null)
|
||
{
|
||
cg.alpha = 1f;
|
||
cg.interactable = true;
|
||
cg.blocksRaycasts = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
void PrepareFeedbackText()
|
||
{
|
||
if (feedbackText == null) return;
|
||
|
||
if (feedbackUsteAl)
|
||
{
|
||
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 NextQuestion()
|
||
{
|
||
if (gameOver) return;
|
||
if (wordPool.Count < 4) return;
|
||
|
||
waitingNextQuestion = false;
|
||
selectedAnswer = -1;
|
||
|
||
ResetButtons();
|
||
|
||
if (wordIndex >= wordPool.Count)
|
||
{
|
||
wordIndex = 0;
|
||
Shuffle(wordPool);
|
||
}
|
||
|
||
WordPair chosen = wordPool[wordIndex++];
|
||
|
||
if (questionText != null)
|
||
{
|
||
questionText.text = chosen.GetByCode(questionLang);
|
||
StartCoroutine(FadeInText(questionText));
|
||
}
|
||
|
||
correctAnswerIndex = Random.Range(0, 4);
|
||
|
||
if (answerTexts == null || answerTexts.Length < 4)
|
||
{
|
||
Debug.LogError("answerTexts en az 4 eleman olmalı.");
|
||
return;
|
||
}
|
||
|
||
answerTexts[correctAnswerIndex].text = chosen.GetByCode(answerLang);
|
||
|
||
List<WordPair> wrongPool = new List<WordPair>(wordPool);
|
||
wrongPool.Remove(chosen);
|
||
Shuffle(wrongPool);
|
||
|
||
int wrongIndex = 0;
|
||
|
||
for (int i = 0; i < 4; i++)
|
||
{
|
||
if (i == correctAnswerIndex) continue;
|
||
|
||
if (wrongIndex < wrongPool.Count)
|
||
{
|
||
answerTexts[i].text = wrongPool[wrongIndex].GetByCode(answerLang);
|
||
wrongIndex++;
|
||
}
|
||
}
|
||
|
||
BindAnswerButtons();
|
||
|
||
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 BindAnswerButtons()
|
||
{
|
||
if (answerButtons == null) return;
|
||
|
||
for (int i = 0; i < answerButtons.Length; i++)
|
||
{
|
||
int index = i;
|
||
|
||
if (answerButtons[i] == null) continue;
|
||
|
||
answerButtons[i].onClick.RemoveAllListeners();
|
||
answerButtons[i].onClick.AddListener(() => SelectAnswer(index));
|
||
}
|
||
}
|
||
|
||
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(normalButtonColor);
|
||
|
||
answerButtons[i].transform.localScale = originalButtonScales[i];
|
||
answerButtons[i].transform.localPosition = originalButtonPositions[i];
|
||
|
||
CanvasGroup cg = answerButtons[i].GetComponent<CanvasGroup>();
|
||
if (cg != null)
|
||
{
|
||
cg.alpha = 1f;
|
||
cg.interactable = true;
|
||
cg.blocksRaycasts = true;
|
||
}
|
||
}
|
||
|
||
if (feedbackText != null)
|
||
feedbackText.text = "";
|
||
|
||
if (submitButton != null)
|
||
submitButton.interactable = true;
|
||
}
|
||
|
||
void SelectAnswer(int index)
|
||
{
|
||
if (gameOver || waitingNextQuestion) return;
|
||
if (answerButtons == null) return;
|
||
if (index < 0 || index >= answerButtons.Length) return;
|
||
if (answerButtons[index] == null) return;
|
||
|
||
if (selectedAnswer == index)
|
||
return;
|
||
|
||
if (selectedAnswer >= 0 && selectedAnswer < answerButtons.Length)
|
||
{
|
||
Button oldButton = answerButtons[selectedAnswer];
|
||
|
||
if (oldButton != null)
|
||
{
|
||
Image oldImg = oldButton.image;
|
||
if (oldImg != null)
|
||
oldImg.color = FullAlpha(normalButtonColor);
|
||
|
||
StartScaleAnim(selectedAnswer, originalButtonScales[selectedAnswer]);
|
||
}
|
||
}
|
||
|
||
selectedAnswer = index;
|
||
|
||
Image img = answerButtons[index].image;
|
||
if (img != null)
|
||
img.color = FullAlpha(selectedButtonColor);
|
||
|
||
CanvasGroup cg = answerButtons[index].GetComponent<CanvasGroup>();
|
||
if (cg != null)
|
||
cg.alpha = 1f;
|
||
|
||
StartScaleAnim(index, originalButtonScales[index] * selectedScale);
|
||
}
|
||
|
||
void OnSubmit()
|
||
{
|
||
if (gameOver || waitingNextQuestion) return;
|
||
if (selectedAnswer == -1) return;
|
||
if (answerButtons == null) return;
|
||
|
||
waitingNextQuestion = true;
|
||
|
||
if (submitButton != null)
|
||
submitButton.interactable = false;
|
||
|
||
bool correct = selectedAnswer == correctAnswerIndex;
|
||
|
||
LockAnswerButtons();
|
||
|
||
if (correct)
|
||
HandleCorrectAnswer();
|
||
else
|
||
HandleWrongAnswer();
|
||
|
||
UpdateScore();
|
||
UpdateCombo();
|
||
|
||
StartCoroutine(DelayNext());
|
||
}
|
||
|
||
void LockAnswerButtons()
|
||
{
|
||
for (int i = 0; i < answerButtons.Length; i++)
|
||
{
|
||
if (answerButtons[i] == null) continue;
|
||
|
||
answerButtons[i].interactable = false;
|
||
|
||
CanvasGroup cg = answerButtons[i].GetComponent<CanvasGroup>();
|
||
if (cg != null)
|
||
cg.alpha = 1f;
|
||
|
||
if (i != selectedAnswer && i != correctAnswerIndex)
|
||
{
|
||
Image img = answerButtons[i].image;
|
||
if (img != null)
|
||
img.color = FullAlpha(normalButtonColor);
|
||
}
|
||
}
|
||
}
|
||
|
||
void HandleCorrectAnswer()
|
||
{
|
||
Button selectedButton = answerButtons[selectedAnswer];
|
||
|
||
if (selectedButton != null)
|
||
{
|
||
Image img = selectedButton.image;
|
||
|
||
if (img != null)
|
||
{
|
||
if (butonRenginiKoru)
|
||
img.color = FullAlpha(selectedButtonColor);
|
||
else
|
||
img.color = FullAlpha(correctButtonColor);
|
||
}
|
||
|
||
StartCoroutine(CorrectPulse(selectedButton, selectedAnswer));
|
||
}
|
||
|
||
combo++;
|
||
correctCount++;
|
||
|
||
int addScore = Mathf.RoundToInt(basePoints * GetComboMultiplier(combo));
|
||
score += addScore;
|
||
|
||
timeLeft += correctTimeBonus;
|
||
|
||
if (feedbackText != null)
|
||
{
|
||
feedbackText.color = FullAlpha(correctButtonColor);
|
||
feedbackText.text = combo >= 3 ? $"TRUE {combo}x COMBO!" : "TRUE ";
|
||
|
||
if (feedbackUsteAl)
|
||
{
|
||
Vector3 pos = feedbackText.transform.localPosition;
|
||
pos.y = feedbackTopY;
|
||
feedbackText.transform.localPosition = pos;
|
||
}
|
||
|
||
StartCoroutine(FeedbackAnim(feedbackText));
|
||
}
|
||
|
||
if (comboText != null) StartCoroutine(ComboAnim(comboText));
|
||
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
||
}
|
||
|
||
void HandleWrongAnswer()
|
||
{
|
||
Button selectedButton = answerButtons[selectedAnswer];
|
||
|
||
if (selectedButton != null)
|
||
{
|
||
Image selectedImg = selectedButton.image;
|
||
|
||
if (selectedImg != null)
|
||
{
|
||
if (butonRenginiKoru)
|
||
selectedImg.color = FullAlpha(selectedButtonColor);
|
||
else
|
||
selectedImg.color = FullAlpha(wrongButtonColor);
|
||
}
|
||
|
||
StartCoroutine(ShakeButton(selectedButton, selectedAnswer));
|
||
}
|
||
|
||
if (correctAnswerIndex >= 0 && correctAnswerIndex < answerButtons.Length)
|
||
{
|
||
Button correctButton = answerButtons[correctAnswerIndex];
|
||
|
||
if (correctButton != null)
|
||
{
|
||
Image correctImg = correctButton.image;
|
||
|
||
if (correctImg != null)
|
||
{
|
||
if (butonRenginiKoru)
|
||
correctImg.color = FullAlpha(normalButtonColor);
|
||
else
|
||
correctImg.color = FullAlpha(correctButtonColor);
|
||
}
|
||
|
||
StartScaleAnim(correctAnswerIndex, originalButtonScales[correctAnswerIndex] * 1.04f);
|
||
}
|
||
}
|
||
|
||
wrongCount++;
|
||
combo = 0;
|
||
|
||
score -= wrongPenalty;
|
||
if (score < 0) score = 0;
|
||
|
||
if (feedbackText != null)
|
||
{
|
||
feedbackText.color = FullAlpha(wrongButtonColor);
|
||
feedbackText.text = "FALSE";
|
||
|
||
if (feedbackUsteAl)
|
||
{
|
||
Vector3 pos = feedbackText.transform.localPosition;
|
||
pos.y = feedbackTopY;
|
||
feedbackText.transform.localPosition = pos;
|
||
}
|
||
|
||
StartCoroutine(FeedbackAnim(feedbackText));
|
||
}
|
||
}
|
||
|
||
IEnumerator DelayNext()
|
||
{
|
||
yield return new WaitForSeconds(nextQuestionDelay);
|
||
|
||
if (!gameOver)
|
||
NextQuestion();
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
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 UpdateScore()
|
||
{
|
||
if (scoreText != null)
|
||
scoreText.text = score.ToString();
|
||
}
|
||
|
||
void UpdateCombo()
|
||
{
|
||
if (comboText != null)
|
||
comboText.text = combo + "X Combo";
|
||
}
|
||
|
||
float GetComboMultiplier(int c)
|
||
{
|
||
if (c >= 8) return mult_8plus;
|
||
if (c >= 5) return mult_5to7;
|
||
if (c >= 3) return mult_3to4;
|
||
return mult_1to2;
|
||
}
|
||
|
||
void OnExtraTime()
|
||
{
|
||
if (!extraTimeReady || gameOver) return;
|
||
|
||
timeLeft += 5f;
|
||
extraTimeReady = false;
|
||
|
||
if (extraTimeButton != null)
|
||
extraTimeButton.interactable = false;
|
||
|
||
if (extraTimeCooldownText != null)
|
||
{
|
||
extraTimeCooldownText.gameObject.SetActive(true);
|
||
StartCoroutine(Cooldown(extraTimeCooldownText, extraTimeButton, () => extraTimeReady = true));
|
||
}
|
||
else
|
||
{
|
||
StartCoroutine(SimpleCooldown(extraTimeButton, () => extraTimeReady = true));
|
||
}
|
||
}
|
||
|
||
void OnExtraHint()
|
||
{
|
||
if (!extraHintReady || gameOver || waitingNextQuestion) return;
|
||
|
||
int removed = 0;
|
||
|
||
for (int i = 0; i < answerButtons.Length && removed < 2; i++)
|
||
{
|
||
if (i == correctAnswerIndex || i == selectedAnswer) continue;
|
||
if (answerButtons[i] == null) continue;
|
||
|
||
answerButtons[i].interactable = false;
|
||
|
||
CanvasGroup cg = answerButtons[i].GetComponent<CanvasGroup>();
|
||
if (cg != null)
|
||
cg.alpha = 1f;
|
||
|
||
Image img = answerButtons[i].image;
|
||
if (img != null)
|
||
img.color = FullAlpha(disabledButtonColor);
|
||
|
||
if (answerTexts != null && i < answerTexts.Length && answerTexts[i] != null)
|
||
answerTexts[i].text = "—";
|
||
|
||
removed++;
|
||
}
|
||
|
||
extraHintReady = false;
|
||
|
||
if (extraHintButton != null)
|
||
extraHintButton.interactable = false;
|
||
|
||
if (extraHintCooldownText != null)
|
||
{
|
||
extraHintCooldownText.gameObject.SetActive(true);
|
||
StartCoroutine(Cooldown(extraHintCooldownText, extraHintButton, () => extraHintReady = true));
|
||
}
|
||
else
|
||
{
|
||
StartCoroutine(SimpleCooldown(extraHintButton, () => extraHintReady = true));
|
||
}
|
||
}
|
||
|
||
void OnExtraSkip()
|
||
{
|
||
if (!extraSkipReady || gameOver || waitingNextQuestion) return;
|
||
|
||
NextQuestion();
|
||
|
||
extraSkipReady = false;
|
||
|
||
if (extraSkipButton != null)
|
||
extraSkipButton.interactable = false;
|
||
|
||
if (extraSkipCooldownText != null)
|
||
{
|
||
extraSkipCooldownText.gameObject.SetActive(true);
|
||
StartCoroutine(Cooldown(extraSkipCooldownText, extraSkipButton, () => extraSkipReady = true));
|
||
}
|
||
else
|
||
{
|
||
StartCoroutine(SimpleCooldown(extraSkipButton, () => extraSkipReady = true));
|
||
}
|
||
}
|
||
|
||
IEnumerator Cooldown(TMP_Text label, Button button, System.Action done)
|
||
{
|
||
float t = 5f;
|
||
|
||
while (t > 0f)
|
||
{
|
||
if (label != null)
|
||
label.text = Mathf.Ceil(t).ToString();
|
||
|
||
t -= Time.deltaTime;
|
||
yield return null;
|
||
}
|
||
|
||
if (label != null)
|
||
{
|
||
label.text = "";
|
||
label.gameObject.SetActive(false);
|
||
}
|
||
|
||
if (button != null)
|
||
button.interactable = true;
|
||
|
||
done?.Invoke();
|
||
}
|
||
|
||
IEnumerator SimpleCooldown(Button button, System.Action done)
|
||
{
|
||
yield return new WaitForSeconds(5f);
|
||
|
||
if (button != null)
|
||
button.interactable = true;
|
||
|
||
done?.Invoke();
|
||
}
|
||
|
||
void GameOver()
|
||
{
|
||
if (gameOver) return;
|
||
|
||
gameOver = true;
|
||
|
||
PlayerPrefs.SetInt("Mod3Score", score);
|
||
PlayerPrefs.SetInt("Mod3Correct", correctCount);
|
||
PlayerPrefs.SetInt("Mod3Wrong", wrongCount);
|
||
|
||
int best = PlayerPrefs.GetInt("BestScore_Mod3", 0);
|
||
if (score > best)
|
||
PlayerPrefs.SetInt("BestScore_Mod3", score);
|
||
|
||
int bestCombo = PlayerPrefs.GetInt("BestCombo_Mod3", 0);
|
||
if (combo > bestCombo)
|
||
PlayerPrefs.SetInt("BestCombo_Mod3", combo);
|
||
|
||
PlayerPrefs.SetInt("TotalCorrect_Mod3", PlayerPrefs.GetInt("TotalCorrect_Mod3", 0) + correctCount);
|
||
PlayerPrefs.SetInt("TotalWrong_Mod3", PlayerPrefs.GetInt("TotalWrong_Mod3", 0) + wrongCount);
|
||
PlayerPrefs.SetInt("PlayCount_Mod3", PlayerPrefs.GetInt("PlayCount_Mod3", 0) + 1);
|
||
|
||
int total = PlayerPrefs.GetInt("TotalScore", 0) + score;
|
||
PlayerPrefs.SetInt("TotalScore", total);
|
||
|
||
PlayerPrefs.Save();
|
||
|
||
SceneManager.LoadScene(resultSceneName);
|
||
}
|
||
|
||
Color FullAlpha(Color c)
|
||
{
|
||
c.a = 1f;
|
||
return c;
|
||
}
|
||
|
||
void Shuffle<T>(List<T> list)
|
||
{
|
||
for (int i = 0; i < list.Count; i++)
|
||
{
|
||
int rnd = Random.Range(i, list.Count);
|
||
T temp = list[i];
|
||
list[i] = list[rnd];
|
||
list[rnd] = temp;
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
class WordPair
|
||
{
|
||
public string tr;
|
||
public string en;
|
||
public string es;
|
||
public string de;
|
||
public string fr;
|
||
public string pt;
|
||
|
||
public WordPair(string tr, string en, string es, string de, string fr, string pt)
|
||
{
|
||
this.tr = tr;
|
||
this.en = en;
|
||
this.es = es;
|
||
this.de = de;
|
||
this.fr = fr;
|
||
this.pt = pt;
|
||
}
|
||
|
||
public string GetByCode(string code)
|
||
{
|
||
switch (code)
|
||
{
|
||
case "tr": return tr;
|
||
case "en": return en;
|
||
case "es": return es;
|
||
case "de": return de;
|
||
case "fr": return fr;
|
||
case "pt": return pt;
|
||
default: return en;
|
||
}
|
||
}
|
||
}
|
||
} |