starOfWords/Assets/Scripts/2.0/LevelSelectController.cs
portakal ecb1c9edea Initial commit: Star of Words Unity project
Snapshot of the existing Unity 6 language-learning word game before any
refactoring. Adds Unity .gitignore and .gitattributes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 15:31:20 +03:00

220 lines
No EOL
10 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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

using UnityEngine;
using UnityEngine.UI;
using TMPro;
using UnityEngine.SceneManagement;
using System.Collections;
public class LevelSelectController : MonoBehaviour
{
[Header("━━━ UI ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")]
public Button[] levelButtons;
public TMP_Text[] levelNameTexts;
public TMP_Text[] levelScoreTexts;
[Header("━━━ BACK BUTONU ━━━━━━━━━━━━━━━━━━━━━━━")]
public Button backButton;
public string backSceneName = "Anamen";
[Header("━━━ AUDIO ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")]
public AudioSource sfxSource;
public AudioClip clickSound;
[Header("━━━ ANİMASYON ━━━━━━━━━━━━━━━━━━━━━━━━━")]
[Range(0.005f, 0.1f)] public float buttonAniSpeed = 0.02f;
private int langIndex;
private Vector3[] originalScales;
private Vector3[] originalPositions;
// ============================================================
private readonly string[,] levelNames = new string[,]
{
{ "Temel Selamlaşma ve İnsanlar","Basic Greetings & People","Saludos Básicos y Personas","Grundbegrüßungen & Menschen","Salutations de Base & Personnes","Saudações Básicas e Pessoas" },
{ "Günlük Ev Nesneleri","Daily Household Items","Objetos del Hogar Diarios","Tägliche Haushaltsgegenstände","Objets Quotidiens de la Maison","Objetos Domésticos Diários" },
{ "Yiyecekler ve İçecekler","Food & Drinks","Comida y Bebida","Essen & Getränke","Nourriture & Boissons","Comidas e Bebidas" },
{ "Renkler, Şekiller ve Boyutlar","Colors, Shapes & Sizes","Colores, Formas y Tamaños","Farben, Formen & Größen","Couleurs, Formas & Tailles","Cores, Formas e Tamanhos" },
{ "Zaman, Günler ve Mevsimler","Time, Days & Seasons","Tiempo, Días y Estaciones","Zeit, Tage & Jahreszeiten","Temps, Jours & Saisons","Tempo, Dias e Estações" },
{ "Ev İçi Alanlar ve Temizlik","Home Areas & Cleaning","Áreas del Hogar y Limpieza","Hausbereiche & Reinigung","Espaces de Maison & Nettoyage","Áreas da Casa e Limpeza" },
{ "Okul, Eğitim ve Ders Araçları","School, Education & Supplies","Escuela, Educación y Útiles","Schule, Bildung & Materialien","École, Éducation & Fournitures","Escola, Educação e Materiais" },
{ "Vücut Parçaları ve Sağlık","Body Parts & Health","Partes del Cuerpo y Salud","Körperteile & Gesundheit","Parties du Corps & Santé","Partes do Corpo e Saúde" },
{ "Doğa, Hava ve Çevre Unsurları","Nature, Weather & Environment","Naturaleza, Clima y Medio Ambiente","Natur, Wetter & Umwelt","Nature, Météo & Environnement","Natureza, Clima e Meio Ambiente" },
{ "Evcil ve Vahşi Hayvanlar","Pets & Wild Animals","Mascotas y Animales Salvajes","Haustiere & Wildtiere","Animaux Domestiques & Sauvages","Animais Domésticos e Selvagens" },
{ "Ulaşım Araçları ve Trafik","Transportation & Traffic","Transporte y Tráfico","Transport & Verkehr","Transport & Circulation","Transporte e Trânsito" },
{ "Alışveriş ve Mağazalar","Shopping & Stores","Compras y Tiendas","Einkaufen & Geschäfte","Shopping & Magasins","Compras e Lojas" },
{ "Spor Dalları ve Ekipmanları","Sports & Equipment","Deportes y Equipamiento","Sportarten & Ausrüstung","Sports & Équipement","Esportes e Equipamentos" },
{ "Meslekler ve İş Alanları","Jobs & Work Fields","Profesiones y Áreas Laborales","Berufe & Arbeitsfelder","Métiers & Domaines de Travail","Profissões e Áreas de Trabalho" },
{ "Şehir, Yerler ve Binalar","City, Places & Buildings","Ciudad, Lugares y Edificios","Stadt, Orte & Gebäude","Ville, Lieux & Bâtiments","Cidade, Lugares e Edifícios" },
{ "Duygular, Durumlar ve Karakter","Emotions, States & Character","Emociones, Estados y Carácter","Gefühle, Zustände & Charakter","Émotions, États & Caractère","Emoções, Estados e Caráter" },
{ "Seyahat, Tatil ve Turizm","Travel, Vacation & Tourism","Viajes, Vacaciones y Turismo","Reisen, Urlaub & Tourismus","Voyage, Vacances & Tourisme","Viagem, Férias e Turismo" },
{ "Teknoloji, İnternet ve Cihazlar","Technology, Internet & Devices","Tecnología, Internet y Dispositivos","Technologie, Internet & Geräte","Technologie, Internet & Appareils","Tecnologia, Internet e Dispositivos" },
{ "Çevre Koruma ve Geri Dönüşüm","Environmental Protection & Recycling","Protección Ambiental y Reciclaje","Umweltschutz & Recycling","Protection de l'Environnement & Recyclage","Proteção Ambiental e Reciclagem" },
{ "İleri Günlük İfadeler ve İş Hayatı","Advanced Daily Phrases & Work Life","Frases Avanzadas y Vida Laboral","Fortgeschrittene Alltagssätze & Arbeitsleben","Phrases Avançées & Vie Professionnelle","Frases Avançadas e Vida Profissional" }
};
private readonly string[] scoreLabel =
{
"Puan","Score","Puntuación","Punkte","Score","Pontuação"
};
// ============================================================
void Start()
{
string ansLang = PlayerPrefs.GetString("AnswerLangCode", "tr").ToLower();
langIndex = GetLangIndex(ansLang);
CacheButtonData();
SetupLevelNames();
LoadScoresToUI();
BindButtons();
// ─── Buton giriş animasyonu ───────────────
for (int i = 0; i < levelButtons.Length; i++)
StartCoroutine(ButtonEnterAnim(levelButtons[i], i));
}
// ============================================================
int GetLangIndex(string code)
{
return code switch
{
"tr" => 0,
"en" => 1,
"es" => 2,
"de" => 3,
"fr" => 4,
"pt" => 5,
_ => 1
};
}
// ============================================================
void CacheButtonData()
{
if (levelButtons == null) return;
originalScales = new Vector3[levelButtons.Length];
originalPositions = new Vector3[levelButtons.Length];
for (int i = 0; i < levelButtons.Length; i++)
{
if (levelButtons[i] == null) continue;
originalScales[i] = levelButtons[i].transform.localScale;
originalPositions[i] = levelButtons[i].transform.localPosition;
}
}
// ============================================================
void SetupLevelNames()
{
if (levelNameTexts == null) return;
for (int i = 0; i < levelNameTexts.Length; i++)
if (levelNameTexts[i] != null)
levelNameTexts[i].text = levelNames[i, langIndex];
}
// ============================================================
void BindButtons()
{
if (levelButtons == null) return;
for (int i = 0; i < levelButtons.Length; i++)
{
if (levelButtons[i] == null) continue;
int id = i + 1;
levelButtons[i].onClick.RemoveAllListeners();
levelButtons[i].onClick.AddListener(() =>
{
PlayClick();
PlayerPrefs.SetInt("SelectedLevel", id);
PlayerPrefs.Save();
SceneManager.LoadScene("LLGameScene_Level");
});
}
if (backButton != null)
backButton.onClick.AddListener(() => { PlayClick(); SceneManager.LoadScene(backSceneName); });
}
// ============================================================
void LoadScoresToUI()
{
if (levelScoreTexts == null) return;
for (int i = 0; i < levelScoreTexts.Length; i++)
{
if (levelScoreTexts[i] == null) continue;
int levelID = i + 1;
int highScore = PlayerPrefs.GetInt("HighScore_Level_" + levelID, 0);
if (highScore >= 2000)
{
levelScoreTexts[i].text = $"{scoreLabel[langIndex]}: 2000 / 2000";
levelScoreTexts[i].color = Color.green;
}
else
{
levelScoreTexts[i].text = $"{scoreLabel[langIndex]}: {highScore} / 2000";
levelScoreTexts[i].color = Color.red;
}
}
}
// ============================================================
void PlayClick()
{
if (sfxSource != null && clickSound != null)
sfxSource.PlayOneShot(clickSound);
}
// ============================================================
// ANİMASYONLAR
// ============================================================
IEnumerator ButtonEnterAnim(Button btn, int delayIndex)
{
if (btn == null || originalScales == null) yield break;
int idx = System.Array.IndexOf(levelButtons, btn);
if (idx < 0 || idx >= originalScales.Length) yield break;
yield return new WaitForSeconds(delayIndex * 0.08f);
Vector3 targetPos = originalPositions[idx];
Vector3 startPos = targetPos + Vector3.up * 60f;
Vector3 targetScale = originalScales[idx];
btn.transform.localPosition = startPos;
btn.transform.localScale = Vector3.zero;
float t = 0f;
while (t < 1f)
{
t = Mathf.Min(t + buttonAniSpeed * 0.13f, 1f);
float ease = EaseOutBack(t);
btn.transform.localPosition = Vector3.Lerp(startPos, targetPos, ease);
btn.transform.localScale = Vector3.Lerp(Vector3.zero, targetScale, ease);
yield return null;
}
btn.transform.localPosition = targetPos;
btn.transform.localScale = targetScale;
}
IEnumerator PunchScale(Button btn, int idx)
{
if (btn == null || originalScales == null) yield break;
if (idx < 0 || idx >= originalScales.Length) yield break;
Vector3 original = originalScales[idx];
Vector3 big = original * 1.08f;
float t = 0f;
while (t < 1f) { t = Mathf.Min(t + 0.15f, 1f); btn.transform.localScale = Vector3.Lerp(original, big, EaseOutQuad(t)); yield return null; }
t = 0f;
while (t < 1f) { t = Mathf.Min(t + 0.12f, 1f); btn.transform.localScale = Vector3.Lerp(big, original, EaseOutQuad(t)); yield return null; }
btn.transform.localScale = original;
}
// ============================================================
float EaseOutBack(float 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) => 1f - (1f - t) * (1f - t);
}