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
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