Danro/Assets/Resources/Scripts/UI/LevelSelectModal.cs

112 lines
3.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.InputSystem;
public class LevelSelectModal : MonoBehaviour
{
[Header("Управление")]
[SerializeField] private InputActionReference close;
[Header("UI")]
[SerializeField] private CanvasGroup canvasGroup;
[SerializeField] private Transform content; // Grid parent
[SerializeField] private LevelButton levelButtonPrefab;
[SerializeField] private Button closeButton;
[SerializeField] private float fadeDuration = 0.15f;
readonly List<LevelButton> levelsPool = new();
void Awake()
{
if (closeButton) closeButton.onClick.AddListener(Close);
gameObject.SetActive(false);
}
// ==== ПУБЛИЧНЫЙ API ====
public void Open()
{
BuildIfNeeded();
gameObject.SetActive(true);
StopAllCoroutines();
StartCoroutine(Fade(0f, 1f, fadeDuration));
}
public void Close()
{
StopAllCoroutines();
StartCoroutine(Fade(1f, 0f, fadeDuration, () => gameObject.SetActive(false)));
}
// ==== ВНУТРЕННЕЕ ====
void BuildIfNeeded()
{
// Очистим/пересоберём (можно кэшировать, но пересборка надёжнее при изменениях Build Settings)
foreach (var b in levelsPool) if (b) Destroy(b.gameObject);
levelsPool.Clear();
var levels = EnumerateLevelScenesInBuild()
.OrderBy(e => e.world)
.ThenBy(e => e.stage)
.ToList();
foreach (var lv in levels)
{
var btn = Instantiate(levelButtonPrefab, content);
btn.Setup(lv.name, lv.world, lv.stage);
btn.SetColor(Color.green);
levelsPool.Add(btn);
}
}
struct LevelEntry { public string name; public int world; public int stage; }
IEnumerable<LevelEntry> EnumerateLevelScenesInBuild()
{
int n = SceneManager.sceneCountInBuildSettings;
for (int i = 0; i < n; i++)
{
string path = SceneUtility.GetScenePathByBuildIndex(i);
string name = System.IO.Path.GetFileNameWithoutExtension(path);
// фильтр "только уровни" по формату имени W-S:
var parts = name.Split('-');
if (parts.Length != 2) continue;
if (!int.TryParse(parts[0], out int w)) continue;
if (!int.TryParse(parts[1], out int s)) continue;
// Исключим служебные сцены, даже если вдруг совпадут по формату (на всякий случай)
if (name.Equals("Level UI", System.StringComparison.OrdinalIgnoreCase)) continue;
if (name.Equals("MainMenu", System.StringComparison.OrdinalIgnoreCase)) continue;
yield return new LevelEntry { name = name, world = w, stage = s };
}
}
System.Collections.IEnumerator Fade(float from, float to, float time, System.Action onDone = null)
{
if (!canvasGroup) { onDone?.Invoke(); yield break; }
float t = 0f;
canvasGroup.alpha = from;
canvasGroup.blocksRaycasts = true;
while (t < time)
{
t += Time.unscaledDeltaTime;
canvasGroup.alpha = Mathf.Lerp(from, to, t / time);
yield return null;
}
canvasGroup.alpha = to;
canvasGroup.blocksRaycasts = to > 0.99f;
onDone?.Invoke();
}
void Update()
{
// ESC закрыть
if (gameObject.activeSelf && close.action.WasPressedThisFrame())
Close();
}
}