- Removed deprecated ButtonPinMapping enum and related COM input classes- Updated ComInputToInputSystemAdapter with improved binding logic- Refactored GameManager to use new globals prefab path - Enhanced GameEndUIController with event system focus management - Modified Globals prefab to use pin-based input bindings - Cleaned up obsolete COM system wrapper and native wrapper classes - Adjusted input adapter to support pin bindings over action bindings - Updated manufacturer name in virtual gamepad description
139 lines
5.1 KiB
C#
139 lines
5.1 KiB
C#
using System.Linq;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.SceneManagement;
|
||
|
||
namespace RR.Common.UI
|
||
{
|
||
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;
|
||
|
||
private readonly List<LevelButton> _levelsPool = new();
|
||
|
||
void Awake()
|
||
{
|
||
if (closeButton) closeButton.onClick.AddListener(Close);
|
||
gameObject.SetActive(false);
|
||
}
|
||
|
||
// ==== ПУБЛИЧНЫЙ API ====
|
||
/// <summary>
|
||
/// Метод для открытия модального окна
|
||
/// </summary>
|
||
public void Open()
|
||
{
|
||
BuildIfNeeded();
|
||
gameObject.SetActive(true);
|
||
StopAllCoroutines();
|
||
StartCoroutine(Fade(0f, 1f, fadeDuration));
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метод для закрытия модального окна
|
||
/// </summary>
|
||
private void Close()
|
||
{
|
||
StopAllCoroutines();
|
||
StartCoroutine(Fade(1f, 0f, fadeDuration, () => gameObject.SetActive(false)));
|
||
}
|
||
|
||
// ==== ВНУТРЕННЕЕ ====
|
||
/// <summary>
|
||
/// Метод для сборки кнопок уровней
|
||
/// </summary>
|
||
void BuildIfNeeded()
|
||
{
|
||
// Очистим/пересоберём
|
||
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);
|
||
|
||
if (lv.world == 1) btn.SetColor(Color.green);
|
||
else if (lv.world == 2) btn.SetColor(Color.blue);
|
||
|
||
_levelsPool.Add(btn);
|
||
}
|
||
}
|
||
|
||
struct LevelEntry { public string name; public int world; public int stage; }
|
||
|
||
/// <summary>
|
||
/// Метод для перебора уровней в игре
|
||
/// </summary>
|
||
/// <returns>LevelEntry - текущий мир при переборе</returns>
|
||
IEnumerable<LevelEntry> EnumerateLevelScenesInBuild()
|
||
{
|
||
int n = SceneManager.sceneCountInBuildSettings;
|
||
for (int i = 0; i < n; i++)
|
||
{
|
||
string path = SceneUtility.GetScenePathByBuildIndex(i);
|
||
string buttonName = System.IO.Path.GetFileNameWithoutExtension(path);
|
||
|
||
// фильтр "только уровни" по формату имени W-S:
|
||
var parts = buttonName.Split('-');
|
||
if (parts.Length != 2) continue;
|
||
if (!int.TryParse(parts[0], out int world)) continue;
|
||
if (!int.TryParse(parts[1], out int stage)) continue;
|
||
|
||
// Исключим служебные сцены, даже если вдруг совпадут по формату (на всякий случай)
|
||
if (buttonName.Equals("Level UI", System.StringComparison.OrdinalIgnoreCase)) continue;
|
||
if (buttonName.Equals("MainMenu", System.StringComparison.OrdinalIgnoreCase)) continue;
|
||
|
||
yield return new LevelEntry { name = buttonName, world = world, stage = stage };
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Метод для плавного перехода (затухания)
|
||
/// </summary>
|
||
/// <param name="from">Начальная прозрачность</param>
|
||
/// <param name="to">Конечная прозрачнеость</param>
|
||
/// <param name="time">Время перехода</param>
|
||
/// <param name="onDone">Действие при выполнении перехода</param>
|
||
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();
|
||
}
|
||
}
|
||
}
|