starOfWords/Assets/Scripts/3.0/mod12/TFTranslationGameScene.cs
portakal ecb1c9edea Initial commit: Star of Words Unity project
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>
2026-07-05 15:31:20 +03:00

662 lines
No EOL
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
public class Mod12_TrueFalseGame : MonoBehaviour
{
[Header("TXT FILE (TR,EN,ES,DE,FR,PT)")]
public TextAsset analogyFile; // TXT dosyasını sürükle-bırak
[System.Serializable]
public class WordPair
{
public string tr, en, es, de, fr, 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 Get(string lang)
{
return lang switch
{
"tr" => tr,
"en" => en,
"es" => es,
"de" => de,
"fr" => fr,
"pt" => pt,
_ => en
};
}
}
// ================= UI =================
public TMP_Text wordText;
public TMP_Text feedbackText;
public TMP_Text scoreText;
public TMP_Text comboText;
public TMP_Text timerText;
public Button trueButton;
public Button falseButton;
public Button passButton;
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
public Button backButton;
public string backSceneName = "ModSec 12";
[Header("COLORS")]
public Color normalColor = new Color32(255, 255, 255, 40);
public Color selectedColor = new Color32(60, 120, 220, 255);
public Color correctColor = new Color32(0, 200, 0, 255);
public Color wrongColor = new Color32(200, 0, 0, 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;
// ================= Logic =================
private List<WordPair> words = new List<WordPair>();
private bool correctPair;
private bool locked = false;
private float timeLeft = 60f;
private int score = 0;
private int combo = 0;
private int correctCount = 0;
private int wrongCount = 0;
string qLang;
string aLang;
string modKey = "Mod12";
readonly Color timerNormalColor = Color.white;
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
Vector3 trueOriginalScale = Vector3.one;
Vector3 falseOriginalScale = Vector3.one;
Vector3 trueOriginalPos;
Vector3 falseOriginalPos;
Coroutine trueScaleCo;
Coroutine falseScaleCo;
Coroutine feedbackCo;
Coroutine wordFadeCo;
// ============================================================
void Start()
{
qLang = PlayerPrefs.GetString("QuestionLangCode", "en");
aLang = PlayerPrefs.GetString("AnswerLangCode", "tr");
CacheButtonData();
PrepareFeedbackText();
LoadTXT();
trueButton.onClick.AddListener(() => Answer(true));
falseButton.onClick.AddListener(() => Answer(false));
passButton.onClick.AddListener(Pass);
if (backButton != null)
{
backButton.onClick.RemoveAllListeners();
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
}
UpdateScore();
UpdateCombo();
NextQuestion();
}
// ============================================================
void Update()
{
if (!locked)
{
timeLeft -= Time.deltaTime;
if (timeLeft <= 0) GameOver();
}
UpdateTimerUI();
}
// ============================================================
void CacheButtonData()
{
if (trueButton != null)
{
trueOriginalScale = trueButton.transform.localScale;
trueOriginalPos = trueButton.transform.localPosition;
trueButton.transition = Selectable.Transition.None;
}
if (falseButton != null)
{
falseOriginalScale = falseButton.transform.localScale;
falseOriginalPos = falseButton.transform.localPosition;
falseButton.transition = Selectable.Transition.None;
}
}
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 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 LoadTXT()
{
words.Clear();
if (analogyFile == null)
{
wordText.text = "TXT NOT FOUND!";
return;
}
string raw = analogyFile.text.Replace("\r", "");
string[] lines = raw.Split('\n');
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line)) continue;
string[] p = line.Split(',');
if (p.Length != 6)
{
Debug.LogError("HATALI SATIR → Format TR,EN,ES,DE,FR,PT olmalı: " + line);
continue;
}
words.Add(new WordPair(
p[0].Trim(), p[1].Trim(), p[2].Trim(),
p[3].Trim(), p[4].Trim(), p[5].Trim()
));
}
if (words.Count < 2)
{
wordText.text = "YETERSİZ KELİME!";
}
}
// ============================================================
void NextQuestion()
{
if (words.Count < 2) return;
locked = false;
if (feedbackText != null)
feedbackText.text = "";
ResetColors();
WordPair w1 = words[Random.Range(0, words.Count)];
WordPair w2 = w1;
// %50 doğru / %50 yanlış
correctPair = (Random.value > 0.5f);
if (!correctPair)
{
WordPair temp;
do temp = words[Random.Range(0, words.Count)];
while (temp == w1);
w2 = temp;
}
// TEK TEXT EKLEME
wordText.text = $"{w1.Get(qLang)} = {w2.Get(aLang)}";
if (wordFadeCo != null) StopCoroutine(wordFadeCo);
wordFadeCo = StartCoroutine(FadeInText(wordText));
}
// ============================================================
void Answer(bool pickedTrue)
{
if (locked) return;
locked = true;
bool ok =
(pickedTrue && correctPair) ||
(!pickedTrue && !correctPair);
if (pickedTrue)
{
trueButton.image.color = FullAlpha(selectedColor);
StartScaleAnim(trueButton, ref trueScaleCo, trueOriginalScale * selectedScale);
}
else
{
falseButton.image.color = FullAlpha(selectedColor);
StartScaleAnim(falseButton, ref falseScaleCo, falseOriginalScale * selectedScale);
}
if (ok) Correct(pickedTrue);
else Wrong(pickedTrue);
Invoke(nameof(NextQuestion), 1f);
}
// ============================================================
void Correct(bool pickedTrue)
{
correctCount++;
combo++;
score += 50 + combo * 10;
timeLeft += 2f;
SetFeedback(combo >= 3 ? $"{Local("correct")} {combo}x COMBO!" : Local("correct"), correctColor);
Button btn = pickedTrue ? trueButton : falseButton;
Vector3 normalScale = pickedTrue ? trueOriginalScale : falseOriginalScale;
btn.image.color = FullAlpha(correctColor);
StartCoroutine(CorrectPulse(btn, normalScale));
if (comboText != null) StartCoroutine(ComboAnim(comboText));
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
UpdateScore();
UpdateCombo();
}
void Wrong(bool pickedTrue)
{
wrongCount++;
combo = 0;
score -= 20;
if (score < 0) score = 0;
SetFeedback(Local("wrong"), wrongColor);
Button btn = pickedTrue ? trueButton : falseButton;
Vector3 originalPos = pickedTrue ? trueOriginalPos : falseOriginalPos;
btn.image.color = FullAlpha(wrongColor);
StartCoroutine(ShakeButton(btn, originalPos));
UpdateScore();
UpdateCombo();
}
// ============================================================
void Pass()
{
if (locked) return;
combo = 0;
UpdateCombo();
NextQuestion();
}
void ResetColors()
{
if (trueScaleCo != null) { StopCoroutine(trueScaleCo); trueScaleCo = null; }
if (falseScaleCo != null) { StopCoroutine(falseScaleCo); falseScaleCo = null; }
trueButton.image.color = FullAlpha(normalColor);
falseButton.image.color = FullAlpha(normalColor);
trueButton.transform.localScale = trueOriginalScale;
falseButton.transform.localScale = falseOriginalScale;
trueButton.transform.localPosition = trueOriginalPos;
falseButton.transform.localPosition = falseOriginalPos;
}
void UpdateScore() => scoreText.text = score.ToString();
void UpdateCombo() => comboText.text = combo + "x";
// ============================================================
void GameOver()
{
// Son elde edilen skor
int lastScore = score;
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
PlayerPrefs.SetInt("Mod12Skor", lastScore);
// Mevcut max skoru oku (yoksa 0)
int maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
// Eğer yeni skor daha yüksekse güncelle
if (lastScore > maxScore)
{
PlayerPrefs.SetInt(modKey + "_MaxScore", lastScore);
}
// Temel kayıtlar
PlayerPrefs.SetInt(modKey + "_Score", lastScore);
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
PlayerPrefs.Save();
// Resume sahnesine git
SceneManager.LoadScene("Mod12Resume");
}
// ============================================================
string Local(string key)
{
int L = PlayerPrefs.GetInt("AppLanguage", 1);
if (key == "correct")
return new[] { "Doğru!", "Correct!", "¡Correcto!", "Richtig!", "Correct!", "Correto!" }[L];
if (key == "wrong")
return new[] { "Yanlış!", "Wrong!", "¡Incorrecto!", "Falsch!", "Faux!", "Errado!" }[L];
return key;
}
// ================== ANIMATION HELPERS ==================
void SetFeedback(string msg, Color c)
{
if (feedbackText == null) return;
feedbackText.text = msg;
feedbackText.color = FullAlpha(c);
if (feedbackOnTop)
{
Vector3 pos = feedbackText.transform.localPosition;
pos.y = feedbackTopY;
feedbackText.transform.localPosition = pos;
}
if (feedbackCo != null) StopCoroutine(feedbackCo);
feedbackCo = StartCoroutine(FeedbackAnim(feedbackText));
}
void StartScaleAnim(Button btn, ref Coroutine co, Vector3 targetScale)
{
if (btn == null) return;
if (co != null) StopCoroutine(co);
co = StartCoroutine(ScaleButton(btn, targetScale));
}
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 CorrectPulse(Button btn, Vector3 normal)
{
if (btn == null) yield break;
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, Vector3 origin)
{
if (btn == null) yield break;
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 = Vector3.one;
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;
feedbackCo = null;
}
IEnumerator ComboAnim(TMP_Text txt)
{
if (txt == null) yield break;
Vector3 original = Vector3.one;
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 = Vector3.one;
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;
wordFadeCo = null;
}
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);
}
}