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>
This commit is contained in:
commit
ecb1c9edea
1455 changed files with 933295 additions and 0 deletions
8
Assets/Scripts/3.0/Mod4.meta
Normal file
8
Assets/Scripts/3.0/Mod4.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 361cc2564c58fe6449c1822064d12c32
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
804
Assets/Scripts/3.0/Mod4/ClozeGameScene.cs
Normal file
804
Assets/Scripts/3.0/Mod4/ClozeGameScene.cs
Normal file
|
|
@ -0,0 +1,804 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod4/ClozeGameScene.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod4/ClozeGameScene.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e2fc2555785ff244ca431198dfe8bc21
|
||||
168
Assets/Scripts/3.0/Mod4/Mod4Resume.cs
Normal file
168
Assets/Scripts/3.0/Mod4/Mod4Resume.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod4Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
// Bu modun kendi ana anahtarı
|
||||
private string modKey = "Mod4";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log("MOD4 RESULT → " +
|
||||
$"Score:{score} | Max:{maxScore} | C:{correct} | W:{wrong}");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
// pop-in scale
|
||||
Vector3 normal = Vector3.one;
|
||||
float t = 0f;
|
||||
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, normal, EaseOutBack(t));
|
||||
|
||||
if (targetValue == 0)
|
||||
txt.text = "0";
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = normal;
|
||||
|
||||
// count-up
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
int shown = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct)));
|
||||
txt.text = shown.ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void Retry()
|
||||
{
|
||||
// 🔥 MOD 4 OYUN SAHNESİNE GERİ DÖNÜŞ
|
||||
SceneManager.LoadScene("Mod4");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod4/Mod4Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod4/Mod4Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 323d69d6258982b41ad0ec9e34e0ba98
|
||||
8
Assets/Scripts/3.0/Mod5.meta
Normal file
8
Assets/Scripts/3.0/Mod5.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2b5728892019a2347bac5fea0b29df9a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
90
Assets/Scripts/3.0/Mod5/Mod5Resume.cs
Normal file
90
Assets/Scripts/3.0/Mod5/Mod5Resume.cs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod5Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
// 🔥 Bu modun özel ana key’i
|
||||
private string modKey = "Mod5";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
UpdateUI();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() =>
|
||||
{
|
||||
PlaySFX();
|
||||
Retry();
|
||||
});
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() =>
|
||||
{
|
||||
PlaySFX();
|
||||
ExitToMenu();
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log("MOD5 RESULT → " +
|
||||
$"Score:{score} | Max:{maxScore} | C:{correct} | W:{wrong}");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void UpdateUI()
|
||||
{
|
||||
if (scoreText != null) scoreText.text = score.ToString();
|
||||
if (maxScoreText != null) maxScoreText.text = maxScore.ToString();
|
||||
if (correctText != null) correctText.text = correct.ToString();
|
||||
if (wrongText != null) wrongText.text = wrong.ToString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void Retry()
|
||||
{
|
||||
// 🔥 Mod 5'in oyun sahnesine geri dönüş
|
||||
SceneManager.LoadScene("Mod5");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod5/Mod5Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod5/Mod5Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5aef591567d26be469298582b4dde11b
|
||||
1076
Assets/Scripts/3.0/Mod5/TetrisCategoryMod.cs
Normal file
1076
Assets/Scripts/3.0/Mod5/TetrisCategoryMod.cs
Normal file
File diff suppressed because it is too large
Load diff
2
Assets/Scripts/3.0/Mod5/TetrisCategoryMod.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod5/TetrisCategoryMod.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a63c8afea6ac9ef49808e75ed89dc7cb
|
||||
8
Assets/Scripts/3.0/Mod6.meta
Normal file
8
Assets/Scripts/3.0/Mod6.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8bddf192a36777c4f89d9bc2f7c58312
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
177
Assets/Scripts/3.0/Mod6/Mod6Resume.cs
Normal file
177
Assets/Scripts/3.0/Mod6/Mod6Resume.cs
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod6Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS")]
|
||||
public TMP_Text scoreText; // Toplam skor
|
||||
public TMP_Text maxScoreText; // En yüksek skor
|
||||
public TMP_Text correctText; // Doğru sayısı
|
||||
public TMP_Text wrongText; // Yanlış sayısı
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
// Mod6 PlayerPrefs Key
|
||||
private string modKey = "Mod6";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
// ============================================================
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
// Retry
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() =>
|
||||
{
|
||||
PlaySFX();
|
||||
Retry();
|
||||
});
|
||||
|
||||
// Exit
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() =>
|
||||
{
|
||||
PlaySFX();
|
||||
ExitToMenu();
|
||||
});
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log($"[MOD6 RESULT] Score={score} | Max={maxScore} | Correct={correct} | Wrong={wrong}");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
// pop-in scale
|
||||
Vector3 normal = Vector3.one;
|
||||
float t = 0f;
|
||||
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, normal, EaseOutBack(t));
|
||||
|
||||
if (targetValue == 0)
|
||||
txt.text = "0";
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = normal;
|
||||
|
||||
// count-up
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
int shown = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct)));
|
||||
txt.text = shown.ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void Retry()
|
||||
{
|
||||
SceneManager.LoadScene("Mod6");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod6/Mod6Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod6/Mod6Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7732f4a1c046d054cadae9b2b5482c31
|
||||
897
Assets/Scripts/3.0/Mod6/WordMatchMod.cs
Normal file
897
Assets/Scripts/3.0/Mod6/WordMatchMod.cs
Normal file
|
|
@ -0,0 +1,897 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class WordMatchMod : MonoBehaviour
|
||||
{
|
||||
[Header("UI - QUESTIONS (LEFT)")]
|
||||
[SerializeField] private Button[] questionButtons;
|
||||
[SerializeField] private TMP_Text[] questionTexts;
|
||||
|
||||
[Header("UI - ANSWERS (RIGHT)")]
|
||||
[SerializeField] private Button[] answerButtons;
|
||||
[SerializeField] private TMP_Text[] answerTexts;
|
||||
|
||||
[Header("UI - OTHER")]
|
||||
[SerializeField] private Button submitButton;
|
||||
[SerializeField] private TMP_Text scoreText;
|
||||
[SerializeField] private TMP_Text comboText;
|
||||
[SerializeField] private TMP_Text timeText;
|
||||
[SerializeField] private TMP_Text feedbackText;
|
||||
|
||||
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
|
||||
public Button backButton;
|
||||
public string backSceneName = "ModSec 6";
|
||||
|
||||
[Header("WORD DATA")]
|
||||
[SerializeField] private TextAsset wordFile;
|
||||
|
||||
[Header("COLORS")]
|
||||
public Color baseColor = new Color32(230, 230, 230, 255);
|
||||
public Color[] pairColors = new Color[]
|
||||
{
|
||||
new Color32(120,180,255,255),
|
||||
new Color32(255,200,120,255),
|
||||
new Color32(160,255,160,255),
|
||||
new Color32(255,150,150,255),
|
||||
new Color32(210,150,255,255),
|
||||
};
|
||||
|
||||
public Color correctColor = new Color32(0, 160, 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;
|
||||
public float enterAnimTime = 0.22f;
|
||||
|
||||
Dictionary<string, string> activeMap = new Dictionary<string, string>();
|
||||
List<KeyValuePair<string, string>> selectedPairs = new List<KeyValuePair<string, string>>();
|
||||
|
||||
private int[] questionToAnswer = new int[5];
|
||||
private int[] questionColorIdx = new int[5];
|
||||
private int[] answerColorIdx = new int[5];
|
||||
|
||||
private int selectedQuestion = -1;
|
||||
|
||||
// 🔥 90 saniyelik toplam süre, round başına sıfırlanmıyor
|
||||
private float timeLeft = 90f;
|
||||
|
||||
private int score = 0;
|
||||
private int combo = 0;
|
||||
private int correctCount = 0;
|
||||
private int wrongCount = 0;
|
||||
|
||||
// Durum kontrolü
|
||||
private bool isTimeUp = false; // süre tamamen bitti mi?
|
||||
private bool isRoundProcessing = false; // bu round için submit işlemi devam ediyor mu?
|
||||
|
||||
// PlayerPrefs Key
|
||||
private string modKey = "Mod6";
|
||||
|
||||
private string qLang;
|
||||
private string aLang;
|
||||
|
||||
readonly Color timerNormalColor = Color.white;
|
||||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||||
|
||||
Vector3[] questionOriginalScales;
|
||||
Vector3[] answerOriginalScales;
|
||||
Vector3[] questionOriginalPositions;
|
||||
Vector3[] answerOriginalPositions;
|
||||
|
||||
Coroutine[] questionScaleCo;
|
||||
Coroutine[] answerScaleCo;
|
||||
Coroutine[] questionEnterCo;
|
||||
Coroutine[] answerEnterCo;
|
||||
|
||||
Coroutine feedbackCo;
|
||||
|
||||
//---------------------------------------------------------
|
||||
void Start()
|
||||
{
|
||||
qLang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||||
aLang = PlayerPrefs.GetString("AnswerLangCode", "tr");
|
||||
|
||||
LoadWordFile();
|
||||
|
||||
CacheButtonData();
|
||||
PrepareFeedbackText();
|
||||
|
||||
if (submitButton != null)
|
||||
{
|
||||
submitButton.onClick.RemoveAllListeners();
|
||||
submitButton.onClick.AddListener(OnSubmit);
|
||||
}
|
||||
|
||||
if (backButton != null)
|
||||
{
|
||||
backButton.onClick.RemoveAllListeners();
|
||||
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
||||
}
|
||||
|
||||
LoadRound();
|
||||
ResetColorMaps();
|
||||
|
||||
// Oyun başlangıcı süresi
|
||||
timeLeft = 90f;
|
||||
isTimeUp = false;
|
||||
isRoundProcessing = false;
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void Update()
|
||||
{
|
||||
if (isTimeUp) // süre bittiyse artık hiçbir şey yapma
|
||||
{
|
||||
UpdateTimerUI();
|
||||
return;
|
||||
}
|
||||
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft < 0f) timeLeft = 0f;
|
||||
|
||||
UpdateTimerUI();
|
||||
|
||||
if (!isTimeUp && timeLeft <= 0f)
|
||||
{
|
||||
// Süre ilk kez bitti
|
||||
isTimeUp = true;
|
||||
ProcessSubmit(true); // timeout'tan gelen submit
|
||||
StartCoroutine(GoResume()); // sonuç sahnesine git
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void UpdateTimerUI()
|
||||
{
|
||||
if (timeText == null) return;
|
||||
|
||||
timeText.text = Mathf.CeilToInt(timeLeft).ToString();
|
||||
|
||||
if (timeLeft <= 10f)
|
||||
{
|
||||
timeText.color = FullAlpha(Color.Lerp(timerWarnColor, Color.white, Mathf.PingPong(Time.time * 3f, 1f)));
|
||||
timeText.transform.localScale = Vector3.one * (1f + Mathf.Sin(Time.time * 10f) * 0.05f);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText.color = FullAlpha(timerNormalColor);
|
||||
timeText.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void LoadWordFile()
|
||||
{
|
||||
activeMap.Clear();
|
||||
|
||||
string[] lines = wordFile.text.Split('\n');
|
||||
|
||||
int qi = LangIndex(qLang);
|
||||
int ai = LangIndex(aLang);
|
||||
|
||||
foreach (string raw in lines)
|
||||
{
|
||||
string line = raw.Trim();
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
if (!line.Contains(",")) continue;
|
||||
|
||||
string[] p = line.Split(',');
|
||||
if (p.Length < 6) continue;
|
||||
|
||||
string q = p[qi].Trim();
|
||||
string a = p[ai].Trim();
|
||||
|
||||
if (!activeMap.ContainsKey(q))
|
||||
activeMap.Add(q, a);
|
||||
}
|
||||
}
|
||||
|
||||
int LangIndex(string c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case "tr": return 0;
|
||||
case "en": return 1;
|
||||
case "es": return 2;
|
||||
case "de": return 3;
|
||||
case "fr": return 4;
|
||||
case "pt": return 5;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void CacheButtonData()
|
||||
{
|
||||
int n = questionButtons.Length;
|
||||
|
||||
questionOriginalScales = new Vector3[n];
|
||||
answerOriginalScales = new Vector3[n];
|
||||
questionOriginalPositions = new Vector3[n];
|
||||
answerOriginalPositions = new Vector3[n];
|
||||
|
||||
questionScaleCo = new Coroutine[n];
|
||||
answerScaleCo = new Coroutine[n];
|
||||
questionEnterCo = new Coroutine[n];
|
||||
answerEnterCo = new Coroutine[n];
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (questionButtons[i] != null)
|
||||
{
|
||||
questionOriginalScales[i] = questionButtons[i].transform.localScale;
|
||||
questionOriginalPositions[i] = questionButtons[i].transform.localPosition;
|
||||
questionButtons[i].transition = Selectable.Transition.None;
|
||||
}
|
||||
|
||||
if (answerButtons[i] != null)
|
||||
{
|
||||
answerOriginalScales[i] = answerButtons[i].transform.localScale;
|
||||
answerOriginalPositions[i] = answerButtons[i].transform.localPosition;
|
||||
answerButtons[i].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 LoadRound()
|
||||
{
|
||||
ResetVisuals();
|
||||
ResetColorMaps();
|
||||
|
||||
isRoundProcessing = false; // yeni round için submit tekrar aktif
|
||||
|
||||
var all = activeMap.ToList();
|
||||
Shuffle(all);
|
||||
|
||||
selectedPairs = all.Take(5).ToList();
|
||||
|
||||
// Questions
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionTexts[i].text = selectedPairs[i].Key;
|
||||
|
||||
int id = i;
|
||||
questionButtons[i].onClick.RemoveAllListeners();
|
||||
questionButtons[i].onClick.AddListener(() => SelectQuestion(id));
|
||||
}
|
||||
|
||||
// Answers
|
||||
List<string> answers = selectedPairs.Select(x => x.Value).ToList();
|
||||
Shuffle(answers);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
answerTexts[i].text = answers[i];
|
||||
|
||||
int id = i;
|
||||
answerButtons[i].onClick.RemoveAllListeners();
|
||||
answerButtons[i].onClick.AddListener(() => SelectAnswer(id));
|
||||
}
|
||||
|
||||
// Enter animasyonları
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionEnterCo[i] != null) StopCoroutine(questionEnterCo[i]);
|
||||
questionEnterCo[i] = StartCoroutine(ButtonEnterAnim(questionButtons[i], questionOriginalScales[i], questionOriginalPositions[i], i, -1));
|
||||
|
||||
if (answerEnterCo[i] != null) StopCoroutine(answerEnterCo[i]);
|
||||
answerEnterCo[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], answerOriginalScales[i], answerOriginalPositions[i], i, 1));
|
||||
|
||||
if (questionTexts[i] != null) StartCoroutine(FadeInText(questionTexts[i]));
|
||||
if (answerTexts[i] != null) StartCoroutine(FadeInText(answerTexts[i]));
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void ResetVisuals()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
StopButtonAnims(i);
|
||||
|
||||
questionButtons[i].image.color = FullAlpha(baseColor);
|
||||
answerButtons[i].image.color = FullAlpha(baseColor);
|
||||
|
||||
questionButtons[i].transform.localScale = questionOriginalScales[i];
|
||||
answerButtons[i].transform.localScale = answerOriginalScales[i];
|
||||
|
||||
questionButtons[i].transform.localPosition = questionOriginalPositions[i];
|
||||
answerButtons[i].transform.localPosition = answerOriginalPositions[i];
|
||||
}
|
||||
|
||||
feedbackText.text = "";
|
||||
}
|
||||
|
||||
void StopButtonAnims(int i)
|
||||
{
|
||||
if (questionScaleCo[i] != null) { StopCoroutine(questionScaleCo[i]); questionScaleCo[i] = null; }
|
||||
if (answerScaleCo[i] != null) { StopCoroutine(answerScaleCo[i]); answerScaleCo[i] = null; }
|
||||
if (questionEnterCo[i] != null) { StopCoroutine(questionEnterCo[i]); questionEnterCo[i] = null; }
|
||||
if (answerEnterCo[i] != null) { StopCoroutine(answerEnterCo[i]); answerEnterCo[i] = null; }
|
||||
}
|
||||
|
||||
void ResetColorMaps()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
answerColorIdx[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void SelectQuestion(int q)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
|
||||
selectedQuestion = q;
|
||||
|
||||
StartScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, q, questionOriginalScales[q] * selectedScale);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void SelectAnswer(int a)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
if (selectedQuestion == -1)
|
||||
return;
|
||||
|
||||
int prevQuestion = selectedQuestion;
|
||||
|
||||
// Aynı cevabı tekrar tıklarsa iptal et
|
||||
if (questionToAnswer[selectedQuestion] == a)
|
||||
{
|
||||
questionToAnswer[selectedQuestion] = -1;
|
||||
questionColorIdx[selectedQuestion] = -1;
|
||||
answerColorIdx[a] = -1;
|
||||
RefreshColors();
|
||||
selectedQuestion = -1;
|
||||
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, a);
|
||||
return;
|
||||
}
|
||||
|
||||
// Bu cevap başka bir soruya atanmışsa oradan kaldır
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionToAnswer[i] == a && i != selectedQuestion)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Önceden seçilmiş cevabı temizle
|
||||
int oldAns = questionToAnswer[selectedQuestion];
|
||||
if (oldAns != -1)
|
||||
{
|
||||
answerColorIdx[oldAns] = -1;
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, oldAns);
|
||||
}
|
||||
|
||||
// Yeni eşleşmeyi ata
|
||||
questionToAnswer[selectedQuestion] = a;
|
||||
|
||||
int colorIdx = selectedQuestion;
|
||||
questionColorIdx[selectedQuestion] = colorIdx;
|
||||
answerColorIdx[a] = colorIdx;
|
||||
|
||||
RefreshColors();
|
||||
|
||||
// pair pulse animasyonu
|
||||
StartCoroutine(PairPulse(prevQuestion, a));
|
||||
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
|
||||
selectedQuestion = -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void RefreshColors()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionButtons[i].image.color =
|
||||
questionColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[questionColorIdx[i]]);
|
||||
|
||||
answerButtons[i].image.color =
|
||||
answerColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[answerColorIdx[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Butondan gelen submit
|
||||
void OnSubmit()
|
||||
{
|
||||
// Eğer bu round zaten işleniyorsa veya süre bittiyse tekrar işleme
|
||||
if (isRoundProcessing || isTimeUp)
|
||||
return;
|
||||
|
||||
ProcessSubmit(false);
|
||||
}
|
||||
|
||||
// Asıl hesaplamayı yapan fonksiyon
|
||||
void ProcessSubmit(bool fromTimeout)
|
||||
{
|
||||
isRoundProcessing = true;
|
||||
|
||||
int roundCorrect = 0;
|
||||
|
||||
for (int q = 0; q < 5; q++)
|
||||
{
|
||||
int a = questionToAnswer[q];
|
||||
|
||||
if (a == -1)
|
||||
{
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
wrongCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
string qWord = questionTexts[q].text;
|
||||
string correctA = activeMap[qWord];
|
||||
string chosen = answerTexts[a].text;
|
||||
|
||||
if (chosen == correctA)
|
||||
{
|
||||
roundCorrect++;
|
||||
correctCount++;
|
||||
questionButtons[q].image.color = FullAlpha(correctColor);
|
||||
answerButtons[a].image.color = FullAlpha(correctColor);
|
||||
|
||||
StartCoroutine(CorrectPulse(questionButtons[q], questionOriginalScales[q]));
|
||||
StartCoroutine(CorrectPulse(answerButtons[a], answerOriginalScales[a]));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrongCount++;
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
answerButtons[a].image.color = FullAlpha(wrongColor);
|
||||
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
StartCoroutine(ShakeButton(answerButtons[a], answerOriginalPositions[a]));
|
||||
}
|
||||
}
|
||||
|
||||
// Her doğru 20 puan
|
||||
int gainedScore = roundCorrect * 20;
|
||||
score += gainedScore;
|
||||
|
||||
Color feedbackColor;
|
||||
|
||||
if (roundCorrect == 5)
|
||||
{
|
||||
combo++;
|
||||
feedbackText.text = combo >= 2 ? $"PERFECT! {combo}x COMBO!" : "PERFECT!";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else if (roundCorrect > 0)
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "+" + gainedScore + " Puan";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "Try again!";
|
||||
feedbackColor = wrongColor;
|
||||
}
|
||||
|
||||
feedbackText.color = FullAlpha(feedbackColor);
|
||||
|
||||
if (feedbackOnTop)
|
||||
{
|
||||
Vector3 pos = feedbackText.transform.localPosition;
|
||||
pos.y = feedbackTopY;
|
||||
feedbackText.transform.localPosition = pos;
|
||||
}
|
||||
|
||||
if (feedbackCo != null) StopCoroutine(feedbackCo);
|
||||
feedbackCo = StartCoroutine(FeedbackAnim(feedbackText));
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
||||
if (combo > 0 && comboText != null) StartCoroutine(ComboAnim(comboText));
|
||||
|
||||
SaveProgress();
|
||||
|
||||
// Eğer bu timeout değilse ve oyun tamamen bitmediyse yeni round
|
||||
if (!fromTimeout && !isTimeUp)
|
||||
{
|
||||
StartCoroutine(NextRound());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void SaveProgress()
|
||||
{
|
||||
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
|
||||
PlayerPrefs.SetInt("Mod6Skor", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
||||
|
||||
int maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
if (score > maxScore)
|
||||
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
||||
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
||||
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
IEnumerator NextRound()
|
||||
{
|
||||
yield return new WaitForSeconds(0.8f);
|
||||
LoadRound();
|
||||
}
|
||||
|
||||
IEnumerator GoResume()
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
SceneManager.LoadScene("Mod6Resume");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
void Shuffle<T>(List<T> list)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
{
|
||||
int j = Random.Range(0, i + 1);
|
||||
(list[i], list[j]) = (list[j], list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ================== ANIMATION HELPERS ==================
|
||||
|
||||
void StartScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx, Vector3 targetScale)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
|
||||
if (coArr[idx] != null)
|
||||
StopCoroutine(coArr[idx]);
|
||||
|
||||
coArr[idx] = StartCoroutine(ScaleButton(buttons[idx], targetScale, idx, coArr));
|
||||
}
|
||||
|
||||
void ResetScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
|
||||
StartScaleAnim(buttons, coArr, originalScales, idx, originalScales[idx]);
|
||||
}
|
||||
|
||||
IEnumerator ScaleButton(Button btn, Vector3 targetScale, int idx, Coroutine[] coArr)
|
||||
{
|
||||
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;
|
||||
coArr[idx] = null;
|
||||
}
|
||||
|
||||
IEnumerator ButtonEnterAnim(Button btn, Vector3 targetScale, Vector3 targetPos, int delayIndex, int sideSign)
|
||||
{
|
||||
if (btn == null) yield break;
|
||||
|
||||
yield return new WaitForSeconds(delayIndex * 0.05f);
|
||||
|
||||
Vector3 startPos = targetPos + new Vector3(sideSign * 40f, 0f, 0f);
|
||||
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 PairPulse(int questionIdx, int answerIdx)
|
||||
{
|
||||
if (questionIdx >= 0 && questionIdx < questionButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(questionButtons[questionIdx].transform, questionOriginalScales[questionIdx]));
|
||||
|
||||
if (answerIdx >= 0 && answerIdx < answerButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(answerButtons[answerIdx].transform, answerOriginalScales[answerIdx]));
|
||||
}
|
||||
|
||||
IEnumerator QuickPulse(Transform tr, Vector3 normal)
|
||||
{
|
||||
if (tr == null) yield break;
|
||||
|
||||
Vector3 big = normal * 1.08f;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(normal, big, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
tr.localScale = normal;
|
||||
}
|
||||
|
||||
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 baseC = 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(baseC, 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, baseC, t));
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = original;
|
||||
txt.color = baseC;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod6/WordMatchMod.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod6/WordMatchMod.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8009dfdd6ea39fb4e8299d3815d05377
|
||||
8
Assets/Scripts/3.0/Mod8.meta
Normal file
8
Assets/Scripts/3.0/Mod8.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ec4dd0c0e48b6d445aac4329391489cc
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
152
Assets/Scripts/3.0/Mod8/Mod8Resume.cs
Normal file
152
Assets/Scripts/3.0/Mod8/Mod8Resume.cs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod8Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
private string modKey = "Mod8_Antonym";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
// ============================================================
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log($"[MOD8 RESULT] Score={score} | Max={maxScore} | Correct={correct} | Wrong={wrong}");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, Vector3.one, EaseOutBack(t));
|
||||
if (targetValue == 0) txt.text = "0";
|
||||
yield return null;
|
||||
}
|
||||
txt.transform.localScale = Vector3.one;
|
||||
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
txt.text = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct))).ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx != null && clickSound != null)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void Retry()
|
||||
{
|
||||
SceneManager.LoadScene("Mod8");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
float EaseOutBack(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float c1 = 1.70158f, 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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod8/Mod8Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod8/Mod8Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2aa39617cac61c542b3904ef06fefa38
|
||||
876
Assets/Scripts/3.0/Mod8/WordMatchMod8.cs
Normal file
876
Assets/Scripts/3.0/Mod8/WordMatchMod8.cs
Normal file
|
|
@ -0,0 +1,876 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class WordMatchMod8 : MonoBehaviour
|
||||
{
|
||||
[Header("UI - QUESTIONS (LEFT)")]
|
||||
[SerializeField] private Button[] questionButtons;
|
||||
[SerializeField] private TMP_Text[] questionTexts;
|
||||
|
||||
[Header("UI - ANSWERS (RIGHT)")]
|
||||
[SerializeField] private Button[] answerButtons;
|
||||
[SerializeField] private TMP_Text[] answerTexts;
|
||||
|
||||
[Header("UI - OTHER")]
|
||||
[SerializeField] private Button submitButton;
|
||||
[SerializeField] private TMP_Text scoreText;
|
||||
[SerializeField] private TMP_Text comboText;
|
||||
[SerializeField] private TMP_Text timeText;
|
||||
[SerializeField] private TMP_Text feedbackText;
|
||||
|
||||
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
|
||||
public Button backButton;
|
||||
public string backSceneName = "ModSec 8";
|
||||
|
||||
[Header("WORD DATA")]
|
||||
[SerializeField] private TextAsset wordFile;
|
||||
|
||||
[Header("COLORS")]
|
||||
public Color baseColor = new Color32(230, 230, 230, 255);
|
||||
|
||||
public Color[] pairColors = new Color[]
|
||||
{
|
||||
new Color32(120,180,255,255),
|
||||
new Color32(255,200,120,255),
|
||||
new Color32(160,255,160,255),
|
||||
new Color32(255,150,150,255),
|
||||
new Color32(210,150,255,255),
|
||||
};
|
||||
|
||||
public Color correctColor = new Color32(0, 160, 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;
|
||||
public float enterAnimTime = 0.22f;
|
||||
|
||||
Dictionary<string, string> activeMap = new Dictionary<string, string>();
|
||||
|
||||
private int[] questionToAnswer = new int[5];
|
||||
private int[] questionColorIdx = new int[5];
|
||||
private int[] answerColorIdx = new int[5];
|
||||
|
||||
private int selectedQuestion = -1;
|
||||
|
||||
private float timeLeft = 90f;
|
||||
private bool isTimeUp = false;
|
||||
private bool isRoundProcessing = false;
|
||||
|
||||
private int score = 0;
|
||||
private int combo = 0;
|
||||
private int correctCount = 0;
|
||||
private int wrongCount = 0;
|
||||
|
||||
private string modKey = "Mod8_Antonym";
|
||||
private string qLang;
|
||||
|
||||
private List<KeyValuePair<string, string>> selectedPairs = new List<KeyValuePair<string, string>>();
|
||||
|
||||
readonly Color timerNormalColor = Color.white;
|
||||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||||
|
||||
Vector3[] questionOriginalScales;
|
||||
Vector3[] answerOriginalScales;
|
||||
Vector3[] questionOriginalPositions;
|
||||
Vector3[] answerOriginalPositions;
|
||||
|
||||
Coroutine[] questionScaleCo;
|
||||
Coroutine[] answerScaleCo;
|
||||
Coroutine[] questionEnterCo;
|
||||
Coroutine[] answerEnterCo;
|
||||
|
||||
Coroutine feedbackCo;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void Start()
|
||||
{
|
||||
qLang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||||
|
||||
LoadWordFile();
|
||||
|
||||
CacheButtonData();
|
||||
PrepareFeedbackText();
|
||||
|
||||
if (submitButton != null)
|
||||
{
|
||||
submitButton.onClick.RemoveAllListeners();
|
||||
submitButton.onClick.AddListener(OnSubmit);
|
||||
}
|
||||
|
||||
if (backButton != null)
|
||||
{
|
||||
backButton.onClick.RemoveAllListeners();
|
||||
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
||||
}
|
||||
|
||||
ResetColorMaps();
|
||||
LoadRound();
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
timeLeft = 90f;
|
||||
isTimeUp = false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void Update()
|
||||
{
|
||||
if (isTimeUp)
|
||||
{
|
||||
UpdateTimerUI();
|
||||
return;
|
||||
}
|
||||
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft < 0f) timeLeft = 0f;
|
||||
|
||||
UpdateTimerUI();
|
||||
|
||||
if (timeLeft <= 0f)
|
||||
{
|
||||
isTimeUp = true;
|
||||
ProcessSubmit(true);
|
||||
StartCoroutine(GoResume());
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void UpdateTimerUI()
|
||||
{
|
||||
if (timeText == null) return;
|
||||
|
||||
timeText.text = Mathf.CeilToInt(timeLeft).ToString();
|
||||
|
||||
if (timeLeft <= 10f)
|
||||
{
|
||||
timeText.color = FullAlpha(Color.Lerp(timerWarnColor, Color.white, Mathf.PingPong(Time.time * 3f, 1f)));
|
||||
timeText.transform.localScale = Vector3.one * (1f + Mathf.Sin(Time.time * 10f) * 0.05f);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText.color = FullAlpha(timerNormalColor);
|
||||
timeText.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void LoadWordFile()
|
||||
{
|
||||
activeMap.Clear();
|
||||
|
||||
if (wordFile == null)
|
||||
{
|
||||
Debug.LogError("Mod8: wordFile atanmadı!");
|
||||
return;
|
||||
}
|
||||
|
||||
string[] lines = wordFile.text.Split('\n');
|
||||
int li = LangIndex(qLang);
|
||||
|
||||
for (int i = 0; i + 1 < lines.Length; i += 2)
|
||||
{
|
||||
string A = lines[i].Trim();
|
||||
string B = lines[i + 1].Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(A) || string.IsNullOrWhiteSpace(B)) continue;
|
||||
if (!A.Contains(",") || !B.Contains(",")) continue;
|
||||
|
||||
string[] wA = A.Split(',');
|
||||
string[] wB = B.Split(',');
|
||||
|
||||
if (wA.Length < 6 || wB.Length < 6) continue;
|
||||
|
||||
string q = wA[li].Trim();
|
||||
string a = wB[li].Trim();
|
||||
|
||||
if (!activeMap.ContainsKey(q))
|
||||
activeMap.Add(q, a);
|
||||
}
|
||||
}
|
||||
|
||||
int LangIndex(string c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case "tr": return 0;
|
||||
case "en": return 1;
|
||||
case "es": return 2;
|
||||
case "de": return 3;
|
||||
case "fr": return 4;
|
||||
case "pt": return 5;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void CacheButtonData()
|
||||
{
|
||||
int n = questionButtons.Length;
|
||||
|
||||
questionOriginalScales = new Vector3[n];
|
||||
answerOriginalScales = new Vector3[n];
|
||||
questionOriginalPositions = new Vector3[n];
|
||||
answerOriginalPositions = new Vector3[n];
|
||||
|
||||
questionScaleCo = new Coroutine[n];
|
||||
answerScaleCo = new Coroutine[n];
|
||||
questionEnterCo = new Coroutine[n];
|
||||
answerEnterCo = new Coroutine[n];
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (questionButtons[i] != null)
|
||||
{
|
||||
questionOriginalScales[i] = questionButtons[i].transform.localScale;
|
||||
questionOriginalPositions[i] = questionButtons[i].transform.localPosition;
|
||||
questionButtons[i].transition = Selectable.Transition.None;
|
||||
}
|
||||
|
||||
if (answerButtons[i] != null)
|
||||
{
|
||||
answerOriginalScales[i] = answerButtons[i].transform.localScale;
|
||||
answerOriginalPositions[i] = answerButtons[i].transform.localPosition;
|
||||
answerButtons[i].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 LoadRound()
|
||||
{
|
||||
ResetVisuals();
|
||||
ResetColorMaps();
|
||||
|
||||
isRoundProcessing = false;
|
||||
|
||||
var all = activeMap.ToList();
|
||||
Shuffle(all);
|
||||
|
||||
selectedPairs = all.Take(5).ToList();
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionTexts[i].text = selectedPairs[i].Key;
|
||||
|
||||
int id = i;
|
||||
questionButtons[i].onClick.RemoveAllListeners();
|
||||
questionButtons[i].onClick.AddListener(() => SelectQuestion(id));
|
||||
}
|
||||
|
||||
List<string> answers = selectedPairs.Select(p => p.Value).ToList();
|
||||
Shuffle(answers);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
answerTexts[i].text = answers[i];
|
||||
|
||||
int id = i;
|
||||
answerButtons[i].onClick.RemoveAllListeners();
|
||||
answerButtons[i].onClick.AddListener(() => SelectAnswer(id));
|
||||
}
|
||||
|
||||
// Enter animasyonları
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionEnterCo[i] != null) StopCoroutine(questionEnterCo[i]);
|
||||
questionEnterCo[i] = StartCoroutine(ButtonEnterAnim(questionButtons[i], questionOriginalScales[i], questionOriginalPositions[i], i, -1));
|
||||
|
||||
if (answerEnterCo[i] != null) StopCoroutine(answerEnterCo[i]);
|
||||
answerEnterCo[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], answerOriginalScales[i], answerOriginalPositions[i], i, 1));
|
||||
|
||||
if (questionTexts[i] != null) StartCoroutine(FadeInText(questionTexts[i]));
|
||||
if (answerTexts[i] != null) StartCoroutine(FadeInText(answerTexts[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void ResetVisuals()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
StopButtonAnims(i);
|
||||
|
||||
questionButtons[i].image.color = FullAlpha(baseColor);
|
||||
answerButtons[i].image.color = FullAlpha(baseColor);
|
||||
|
||||
questionButtons[i].transform.localScale = questionOriginalScales[i];
|
||||
answerButtons[i].transform.localScale = answerOriginalScales[i];
|
||||
|
||||
questionButtons[i].transform.localPosition = questionOriginalPositions[i];
|
||||
answerButtons[i].transform.localPosition = answerOriginalPositions[i];
|
||||
}
|
||||
|
||||
if (feedbackText != null)
|
||||
feedbackText.text = "";
|
||||
}
|
||||
|
||||
void StopButtonAnims(int i)
|
||||
{
|
||||
if (questionScaleCo[i] != null) { StopCoroutine(questionScaleCo[i]); questionScaleCo[i] = null; }
|
||||
if (answerScaleCo[i] != null) { StopCoroutine(answerScaleCo[i]); answerScaleCo[i] = null; }
|
||||
if (questionEnterCo[i] != null) { StopCoroutine(questionEnterCo[i]); questionEnterCo[i] = null; }
|
||||
if (answerEnterCo[i] != null) { StopCoroutine(answerEnterCo[i]); answerEnterCo[i] = null; }
|
||||
}
|
||||
|
||||
void ResetColorMaps()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
answerColorIdx[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void SelectQuestion(int q)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
|
||||
selectedQuestion = q;
|
||||
StartScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, q, questionOriginalScales[q] * selectedScale);
|
||||
}
|
||||
|
||||
void SelectAnswer(int a)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
if (selectedQuestion == -1) return;
|
||||
|
||||
int prevQuestion = selectedQuestion;
|
||||
|
||||
if (questionToAnswer[selectedQuestion] == a)
|
||||
{
|
||||
questionToAnswer[selectedQuestion] = -1;
|
||||
questionColorIdx[selectedQuestion] = -1;
|
||||
answerColorIdx[a] = -1;
|
||||
RefreshColors();
|
||||
selectedQuestion = -1;
|
||||
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, a);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionToAnswer[i] == a && i != selectedQuestion)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, i);
|
||||
}
|
||||
}
|
||||
|
||||
int oldA = questionToAnswer[selectedQuestion];
|
||||
if (oldA != -1)
|
||||
{
|
||||
answerColorIdx[oldA] = -1;
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, oldA);
|
||||
}
|
||||
|
||||
questionToAnswer[selectedQuestion] = a;
|
||||
|
||||
int c = selectedQuestion % pairColors.Length;
|
||||
questionColorIdx[selectedQuestion] = c;
|
||||
answerColorIdx[a] = c;
|
||||
|
||||
RefreshColors();
|
||||
|
||||
StartCoroutine(PairPulse(prevQuestion, a));
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
|
||||
selectedQuestion = -1;
|
||||
}
|
||||
|
||||
void RefreshColors()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionButtons[i].image.color =
|
||||
questionColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[questionColorIdx[i]]);
|
||||
|
||||
answerButtons[i].image.color =
|
||||
answerColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[answerColorIdx[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void OnSubmit()
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
ProcessSubmit(false);
|
||||
}
|
||||
|
||||
void ProcessSubmit(bool fromTimeout)
|
||||
{
|
||||
isRoundProcessing = true;
|
||||
|
||||
int roundCorrect = 0;
|
||||
|
||||
for (int q = 0; q < 5; q++)
|
||||
{
|
||||
int a = questionToAnswer[q];
|
||||
|
||||
if (a == -1)
|
||||
{
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
wrongCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
string qWord = questionTexts[q].text;
|
||||
string correctA = activeMap[qWord];
|
||||
string chosenA = answerTexts[a].text;
|
||||
|
||||
if (chosenA == correctA)
|
||||
{
|
||||
roundCorrect++;
|
||||
correctCount++;
|
||||
|
||||
questionButtons[q].image.color = FullAlpha(correctColor);
|
||||
answerButtons[a].image.color = FullAlpha(correctColor);
|
||||
|
||||
StartCoroutine(CorrectPulse(questionButtons[q], questionOriginalScales[q]));
|
||||
StartCoroutine(CorrectPulse(answerButtons[a], answerOriginalScales[a]));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrongCount++;
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
answerButtons[a].image.color = FullAlpha(wrongColor);
|
||||
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
StartCoroutine(ShakeButton(answerButtons[a], answerOriginalPositions[a]));
|
||||
}
|
||||
}
|
||||
|
||||
int gained = roundCorrect * 20;
|
||||
score += gained;
|
||||
|
||||
Color feedbackColor;
|
||||
|
||||
if (roundCorrect == 5)
|
||||
{
|
||||
combo++;
|
||||
feedbackText.text = combo >= 2 ? $"PERFECT! {combo}x COMBO!" : "PERFECT!";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else if (roundCorrect > 0)
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "+" + gained + " Points";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "Try Again!";
|
||||
feedbackColor = wrongColor;
|
||||
}
|
||||
|
||||
feedbackText.color = FullAlpha(feedbackColor);
|
||||
|
||||
if (feedbackOnTop)
|
||||
{
|
||||
Vector3 pos = feedbackText.transform.localPosition;
|
||||
pos.y = feedbackTopY;
|
||||
feedbackText.transform.localPosition = pos;
|
||||
}
|
||||
|
||||
if (feedbackCo != null) StopCoroutine(feedbackCo);
|
||||
feedbackCo = StartCoroutine(FeedbackAnim(feedbackText));
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
||||
if (combo > 0 && comboText != null) StartCoroutine(ComboAnim(comboText));
|
||||
|
||||
SaveProgress();
|
||||
|
||||
if (!fromTimeout)
|
||||
StartCoroutine(NextRound());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void SaveProgress()
|
||||
{
|
||||
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
|
||||
PlayerPrefs.SetInt("Mod8Skor", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
||||
|
||||
int best = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
if (score > best)
|
||||
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
||||
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
||||
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
IEnumerator NextRound()
|
||||
{
|
||||
yield return new WaitForSeconds(0.8f);
|
||||
LoadRound();
|
||||
}
|
||||
|
||||
IEnumerator GoResume()
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
SceneManager.LoadScene("Mod8Resume");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void Shuffle<T>(List<T> list)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
{
|
||||
int j = Random.Range(0, i + 1);
|
||||
(list[i], list[j]) = (list[j], list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ================== ANIMATION HELPERS ==================
|
||||
|
||||
void StartScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx, Vector3 targetScale)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
|
||||
if (coArr[idx] != null)
|
||||
StopCoroutine(coArr[idx]);
|
||||
|
||||
coArr[idx] = StartCoroutine(ScaleButton(buttons[idx], targetScale, idx, coArr));
|
||||
}
|
||||
|
||||
void ResetScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
StartScaleAnim(buttons, coArr, originalScales, idx, originalScales[idx]);
|
||||
}
|
||||
|
||||
IEnumerator ScaleButton(Button btn, Vector3 targetScale, int idx, Coroutine[] coArr)
|
||||
{
|
||||
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;
|
||||
coArr[idx] = null;
|
||||
}
|
||||
|
||||
IEnumerator ButtonEnterAnim(Button btn, Vector3 targetScale, Vector3 targetPos, int delayIndex, int sideSign)
|
||||
{
|
||||
if (btn == null) yield break;
|
||||
|
||||
yield return new WaitForSeconds(delayIndex * 0.05f);
|
||||
|
||||
Vector3 startPos = targetPos + new Vector3(sideSign * 40f, 0f, 0f);
|
||||
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 PairPulse(int questionIdx, int answerIdx)
|
||||
{
|
||||
if (questionIdx >= 0 && questionIdx < questionButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(questionButtons[questionIdx].transform, questionOriginalScales[questionIdx]));
|
||||
|
||||
if (answerIdx >= 0 && answerIdx < answerButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(answerButtons[answerIdx].transform, answerOriginalScales[answerIdx]));
|
||||
}
|
||||
|
||||
IEnumerator QuickPulse(Transform tr, Vector3 normal)
|
||||
{
|
||||
if (tr == null) yield break;
|
||||
|
||||
Vector3 big = normal * 1.08f;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(normal, big, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
tr.localScale = normal;
|
||||
}
|
||||
|
||||
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 baseC = 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(baseC, 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, baseC, t));
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = original;
|
||||
txt.color = baseC;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/Mod8/WordMatchMod8.cs.meta
Normal file
2
Assets/Scripts/3.0/Mod8/WordMatchMod8.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 24738b79935ff2e4684b1e2523827057
|
||||
8
Assets/Scripts/3.0/mod10.meta
Normal file
8
Assets/Scripts/3.0/mod10.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 15b1f064ebce8074c855ee805144ea4a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
82
Assets/Scripts/3.0/mod10/Mod10Resume.cs
Normal file
82
Assets/Scripts/3.0/mod10/Mod10Resume.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod10Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
// Bu modun kendi ana anahtarı
|
||||
private string modKey = "Mod10";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
UpdateUI();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log("MOD10 RESULT → " +
|
||||
$"Score:{score} | Max:{maxScore} | C:{correct} | W:{wrong}");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void UpdateUI()
|
||||
{
|
||||
if (scoreText != null) scoreText.text = score.ToString();
|
||||
if (maxScoreText != null) maxScoreText.text = maxScore.ToString();
|
||||
if (correctText != null) correctText.text = correct.ToString();
|
||||
if (wrongText != null) wrongText.text = wrong.ToString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void Retry()
|
||||
{
|
||||
// 🔥 MOD 10 OYUN SAHNESİNE GERİ DÖNÜŞ
|
||||
SceneManager.LoadScene("Mod10");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod10/Mod10Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/mod10/Mod10Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 943d61e94ac5fdc45b9ea6f4357d8d71
|
||||
807
Assets/Scripts/3.0/mod10/SentenceOrderGameScene.cs
Normal file
807
Assets/Scripts/3.0/mod10/SentenceOrderGameScene.cs
Normal file
|
|
@ -0,0 +1,807 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class SentenceOrderGameScene : 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 selectedWordsText;
|
||||
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 10";
|
||||
|
||||
[Header("RENKLER")]
|
||||
public Color normalColor = new Color32(255, 255, 255, 70);
|
||||
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);
|
||||
|
||||
[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
|
||||
private class SentenceEntry
|
||||
{
|
||||
public string[] sentence = new string[6];
|
||||
}
|
||||
|
||||
private List<SentenceEntry> questions = new List<SentenceEntry>();
|
||||
|
||||
private string[] correctWords;
|
||||
private string[] scrambledWords;
|
||||
|
||||
private int[] order;
|
||||
private int selectedCount = 0;
|
||||
|
||||
private bool locked = false;
|
||||
private int lastID = -1;
|
||||
|
||||
private int score = 0;
|
||||
private int combo = 0;
|
||||
private float timeLeft = 60f;
|
||||
private float nextTimer = 0f;
|
||||
|
||||
// LANGUAGE & MOD KEY
|
||||
private string lang;
|
||||
private string modKey = "Mod10";
|
||||
|
||||
// Counters
|
||||
private int correctCount = 0;
|
||||
private int wrongCount = 0;
|
||||
|
||||
readonly Color timerNormalColor = Color.white;
|
||||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||||
|
||||
Vector3[] originalButtonScales;
|
||||
Vector3[] originalButtonPositions;
|
||||
Coroutine[] buttonScaleCoroutines;
|
||||
Coroutine[] buttonEnterCoroutines;
|
||||
|
||||
Coroutine feedbackCo;
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void Start()
|
||||
{
|
||||
lang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||||
order = new int[answerButtons.Length];
|
||||
|
||||
if (questionFile == null)
|
||||
{
|
||||
Debug.LogError("SentenceOrderGameScene: TXT bağlanmamış!");
|
||||
return;
|
||||
}
|
||||
|
||||
CacheButtonData();
|
||||
PrepareFeedbackText();
|
||||
|
||||
LoadTXT(questionFile.text);
|
||||
Shuffle(questions);
|
||||
|
||||
submitButton.onClick.AddListener(OnSubmit);
|
||||
extraTimeButton.onClick.AddListener(() => timeLeft += 5f);
|
||||
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";
|
||||
|
||||
NextQuestion();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void Update()
|
||||
{
|
||||
if (!locked)
|
||||
{
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft <= 0)
|
||||
{
|
||||
timeLeft = 0;
|
||||
GameOver();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTimerUI();
|
||||
|
||||
if (locked && nextTimer > 0)
|
||||
{
|
||||
nextTimer -= Time.deltaTime;
|
||||
if (nextTimer <= 0)
|
||||
NextQuestion();
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
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;
|
||||
|
||||
answerButtons[i].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(string raw)
|
||||
{
|
||||
foreach (string line in raw.Trim().Split('\n'))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
|
||||
string[] p = line.Split(',');
|
||||
if (p.Length < 6) continue;
|
||||
|
||||
SentenceEntry e = new SentenceEntry();
|
||||
for (int i = 0; i < 6; i++)
|
||||
e.sentence[i] = p[i].Trim();
|
||||
|
||||
questions.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void NextQuestion()
|
||||
{
|
||||
nextTimer = 0f;
|
||||
locked = false;
|
||||
selectedCount = 0;
|
||||
|
||||
if (feedbackText != null)
|
||||
feedbackText.text = "";
|
||||
|
||||
if (selectedWordsText != null)
|
||||
selectedWordsText.text = "";
|
||||
|
||||
for (int i = 0; i < order.Length; i++)
|
||||
order[i] = 0;
|
||||
|
||||
for (int i = 0; i < answerButtons.Length; i++)
|
||||
{
|
||||
StopButtonCoroutines(i);
|
||||
|
||||
answerButtons[i].interactable = true;
|
||||
answerButtons[i].image.color = FullAlpha(normalColor);
|
||||
answerButtons[i].transform.localScale = originalButtonScales[i];
|
||||
answerButtons[i].transform.localPosition = originalButtonPositions[i];
|
||||
answerButtons[i].gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// random
|
||||
int qID = Random.Range(0, questions.Count);
|
||||
if (qID == lastID && questions.Count > 1)
|
||||
qID = (qID + 1) % questions.Count;
|
||||
lastID = qID;
|
||||
|
||||
SentenceEntry entry = questions[qID];
|
||||
int L = GetLangIndex();
|
||||
|
||||
string s = entry.sentence[L];
|
||||
questionText.text = s;
|
||||
StartCoroutine(FadeInText(questionText));
|
||||
|
||||
correctWords = s.Split(' ');
|
||||
|
||||
int wc = Mathf.Min(correctWords.Length, answerButtons.Length);
|
||||
System.Array.Resize(ref correctWords, wc);
|
||||
|
||||
scrambledWords = (string[])correctWords.Clone();
|
||||
Shuffle(scrambledWords);
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
{
|
||||
answerButtons[i].gameObject.SetActive(true);
|
||||
answerTexts[i].text = scrambledWords[i];
|
||||
|
||||
int id = i;
|
||||
answerButtons[i].onClick.RemoveAllListeners();
|
||||
answerButtons[i].onClick.AddListener(() => OnClickWord(id));
|
||||
|
||||
buttonEnterCoroutines[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], i));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void OnClickWord(int id)
|
||||
{
|
||||
if (locked) return;
|
||||
|
||||
int wc = correctWords.Length;
|
||||
|
||||
if (order[id] != 0)
|
||||
{
|
||||
int old = order[id];
|
||||
order[id] = 0;
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
if (order[i] > old)
|
||||
order[i]--;
|
||||
|
||||
selectedCount--;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedCount++;
|
||||
order[id] = selectedCount;
|
||||
}
|
||||
|
||||
RefreshUI();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void RefreshUI()
|
||||
{
|
||||
int wc = correctWords.Length;
|
||||
List<string> seq = new List<string>();
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
{
|
||||
if (order[i] > 0)
|
||||
{
|
||||
answerButtons[i].image.color = FullAlpha(selectedColor);
|
||||
answerTexts[i].text = order[i] + ". " + scrambledWords[i];
|
||||
|
||||
StartScaleAnim(i, originalButtonScales[i] * selectedScale);
|
||||
}
|
||||
else
|
||||
{
|
||||
answerButtons[i].image.color = FullAlpha(normalColor);
|
||||
answerTexts[i].text = scrambledWords[i];
|
||||
|
||||
StartScaleAnim(i, originalButtonScales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int orderNum = 1; orderNum <= wc; orderNum++)
|
||||
for (int j = 0; j < wc; j++)
|
||||
if (order[j] == orderNum)
|
||||
seq.Add(scrambledWords[j]);
|
||||
|
||||
if (selectedWordsText != null)
|
||||
selectedWordsText.text = string.Join(" | ", seq);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
void OnSubmit()
|
||||
{
|
||||
if (locked) return;
|
||||
|
||||
int wc = correctWords.Length;
|
||||
|
||||
if (selectedCount < wc)
|
||||
{
|
||||
SetFeedback("Select all words!", wrongColor);
|
||||
return;
|
||||
}
|
||||
|
||||
locked = true;
|
||||
|
||||
bool ok = true;
|
||||
|
||||
for (int orderNum = 1; orderNum <= wc; orderNum++)
|
||||
for (int i = 0; i < wc; i++)
|
||||
if (order[i] == orderNum && scrambledWords[i] != correctWords[orderNum - 1])
|
||||
ok = false;
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
answerButtons[i].interactable = false;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
correctCount++;
|
||||
combo++;
|
||||
|
||||
score += 50 + (combo - 1) * 10;
|
||||
timeLeft += 2f;
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
{
|
||||
answerButtons[i].image.color = FullAlpha(correctColor);
|
||||
StartCoroutine(CorrectPulse(answerButtons[i], i));
|
||||
}
|
||||
|
||||
SetFeedback(combo >= 3 ? $"TRUE {combo}x COMBO!" : "TRUE", correctColor);
|
||||
|
||||
if (comboText != null) StartCoroutine(ComboAnim(comboText));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrongCount++;
|
||||
combo = 0;
|
||||
|
||||
for (int i = 0; i < wc; i++)
|
||||
{
|
||||
answerButtons[i].image.color = FullAlpha(wrongColor);
|
||||
StartCoroutine(ShakeButton(answerButtons[i], i));
|
||||
}
|
||||
|
||||
SetFeedback("FALSE", wrongColor);
|
||||
}
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
||||
|
||||
nextTimer = 1f;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// HINT: İlk kelimeyi otomatik seçer
|
||||
// ------------------------------------------------------------
|
||||
void OnHint()
|
||||
{
|
||||
if (locked) return;
|
||||
|
||||
int wc = correctWords.Length;
|
||||
|
||||
// Önce tüm seçimleri sıfırla
|
||||
selectedCount = 0;
|
||||
for (int i = 0; i < wc; i++)
|
||||
order[i] = 0;
|
||||
|
||||
// Doğru ilk kelime
|
||||
string firstWord = correctWords[0];
|
||||
|
||||
// Scrambled içinde doğru kelimenin index'ini bul
|
||||
for (int i = 0; i < wc; i++)
|
||||
{
|
||||
if (scrambledWords[i] == firstWord)
|
||||
{
|
||||
order[i] = 1;
|
||||
selectedCount = 1;
|
||||
StartCoroutine(CorrectPulse(answerButtons[i], i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshUI();
|
||||
|
||||
SetFeedback("Hint used!", selectedColor);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
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 GameOver()
|
||||
{
|
||||
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
|
||||
PlayerPrefs.SetInt("Mod10Skor", score);
|
||||
|
||||
// kayıt sistemi
|
||||
PlayerPrefs.SetString("LastPlayedMod", modKey);
|
||||
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
||||
|
||||
int oldMax = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
if (score > oldMax)
|
||||
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
||||
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
||||
|
||||
PlayerPrefs.Save();
|
||||
|
||||
// 🔥 MOD 10 SONUÇ SAHNESİ
|
||||
SceneManager.LoadScene("Mod10Resume");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------
|
||||
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 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.05f);
|
||||
|
||||
Vector3 targetPos = originalButtonPositions[idx];
|
||||
Vector3 startPos = targetPos + Vector3.up * 30f;
|
||||
|
||||
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;
|
||||
if (idx < 0 || idx >= originalButtonScales.Length) 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;
|
||||
if (idx < 0 || idx >= originalButtonPositions.Length) 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 = 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod10/SentenceOrderGameScene.cs.meta
Normal file
2
Assets/Scripts/3.0/mod10/SentenceOrderGameScene.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5d1f4458536ed634b97019cf3c7abb27
|
||||
8
Assets/Scripts/3.0/mod11.meta
Normal file
8
Assets/Scripts/3.0/mod11.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5861da0019dff9a42a4a83d14f1722c8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
846
Assets/Scripts/3.0/mod11/AnalogyGameScene.cs
Normal file
846
Assets/Scripts/3.0/mod11/AnalogyGameScene.cs
Normal file
|
|
@ -0,0 +1,846 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class AnalogyLogicGameScene : MonoBehaviour
|
||||
{
|
||||
[Header("TXT (6 Language Analogy Data)")]
|
||||
public TextAsset analogyFile;
|
||||
|
||||
[Header("UI")]
|
||||
public TMP_Text questionText;
|
||||
public TMP_Text[] answerTexts;
|
||||
public Button[] answerButtons;
|
||||
public Button submitButton;
|
||||
|
||||
public TMP_Text feedbackText;
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text comboText;
|
||||
public TMP_Text timerText;
|
||||
public TMP_Text selectedWordsText;
|
||||
|
||||
[Header("EXTRAS")]
|
||||
public Button extraTimeButton;
|
||||
public Button extraHintButton;
|
||||
public Button extraSkipButton;
|
||||
|
||||
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
|
||||
public Button backButton;
|
||||
public string backSceneName = "ModSec 11";
|
||||
|
||||
[Header("COLORS")]
|
||||
public Color normalColor = new Color32(255, 255, 255, 70);
|
||||
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);
|
||||
|
||||
[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;
|
||||
|
||||
// 0=TR, 1=EN, 2=ES, 3=DE, 4=FR, 5=PT
|
||||
private string langCode; // "tr","en"...
|
||||
private int langIndex; // 0–5
|
||||
|
||||
private class AnalogyQ
|
||||
{
|
||||
// data[language, field] -> 0:A 1:B 2:C 3:COR 4:W1 5:W2 6:W3
|
||||
public string[,] data = new string[6, 7];
|
||||
}
|
||||
|
||||
private List<AnalogyQ> questions = new List<AnalogyQ>();
|
||||
|
||||
private int correctIndex = -1;
|
||||
private int selectedIndex = -1;
|
||||
private bool locked = false;
|
||||
private int lastQ = -1;
|
||||
|
||||
private int score = 0;
|
||||
private int combo = 0;
|
||||
private int correctCount = 0;
|
||||
private int wrongCount = 0;
|
||||
|
||||
private float timeLeft = 60f;
|
||||
private float nextTimer = 0f;
|
||||
|
||||
private string modKey = "Mod11";
|
||||
|
||||
readonly Color timerNormalColor = Color.white;
|
||||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||||
|
||||
Vector3[] originalButtonScales;
|
||||
Vector3[] originalButtonPositions;
|
||||
Coroutine[] buttonScaleCoroutines;
|
||||
Coroutine[] buttonEnterCoroutines;
|
||||
|
||||
Coroutine feedbackCo;
|
||||
|
||||
// ================================================================
|
||||
void Start()
|
||||
{
|
||||
// Uses the same system as SentenceOrderGameScene
|
||||
langCode = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||||
langIndex = GetLangIndex();
|
||||
|
||||
if (analogyFile == null)
|
||||
{
|
||||
Debug.LogError("AnalogyLogicGameScene: analogyFile is not assigned!");
|
||||
if (questionText != null)
|
||||
questionText.text = "TXT NOT FOUND!";
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
LoadTXT6Lang(analogyFile.text);
|
||||
|
||||
if (questions.Count == 0)
|
||||
{
|
||||
Debug.LogError("AnalogyLogicGameScene: TXT is empty or invalid!");
|
||||
if (questionText != null)
|
||||
questionText.text = "EMPTY FILE!";
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (answerButtons == null || answerButtons.Length < 4 ||
|
||||
answerTexts == null || answerTexts.Length < 4)
|
||||
{
|
||||
Debug.LogError("AnalogyLogicGameScene: 4 answerButtons / answerTexts are required.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CacheButtonData();
|
||||
PrepareFeedbackText();
|
||||
|
||||
Shuffle(questions);
|
||||
|
||||
if (submitButton != null)
|
||||
submitButton.onClick.AddListener(OnSubmit);
|
||||
if (extraTimeButton != null)
|
||||
extraTimeButton.onClick.AddListener(() => timeLeft += 5f);
|
||||
if (extraHintButton != null)
|
||||
extraHintButton.onClick.AddListener(OnHint);
|
||||
if (extraSkipButton != null)
|
||||
extraSkipButton.onClick.AddListener(NextQuestion);
|
||||
|
||||
if (backButton != null)
|
||||
{
|
||||
backButton.onClick.RemoveAllListeners();
|
||||
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
||||
}
|
||||
|
||||
if (scoreText != null)
|
||||
scoreText.text = "0";
|
||||
if (comboText != null)
|
||||
comboText.text = "0x";
|
||||
|
||||
NextQuestion();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
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;
|
||||
|
||||
answerButtons[i].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;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// 6-LANGUAGE BLOCK TXT READER
|
||||
// Each question: 6 lines (TR, EN, ES, DE, FR, PT)
|
||||
// Line format: A,B,C,COR,W1,W2,W3
|
||||
// ================================================================
|
||||
void LoadTXT6Lang(string raw)
|
||||
{
|
||||
string[] lines = raw.Split('\n');
|
||||
|
||||
for (int i = 0; i < lines.Length;)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(lines[i]))
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 5 >= lines.Length)
|
||||
break;
|
||||
|
||||
AnalogyQ q = new AnalogyQ();
|
||||
bool validBlock = true;
|
||||
|
||||
for (int L = 0; L < 6; L++)
|
||||
{
|
||||
string line = lines[i + L].Trim('\r', '\n', ' ');
|
||||
if (string.IsNullOrEmpty(line))
|
||||
{
|
||||
validBlock = false;
|
||||
break;
|
||||
}
|
||||
|
||||
string[] p = line.Split(',');
|
||||
if (p.Length != 7)
|
||||
{
|
||||
Debug.LogWarning($"AnalogyLogicGameScene: line {i + L} does not contain 7 parts, block skipped.");
|
||||
validBlock = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for (int k = 0; k < 7; k++)
|
||||
q.data[L, k] = p[k].Trim();
|
||||
}
|
||||
|
||||
if (validBlock)
|
||||
questions.Add(q);
|
||||
|
||||
i += 6;
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
void Update()
|
||||
{
|
||||
if (!locked)
|
||||
{
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft <= 0f)
|
||||
{
|
||||
timeLeft = 0f;
|
||||
GameOver();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateTimerUI();
|
||||
|
||||
if (locked && nextTimer > 0f)
|
||||
{
|
||||
nextTimer -= Time.deltaTime;
|
||||
if (nextTimer <= 0f)
|
||||
NextQuestion();
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
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 NextQuestion()
|
||||
{
|
||||
locked = false;
|
||||
selectedIndex = -1;
|
||||
nextTimer = 0f;
|
||||
|
||||
if (selectedWordsText != null)
|
||||
selectedWordsText.text = "";
|
||||
if (feedbackText != null)
|
||||
feedbackText.text = "";
|
||||
|
||||
for (int i = 0; i < answerButtons.Length; i++)
|
||||
{
|
||||
if (answerButtons[i] == null) continue;
|
||||
|
||||
StopButtonCoroutines(i);
|
||||
|
||||
answerButtons[i].interactable = true;
|
||||
answerButtons[i].transform.localScale = originalButtonScales[i];
|
||||
answerButtons[i].transform.localPosition = originalButtonPositions[i];
|
||||
|
||||
if (answerButtons[i].image != null)
|
||||
answerButtons[i].image.color = FullAlpha(normalColor);
|
||||
}
|
||||
|
||||
if (questions.Count == 0)
|
||||
{
|
||||
GameOver();
|
||||
return;
|
||||
}
|
||||
|
||||
int id = Random.Range(0, questions.Count);
|
||||
if (id == lastQ && questions.Count > 1)
|
||||
id = (id + 1) % questions.Count;
|
||||
|
||||
lastQ = id;
|
||||
AnalogyQ q = questions[id];
|
||||
|
||||
string A = q.data[langIndex, 0];
|
||||
string B = q.data[langIndex, 1];
|
||||
string C = q.data[langIndex, 2];
|
||||
string COR = q.data[langIndex, 3];
|
||||
string W1 = q.data[langIndex, 4];
|
||||
string W2 = q.data[langIndex, 5];
|
||||
string W3 = q.data[langIndex, 6];
|
||||
|
||||
if (questionText != null)
|
||||
{
|
||||
questionText.text = $"{A} : {B} = {C} : ?";
|
||||
StartCoroutine(FadeInText(questionText));
|
||||
}
|
||||
|
||||
List<string> opts = new List<string> { COR, W1, W2, W3 };
|
||||
Shuffle(opts);
|
||||
|
||||
correctIndex = opts.IndexOf(COR);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (answerTexts[i] != null)
|
||||
answerTexts[i].text = opts[i];
|
||||
|
||||
int x = i;
|
||||
if (answerButtons[i] != null)
|
||||
{
|
||||
answerButtons[i].onClick.RemoveAllListeners();
|
||||
answerButtons[i].onClick.AddListener(() => OnSelect(x));
|
||||
|
||||
buttonEnterCoroutines[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
void OnSelect(int id)
|
||||
{
|
||||
if (locked) return;
|
||||
if (selectedIndex == id) return;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < answerButtons.Length && answerButtons[selectedIndex] != null)
|
||||
{
|
||||
if (answerButtons[selectedIndex].image != null)
|
||||
answerButtons[selectedIndex].image.color = FullAlpha(normalColor);
|
||||
|
||||
StartScaleAnim(selectedIndex, originalButtonScales[selectedIndex]);
|
||||
}
|
||||
|
||||
selectedIndex = id;
|
||||
|
||||
if (answerButtons[id] != null)
|
||||
{
|
||||
if (answerButtons[id].image != null)
|
||||
answerButtons[id].image.color = FullAlpha(selectedColor);
|
||||
|
||||
StartScaleAnim(id, originalButtonScales[id] * selectedScale);
|
||||
}
|
||||
|
||||
if (selectedWordsText != null && answerTexts[id] != null)
|
||||
selectedWordsText.text = answerTexts[id].text;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
void OnSubmit()
|
||||
{
|
||||
if (locked) return;
|
||||
if (selectedIndex == -1) return;
|
||||
|
||||
locked = true;
|
||||
|
||||
bool ok = (selectedIndex == correctIndex);
|
||||
|
||||
foreach (var b in answerButtons)
|
||||
if (b != null) b.interactable = false;
|
||||
|
||||
if (ok)
|
||||
{
|
||||
correctCount++;
|
||||
combo++;
|
||||
score += 50 + combo * 10;
|
||||
timeLeft += 2f;
|
||||
|
||||
if (answerButtons[selectedIndex] != null && answerButtons[selectedIndex].image != null)
|
||||
answerButtons[selectedIndex].image.color = FullAlpha(correctColor);
|
||||
|
||||
StartCoroutine(CorrectPulse(answerButtons[selectedIndex], selectedIndex));
|
||||
|
||||
SetFeedback(combo >= 3 ? $"{Local("correct")} {combo}x COMBO!" : Local("correct"), correctColor);
|
||||
|
||||
if (comboText != null) StartCoroutine(ComboAnim(comboText));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrongCount++;
|
||||
combo = 0;
|
||||
score -= 20;
|
||||
if (score < 0) score = 0;
|
||||
|
||||
if (answerButtons[selectedIndex] != null && answerButtons[selectedIndex].image != null)
|
||||
answerButtons[selectedIndex].image.color = FullAlpha(wrongColor);
|
||||
|
||||
StartCoroutine(ShakeButton(answerButtons[selectedIndex], selectedIndex));
|
||||
|
||||
if (correctIndex >= 0 && correctIndex < answerButtons.Length &&
|
||||
answerButtons[correctIndex] != null && answerButtons[correctIndex].image != null)
|
||||
{
|
||||
answerButtons[correctIndex].image.color = FullAlpha(correctColor);
|
||||
StartCoroutine(CorrectPulse(answerButtons[correctIndex], correctIndex));
|
||||
}
|
||||
|
||||
SetFeedback(Local("wrong"), wrongColor);
|
||||
}
|
||||
|
||||
if (scoreText != null)
|
||||
{
|
||||
scoreText.text = score.ToString();
|
||||
StartCoroutine(ScorePopAnim(scoreText));
|
||||
}
|
||||
|
||||
if (comboText != null)
|
||||
comboText.text = combo + "x";
|
||||
|
||||
nextTimer = 1f;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
void OnHint()
|
||||
{
|
||||
if (locked) return;
|
||||
if (lastQ < 0 || lastQ >= questions.Count) return;
|
||||
|
||||
string hint = questions[lastQ].data[langIndex, 3]; // correct answer
|
||||
|
||||
if (!string.IsNullOrEmpty(hint))
|
||||
hint = hint.Length > 1 ? hint[0] + "..." : hint;
|
||||
|
||||
SetFeedback("Hint: " + hint, selectedColor);
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
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 GameOver()
|
||||
{
|
||||
// 🔥 Simple key that the Mod Select / Leaderboard screen can bind to directly
|
||||
PlayerPrefs.SetInt("Mod11Skor", score);
|
||||
|
||||
PlayerPrefs.SetString("LastPlayedMod", modKey);
|
||||
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
||||
|
||||
int best = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
if (score > best)
|
||||
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
||||
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
||||
|
||||
PlayerPrefs.Save();
|
||||
|
||||
SceneManager.LoadScene("Mod11Resume");
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
int GetLangIndex()
|
||||
{
|
||||
return langCode switch
|
||||
{
|
||||
"tr" => 1,
|
||||
"en" => 0,
|
||||
"es" => 2,
|
||||
"de" => 3,
|
||||
"fr" => 4,
|
||||
"pt" => 5,
|
||||
_ => 1 // default EN
|
||||
};
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
string Local(string key)
|
||||
{
|
||||
int L = GetLangIndex(); // Same as QuestionLangCode
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "correct":
|
||||
return new[]
|
||||
{
|
||||
"Correct!", "Correct!", "Correct!", "Correct!", "Correct!", "Correct!"
|
||||
}[L];
|
||||
|
||||
case "wrong":
|
||||
return new[]
|
||||
{
|
||||
"Wrong!", "Wrong!", "Wrong!", "Wrong!", "Wrong!", "Wrong!"
|
||||
}[L];
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
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 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;
|
||||
if (idx < 0 || idx >= originalButtonScales.Length) 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;
|
||||
if (idx < 0 || idx >= originalButtonPositions.Length) 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 = 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod11/AnalogyGameScene.cs.meta
Normal file
2
Assets/Scripts/3.0/mod11/AnalogyGameScene.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff5c022bf505d8a4cbd87bc660103cf2
|
||||
154
Assets/Scripts/3.0/mod11/Mod11Resume.cs
Normal file
154
Assets/Scripts/3.0/mod11/Mod11Resume.cs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod11Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
// 🔥 Bu modun özel PlayerPrefs anahtarı
|
||||
private string modKey = "Mod11";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
// ============================================================
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log($"[MOD11 RESULT] Score={score} | Max={maxScore} | Correct={correct} | Wrong={wrong}");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, Vector3.one, EaseOutBack(t));
|
||||
if (targetValue == 0) txt.text = "0";
|
||||
yield return null;
|
||||
}
|
||||
txt.transform.localScale = Vector3.one;
|
||||
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
txt.text = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct))).ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void Retry()
|
||||
{
|
||||
// 🔥 Mod11 oyun sahnesine geri dön
|
||||
SceneManager.LoadScene("Mod11");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
float EaseOutBack(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float c1 = 1.70158f, 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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod11/Mod11Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/mod11/Mod11Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1781e8376e88df94187d95b3c65889d3
|
||||
8
Assets/Scripts/3.0/mod12.meta
Normal file
8
Assets/Scripts/3.0/mod12.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 792af35de8483a3408d24c7c79e3e76b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
144
Assets/Scripts/3.0/mod12/Mod12Resume.cs
Normal file
144
Assets/Scripts/3.0/mod12/Mod12Resume.cs
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod12Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
private string modKey = "Mod12";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
if (retryButton)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_Score", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
|
||||
Debug.Log($"[MOD12 RESULT] Score={score} | Max={maxScore} | Correct={correct} | Wrong={wrong}");
|
||||
}
|
||||
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, Vector3.one, EaseOutBack(t));
|
||||
if (targetValue == 0) txt.text = "0";
|
||||
yield return null;
|
||||
}
|
||||
txt.transform.localScale = Vector3.one;
|
||||
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
txt.text = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct))).ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
void Retry()
|
||||
{
|
||||
SceneManager.LoadScene("Mod12");
|
||||
}
|
||||
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
float EaseOutBack(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float c1 = 1.70158f, 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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod12/Mod12Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/mod12/Mod12Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 569283d0e752d7f4484717cd84e953c7
|
||||
662
Assets/Scripts/3.0/mod12/TFTranslationGameScene.cs
Normal file
662
Assets/Scripts/3.0/mod12/TFTranslationGameScene.cs
Normal file
|
|
@ -0,0 +1,662 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod12/TFTranslationGameScene.cs.meta
Normal file
2
Assets/Scripts/3.0/mod12/TFTranslationGameScene.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59d2c4636dd071b498167e354fc0b612
|
||||
8
Assets/Scripts/3.0/mod7.meta
Normal file
8
Assets/Scripts/3.0/mod7.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0b4d822743fa66c4a8c54880728ec78c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
164
Assets/Scripts/3.0/mod7/Mod7Resume.cs
Normal file
164
Assets/Scripts/3.0/mod7/Mod7Resume.cs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
using System.Collections;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Mod7Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS (ONLY NUMBERS)")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
private string modKey = "Mod7";
|
||||
|
||||
private int score;
|
||||
private int maxScore;
|
||||
private int correct;
|
||||
private int wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
if (retryButton != null)
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); Retry(); });
|
||||
|
||||
if (exitButton != null)
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); ExitToMenu(); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
// pop-in scale
|
||||
Vector3 normal = Vector3.one;
|
||||
float t = 0f;
|
||||
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, normal, EaseOutBack(t));
|
||||
|
||||
if (targetValue == 0)
|
||||
txt.text = "0";
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = normal;
|
||||
|
||||
// count-up
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
int shown = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct)));
|
||||
txt.text = shown.ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void Retry()
|
||||
{
|
||||
// 🔥 Mod 7 oyun sahnesine dön
|
||||
SceneManager.LoadScene("Mod7");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
void ExitToMenu()
|
||||
{
|
||||
SceneManager.LoadScene("Anamen");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod7/Mod7Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/mod7/Mod7Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 56be283e892927547817c76f96c0329e
|
||||
1118
Assets/Scripts/3.0/mod7/TetrisTranslationDropMod.cs
Normal file
1118
Assets/Scripts/3.0/mod7/TetrisTranslationDropMod.cs
Normal file
File diff suppressed because it is too large
Load diff
2
Assets/Scripts/3.0/mod7/TetrisTranslationDropMod.cs.meta
Normal file
2
Assets/Scripts/3.0/mod7/TetrisTranslationDropMod.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e08b0cfd78da3f94b9cd70dfecc1eca4
|
||||
8
Assets/Scripts/3.0/mod9.meta
Normal file
8
Assets/Scripts/3.0/mod9.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d888a15222d70a4ab1849caa1545618
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
126
Assets/Scripts/3.0/mod9/Mod9Resume.cs
Normal file
126
Assets/Scripts/3.0/mod9/Mod9Resume.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class Mod9Resume : MonoBehaviour
|
||||
{
|
||||
[Header("UI TEXTS")]
|
||||
public TMP_Text scoreText;
|
||||
public TMP_Text maxScoreText;
|
||||
public TMP_Text correctText;
|
||||
public TMP_Text wrongText;
|
||||
|
||||
[Header("BUTTONS")]
|
||||
public Button retryButton;
|
||||
public Button exitButton;
|
||||
|
||||
[Header("AUDIO")]
|
||||
public AudioSource sfx;
|
||||
public AudioClip clickSound;
|
||||
|
||||
[Header("━━━ ANIMATION SETTINGS ━━━━━━━━━━━━━━━━━")]
|
||||
public float countUpDuration = 0.8f;
|
||||
public float popInDelay = 0.08f;
|
||||
public float popInTime = 0.3f;
|
||||
|
||||
private string modKey = "Mod9_Synonym";
|
||||
|
||||
int score, maxScore, correct, wrong;
|
||||
|
||||
void Start()
|
||||
{
|
||||
LoadResults();
|
||||
PrepareTexts();
|
||||
|
||||
retryButton.onClick.AddListener(() => { PlaySFX(); SceneManager.LoadScene("Mod9"); });
|
||||
exitButton.onClick.AddListener(() => { PlaySFX(); SceneManager.LoadScene("Anamen"); });
|
||||
|
||||
StartCoroutine(PlayRevealSequence());
|
||||
}
|
||||
|
||||
void LoadResults()
|
||||
{
|
||||
score = PlayerPrefs.GetInt(modKey + "_LastScore", 0);
|
||||
maxScore = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
correct = PlayerPrefs.GetInt(modKey + "_Correct", 0);
|
||||
wrong = PlayerPrefs.GetInt(modKey + "_Wrong", 0);
|
||||
}
|
||||
|
||||
void PrepareTexts()
|
||||
{
|
||||
SetTextZero(scoreText);
|
||||
SetTextZero(maxScoreText);
|
||||
SetTextZero(correctText);
|
||||
SetTextZero(wrongText);
|
||||
}
|
||||
|
||||
void SetTextZero(TMP_Text txt)
|
||||
{
|
||||
if (txt == null) return;
|
||||
txt.text = "0";
|
||||
txt.transform.localScale = Vector3.zero;
|
||||
}
|
||||
|
||||
IEnumerator PlayRevealSequence()
|
||||
{
|
||||
yield return StartCoroutine(RevealStat(scoreText, score));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(maxScoreText, maxScore));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(correctText, correct));
|
||||
yield return new WaitForSeconds(popInDelay);
|
||||
|
||||
yield return StartCoroutine(RevealStat(wrongText, wrong));
|
||||
}
|
||||
|
||||
IEnumerator RevealStat(TMP_Text txt, int targetValue)
|
||||
{
|
||||
if (txt == null) yield break;
|
||||
|
||||
float t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / Mathf.Max(0.01f, popInTime);
|
||||
txt.transform.localScale = Vector3.Lerp(Vector3.zero, Vector3.one, EaseOutBack(t));
|
||||
if (targetValue == 0) txt.text = "0";
|
||||
yield return null;
|
||||
}
|
||||
txt.transform.localScale = Vector3.one;
|
||||
|
||||
if (targetValue > 0)
|
||||
{
|
||||
float ct = 0f;
|
||||
while (ct < 1f)
|
||||
{
|
||||
ct += Time.deltaTime / Mathf.Max(0.01f, countUpDuration);
|
||||
txt.text = Mathf.RoundToInt(Mathf.Lerp(0, targetValue, EaseOutQuad(ct))).ToString();
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
txt.text = targetValue.ToString();
|
||||
}
|
||||
|
||||
void PlaySFX()
|
||||
{
|
||||
if (sfx && clickSound)
|
||||
sfx.PlayOneShot(clickSound);
|
||||
}
|
||||
|
||||
float EaseOutBack(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float c1 = 1.70158f, 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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod9/Mod9Resume.cs.meta
Normal file
2
Assets/Scripts/3.0/mod9/Mod9Resume.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6f34180d9fade5c4fa76a9c5939efad7
|
||||
844
Assets/Scripts/3.0/mod9/WordMatchMod9.cs
Normal file
844
Assets/Scripts/3.0/mod9/WordMatchMod9.cs
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
public class WordMatchMod9 : MonoBehaviour
|
||||
{
|
||||
[Header("UI - QUESTIONS (LEFT)")]
|
||||
[SerializeField] private Button[] questionButtons;
|
||||
[SerializeField] private TMP_Text[] questionTexts;
|
||||
|
||||
[Header("UI - ANSWERS (RIGHT)")]
|
||||
[SerializeField] private Button[] answerButtons;
|
||||
[SerializeField] private TMP_Text[] answerTexts;
|
||||
|
||||
[Header("UI - OTHER")]
|
||||
[SerializeField] private Button submitButton;
|
||||
[SerializeField] private TMP_Text scoreText;
|
||||
[SerializeField] private TMP_Text comboText;
|
||||
[SerializeField] private TMP_Text timeText;
|
||||
[SerializeField] private TMP_Text feedbackText;
|
||||
|
||||
[Header("━━━ BACK BUTTON ━━━━━━━━━━━━━━━━━━━━━━━━")]
|
||||
public Button backButton;
|
||||
public string backSceneName = "ModSec 9";
|
||||
|
||||
[Header("WORD DATA")]
|
||||
[SerializeField] private TextAsset synonymFile;
|
||||
|
||||
[Header("COLORS")]
|
||||
public Color baseColor = new Color32(230, 230, 230, 255);
|
||||
|
||||
public Color[] pairColors = new Color[]
|
||||
{
|
||||
new Color32(120,180,255,255),
|
||||
new Color32(255,200,120,255),
|
||||
new Color32(160,255,160,255),
|
||||
new Color32(255,150,150,255),
|
||||
new Color32(210,150,255,255),
|
||||
};
|
||||
|
||||
public Color correctColor = new Color32(0, 160, 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;
|
||||
public float enterAnimTime = 0.22f;
|
||||
|
||||
Dictionary<string, string> activeMap = new Dictionary<string, string>();
|
||||
|
||||
int[] questionToAnswer = new int[5];
|
||||
int[] questionColorIdx = new int[5];
|
||||
int[] answerColorIdx = new int[5];
|
||||
|
||||
int selectedQuestion = -1;
|
||||
|
||||
float timeLeft = 90f;
|
||||
bool isTimeUp = false;
|
||||
bool isRoundProcessing = false;
|
||||
|
||||
int score = 0;
|
||||
int combo = 0;
|
||||
int correctCount = 0;
|
||||
int wrongCount = 0;
|
||||
|
||||
List<KeyValuePair<string, string>> selectedPairs = new List<KeyValuePair<string, string>>();
|
||||
|
||||
string modKey = "Mod9_Synonym";
|
||||
private string qLang;
|
||||
|
||||
readonly Color timerNormalColor = Color.white;
|
||||
readonly Color timerWarnColor = new Color32(255, 80, 80, 255);
|
||||
|
||||
Vector3[] questionOriginalScales;
|
||||
Vector3[] answerOriginalScales;
|
||||
Vector3[] questionOriginalPositions;
|
||||
Vector3[] answerOriginalPositions;
|
||||
|
||||
Coroutine[] questionScaleCo;
|
||||
Coroutine[] answerScaleCo;
|
||||
Coroutine[] questionEnterCo;
|
||||
Coroutine[] answerEnterCo;
|
||||
|
||||
Coroutine feedbackCo;
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void Start()
|
||||
{
|
||||
qLang = PlayerPrefs.GetString("QuestionLangCode", "en");
|
||||
|
||||
LoadSynonymFile();
|
||||
|
||||
CacheButtonData();
|
||||
PrepareFeedbackText();
|
||||
|
||||
if (submitButton != null)
|
||||
{
|
||||
submitButton.onClick.RemoveAllListeners();
|
||||
submitButton.onClick.AddListener(OnSubmit);
|
||||
}
|
||||
|
||||
if (backButton != null)
|
||||
{
|
||||
backButton.onClick.RemoveAllListeners();
|
||||
backButton.onClick.AddListener(() => SceneManager.LoadScene(backSceneName));
|
||||
}
|
||||
|
||||
ResetMaps();
|
||||
LoadRound();
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
timeLeft = 90f;
|
||||
isTimeUp = false;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void Update()
|
||||
{
|
||||
if (isTimeUp)
|
||||
{
|
||||
UpdateTimerUI();
|
||||
return;
|
||||
}
|
||||
|
||||
timeLeft -= Time.deltaTime;
|
||||
if (timeLeft < 0f) timeLeft = 0f;
|
||||
|
||||
UpdateTimerUI();
|
||||
|
||||
if (timeLeft <= 0f)
|
||||
{
|
||||
isTimeUp = true;
|
||||
ProcessSubmit(true);
|
||||
StartCoroutine(GoResume());
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void UpdateTimerUI()
|
||||
{
|
||||
if (timeText == null) return;
|
||||
|
||||
timeText.text = Mathf.CeilToInt(timeLeft).ToString();
|
||||
|
||||
if (timeLeft <= 10f)
|
||||
{
|
||||
timeText.color = FullAlpha(Color.Lerp(timerWarnColor, Color.white, Mathf.PingPong(Time.time * 3f, 1f)));
|
||||
timeText.transform.localScale = Vector3.one * (1f + Mathf.Sin(Time.time * 10f) * 0.05f);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeText.color = FullAlpha(timerNormalColor);
|
||||
timeText.transform.localScale = Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void LoadSynonymFile()
|
||||
{
|
||||
activeMap.Clear();
|
||||
|
||||
if (synonymFile == null)
|
||||
{
|
||||
Debug.LogError("Mod9: synonymFile atanmadı!");
|
||||
return;
|
||||
}
|
||||
|
||||
string[] lines = synonymFile.text.Split('\n');
|
||||
int li = LangIndex(qLang);
|
||||
|
||||
for (int i = 0; i + 1 < lines.Length; i += 2)
|
||||
{
|
||||
string A = lines[i].Trim();
|
||||
string B = lines[i + 1].Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(A) || string.IsNullOrWhiteSpace(B)) continue;
|
||||
if (!A.Contains(",") || !B.Contains(",")) continue;
|
||||
|
||||
string[] wA = A.Split(',');
|
||||
string[] wB = B.Split(',');
|
||||
|
||||
if (wA.Length < 6 || wB.Length < 6) continue;
|
||||
|
||||
string q = wA[li].Trim();
|
||||
string a = wB[li].Trim();
|
||||
|
||||
if (!activeMap.ContainsKey(q))
|
||||
activeMap.Add(q, a);
|
||||
}
|
||||
}
|
||||
|
||||
int LangIndex(string c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case "tr": return 0;
|
||||
case "en": return 1;
|
||||
case "es": return 2;
|
||||
case "de": return 3;
|
||||
case "fr": return 4;
|
||||
case "pt": return 5;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void CacheButtonData()
|
||||
{
|
||||
int n = questionButtons.Length;
|
||||
|
||||
questionOriginalScales = new Vector3[n];
|
||||
answerOriginalScales = new Vector3[n];
|
||||
questionOriginalPositions = new Vector3[n];
|
||||
answerOriginalPositions = new Vector3[n];
|
||||
|
||||
questionScaleCo = new Coroutine[n];
|
||||
answerScaleCo = new Coroutine[n];
|
||||
questionEnterCo = new Coroutine[n];
|
||||
answerEnterCo = new Coroutine[n];
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (questionButtons[i] != null)
|
||||
{
|
||||
questionOriginalScales[i] = questionButtons[i].transform.localScale;
|
||||
questionOriginalPositions[i] = questionButtons[i].transform.localPosition;
|
||||
questionButtons[i].transition = Selectable.Transition.None;
|
||||
}
|
||||
|
||||
if (answerButtons[i] != null)
|
||||
{
|
||||
answerOriginalScales[i] = answerButtons[i].transform.localScale;
|
||||
answerOriginalPositions[i] = answerButtons[i].transform.localPosition;
|
||||
answerButtons[i].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 LoadRound()
|
||||
{
|
||||
ResetVisuals();
|
||||
ResetMaps();
|
||||
|
||||
isRoundProcessing = false;
|
||||
|
||||
var all = activeMap.ToList();
|
||||
Shuffle(all);
|
||||
|
||||
selectedPairs = all.Take(5).ToList();
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionTexts[i].text = selectedPairs[i].Key;
|
||||
|
||||
int id = i;
|
||||
questionButtons[i].onClick.RemoveAllListeners();
|
||||
questionButtons[i].onClick.AddListener(() => SelectQuestion(id));
|
||||
}
|
||||
|
||||
List<string> answers = selectedPairs.Select(p => p.Value).ToList();
|
||||
Shuffle(answers);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
answerTexts[i].text = answers[i];
|
||||
|
||||
int id = i;
|
||||
answerButtons[i].onClick.RemoveAllListeners();
|
||||
answerButtons[i].onClick.AddListener(() => SelectAnswer(id));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionEnterCo[i] != null) StopCoroutine(questionEnterCo[i]);
|
||||
questionEnterCo[i] = StartCoroutine(ButtonEnterAnim(questionButtons[i], questionOriginalScales[i], questionOriginalPositions[i], i, -1));
|
||||
|
||||
if (answerEnterCo[i] != null) StopCoroutine(answerEnterCo[i]);
|
||||
answerEnterCo[i] = StartCoroutine(ButtonEnterAnim(answerButtons[i], answerOriginalScales[i], answerOriginalPositions[i], i, 1));
|
||||
|
||||
if (questionTexts[i] != null) StartCoroutine(FadeInText(questionTexts[i]));
|
||||
if (answerTexts[i] != null) StartCoroutine(FadeInText(answerTexts[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void ResetVisuals()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
StopButtonAnims(i);
|
||||
|
||||
questionButtons[i].image.color = FullAlpha(baseColor);
|
||||
answerButtons[i].image.color = FullAlpha(baseColor);
|
||||
|
||||
questionButtons[i].transform.localScale = questionOriginalScales[i];
|
||||
answerButtons[i].transform.localScale = answerOriginalScales[i];
|
||||
|
||||
questionButtons[i].transform.localPosition = questionOriginalPositions[i];
|
||||
answerButtons[i].transform.localPosition = answerOriginalPositions[i];
|
||||
}
|
||||
|
||||
if (feedbackText != null) feedbackText.text = "";
|
||||
}
|
||||
|
||||
void StopButtonAnims(int i)
|
||||
{
|
||||
if (questionScaleCo[i] != null) { StopCoroutine(questionScaleCo[i]); questionScaleCo[i] = null; }
|
||||
if (answerScaleCo[i] != null) { StopCoroutine(answerScaleCo[i]); answerScaleCo[i] = null; }
|
||||
if (questionEnterCo[i] != null) { StopCoroutine(questionEnterCo[i]); questionEnterCo[i] = null; }
|
||||
if (answerEnterCo[i] != null) { StopCoroutine(answerEnterCo[i]); answerEnterCo[i] = null; }
|
||||
}
|
||||
|
||||
void ResetMaps()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
answerColorIdx[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void SelectQuestion(int q)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
|
||||
selectedQuestion = q;
|
||||
StartScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, q, questionOriginalScales[q] * selectedScale);
|
||||
}
|
||||
|
||||
void SelectAnswer(int a)
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
if (selectedQuestion == -1) return;
|
||||
|
||||
int prevQuestion = selectedQuestion;
|
||||
|
||||
if (questionToAnswer[selectedQuestion] == a)
|
||||
{
|
||||
questionToAnswer[selectedQuestion] = -1;
|
||||
questionColorIdx[selectedQuestion] = -1;
|
||||
answerColorIdx[a] = -1;
|
||||
RefreshColors();
|
||||
selectedQuestion = -1;
|
||||
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, a);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
if (questionToAnswer[i] == a && i != selectedQuestion)
|
||||
{
|
||||
questionToAnswer[i] = -1;
|
||||
questionColorIdx[i] = -1;
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, i);
|
||||
}
|
||||
}
|
||||
|
||||
int oldA = questionToAnswer[selectedQuestion];
|
||||
if (oldA != -1)
|
||||
{
|
||||
answerColorIdx[oldA] = -1;
|
||||
ResetScaleAnim(answerButtons, answerScaleCo, answerOriginalScales, oldA);
|
||||
}
|
||||
|
||||
questionToAnswer[selectedQuestion] = a;
|
||||
|
||||
int c = selectedQuestion % pairColors.Length;
|
||||
questionColorIdx[selectedQuestion] = c;
|
||||
answerColorIdx[a] = c;
|
||||
|
||||
RefreshColors();
|
||||
|
||||
StartCoroutine(PairPulse(prevQuestion, a));
|
||||
ResetScaleAnim(questionButtons, questionScaleCo, questionOriginalScales, prevQuestion);
|
||||
|
||||
selectedQuestion = -1;
|
||||
}
|
||||
|
||||
void RefreshColors()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
questionButtons[i].image.color =
|
||||
questionColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[questionColorIdx[i]]);
|
||||
|
||||
answerButtons[i].image.color =
|
||||
answerColorIdx[i] == -1 ? FullAlpha(baseColor) : FullAlpha(pairColors[answerColorIdx[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void OnSubmit()
|
||||
{
|
||||
if (isRoundProcessing || isTimeUp) return;
|
||||
ProcessSubmit(false);
|
||||
}
|
||||
|
||||
void ProcessSubmit(bool fromTimeout)
|
||||
{
|
||||
isRoundProcessing = true;
|
||||
|
||||
int roundCorrect = 0;
|
||||
|
||||
for (int q = 0; q < 5; q++)
|
||||
{
|
||||
int a = questionToAnswer[q];
|
||||
|
||||
if (a == -1)
|
||||
{
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
wrongCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
string qWord = questionTexts[q].text;
|
||||
string correctA = activeMap[qWord];
|
||||
string chosenA = answerTexts[a].text;
|
||||
|
||||
if (chosenA == correctA)
|
||||
{
|
||||
roundCorrect++;
|
||||
correctCount++;
|
||||
|
||||
questionButtons[q].image.color = FullAlpha(correctColor);
|
||||
answerButtons[a].image.color = FullAlpha(correctColor);
|
||||
|
||||
StartCoroutine(CorrectPulse(questionButtons[q], questionOriginalScales[q]));
|
||||
StartCoroutine(CorrectPulse(answerButtons[a], answerOriginalScales[a]));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrongCount++;
|
||||
questionButtons[q].image.color = FullAlpha(wrongColor);
|
||||
answerButtons[a].image.color = FullAlpha(wrongColor);
|
||||
|
||||
StartCoroutine(ShakeButton(questionButtons[q], questionOriginalPositions[q]));
|
||||
StartCoroutine(ShakeButton(answerButtons[a], answerOriginalPositions[a]));
|
||||
}
|
||||
}
|
||||
|
||||
int gained = roundCorrect * 20;
|
||||
score += gained;
|
||||
|
||||
Color feedbackColor;
|
||||
|
||||
if (roundCorrect == 5)
|
||||
{
|
||||
combo++;
|
||||
feedbackText.text = combo >= 2 ? $"PERFECT! {combo}x COMBO!" : "PERFECT!";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else if (roundCorrect > 0)
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "+" + gained + " Points";
|
||||
feedbackColor = correctColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
combo = 0;
|
||||
feedbackText.text = "Try Again!";
|
||||
feedbackColor = wrongColor;
|
||||
}
|
||||
|
||||
feedbackText.color = FullAlpha(feedbackColor);
|
||||
|
||||
if (feedbackOnTop)
|
||||
{
|
||||
Vector3 pos = feedbackText.transform.localPosition;
|
||||
pos.y = feedbackTopY;
|
||||
feedbackText.transform.localPosition = pos;
|
||||
}
|
||||
|
||||
if (feedbackCo != null) StopCoroutine(feedbackCo);
|
||||
feedbackCo = StartCoroutine(FeedbackAnim(feedbackText));
|
||||
|
||||
scoreText.text = score.ToString();
|
||||
comboText.text = combo + "x";
|
||||
|
||||
if (scoreText != null) StartCoroutine(ScorePopAnim(scoreText));
|
||||
if (combo > 0 && comboText != null) StartCoroutine(ComboAnim(comboText));
|
||||
|
||||
SaveProgress();
|
||||
|
||||
if (!fromTimeout)
|
||||
StartCoroutine(NextRound());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------
|
||||
void SaveProgress()
|
||||
{
|
||||
// 🔥 Mod Select / Leaderboard ekranına direkt bağlanacak basit key
|
||||
PlayerPrefs.SetInt("Mod9Skor", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_LastScore", score);
|
||||
|
||||
int best = PlayerPrefs.GetInt(modKey + "_MaxScore", 0);
|
||||
if (score > best)
|
||||
PlayerPrefs.SetInt(modKey + "_MaxScore", score);
|
||||
|
||||
PlayerPrefs.SetInt(modKey + "_Correct", correctCount);
|
||||
PlayerPrefs.SetInt(modKey + "_Wrong", wrongCount);
|
||||
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
|
||||
IEnumerator NextRound()
|
||||
{
|
||||
yield return new WaitForSeconds(0.8f);
|
||||
LoadRound();
|
||||
}
|
||||
|
||||
IEnumerator GoResume()
|
||||
{
|
||||
yield return new WaitForSeconds(1f);
|
||||
SceneManager.LoadScene("Mod9Resume");
|
||||
}
|
||||
|
||||
void Shuffle<T>(List<T> list)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
{
|
||||
int j = Random.Range(0, i + 1);
|
||||
(list[i], list[j]) = (list[j], list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// ================== ANIMATION HELPERS ==================
|
||||
|
||||
void StartScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx, Vector3 targetScale)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
|
||||
if (coArr[idx] != null) StopCoroutine(coArr[idx]);
|
||||
|
||||
coArr[idx] = StartCoroutine(ScaleButton(buttons[idx], targetScale, idx, coArr));
|
||||
}
|
||||
|
||||
void ResetScaleAnim(Button[] buttons, Coroutine[] coArr, Vector3[] originalScales, int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= buttons.Length || buttons[idx] == null) return;
|
||||
StartScaleAnim(buttons, coArr, originalScales, idx, originalScales[idx]);
|
||||
}
|
||||
|
||||
IEnumerator ScaleButton(Button btn, Vector3 targetScale, int idx, Coroutine[] coArr)
|
||||
{
|
||||
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;
|
||||
coArr[idx] = null;
|
||||
}
|
||||
|
||||
IEnumerator ButtonEnterAnim(Button btn, Vector3 targetScale, Vector3 targetPos, int delayIndex, int sideSign)
|
||||
{
|
||||
if (btn == null) yield break;
|
||||
|
||||
yield return new WaitForSeconds(delayIndex * 0.05f);
|
||||
|
||||
Vector3 startPos = targetPos + new Vector3(sideSign * 40f, 0f, 0f);
|
||||
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 PairPulse(int questionIdx, int answerIdx)
|
||||
{
|
||||
if (questionIdx >= 0 && questionIdx < questionButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(questionButtons[questionIdx].transform, questionOriginalScales[questionIdx]));
|
||||
|
||||
if (answerIdx >= 0 && answerIdx < answerButtons.Length)
|
||||
yield return StartCoroutine(QuickPulse(answerButtons[answerIdx].transform, answerOriginalScales[answerIdx]));
|
||||
}
|
||||
|
||||
IEnumerator QuickPulse(Transform tr, Vector3 normal)
|
||||
{
|
||||
if (tr == null) yield break;
|
||||
|
||||
Vector3 big = normal * 1.08f;
|
||||
float t = 0f;
|
||||
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(normal, big, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
t = 0f;
|
||||
while (t < 1f)
|
||||
{
|
||||
t += Time.deltaTime / 0.08f;
|
||||
tr.localScale = Vector3.Lerp(big, normal, EaseOutQuad(t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
tr.localScale = normal;
|
||||
}
|
||||
|
||||
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, magnitude = 12f, 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 baseC = 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(baseC, 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, baseC, t));
|
||||
yield return null;
|
||||
}
|
||||
|
||||
txt.transform.localScale = original;
|
||||
txt.color = baseC;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Color FullAlpha(Color c)
|
||||
{
|
||||
c.a = 1f;
|
||||
return c;
|
||||
}
|
||||
|
||||
float EaseOutBack(float t)
|
||||
{
|
||||
t = Mathf.Clamp01(t);
|
||||
float c1 = 1.70158f, 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);
|
||||
}
|
||||
}
|
||||
2
Assets/Scripts/3.0/mod9/WordMatchMod9.cs.meta
Normal file
2
Assets/Scripts/3.0/mod9/WordMatchMod9.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ebec7d06e1d313b43a00264a336593c9
|
||||
Loading…
Add table
Add a link
Reference in a new issue