using UnityEngine; using UnityEngine.SceneManagement; namespace RR.Game2D.Entities { // Явный делегат для события смены чекпоинта public delegate void CheckpointChangedHandler(Checkpoint previous, Checkpoint current); public class CheckpointSystem : MonoBehaviour { public static CheckpointSystem Instance { get; private set; } [Tooltip("Сохранять последний чекпоинт в PlayerPrefs (по имени сцены).")] public bool persistBetweenSessions = false; private Checkpoint _active; private Checkpoint[] _all; // Событие для внешних подписчиков: (старый, новый) public event CheckpointChangedHandler ActiveChanged; // Текущий активный чекпоинт (read-only) public Checkpoint Active => _active; private string PrefKey => $"CP_{SceneManager.GetActiveScene().name}"; void Awake() { if (Instance && Instance != this) { Destroy(gameObject); return; } Instance = this; _all = FindObjectsByType(FindObjectsSortMode.None); // восстановление из PlayerPrefs if (persistBetweenSessions && PlayerPrefs.HasKey(PrefKey)) { var savedId = PlayerPrefs.GetString(PrefKey, ""); foreach (var cp in _all) if (cp.checkpointId == savedId) { _active = cp; break; } } } public void SetActive(Checkpoint cp) { if (_active == cp) return; // уже активен var previous = _active; _active = cp; if (persistBetweenSessions) { if (cp != null) PlayerPrefs.SetString(PrefKey, cp.checkpointId); else PlayerPrefs.DeleteKey(PrefKey); PlayerPrefs.Save(); // гарантируем запись на диск } // Оповестим подписчиков о смене if (ActiveChanged != null) ActiveChanged(previous, _active); // здесь можно задизейблить «подсветку» у старого и включить у нового } // Новый вспомогательный метод: активировать чекпоинт по его идентификатору public void SetActiveById(string id) { if (string.IsNullOrWhiteSpace(id)) return; // Обновим кэш, если он по какой-то причине пуст if (_all == null || _all.Length == 0) _all = FindObjectsByType(FindObjectsSortMode.None); for (int i = 0; i < _all.Length; i++) { var cp = _all[i]; if (cp != null && cp.checkpointId == id) { SetActive(cp); return; } } // Если не нашли — ничего не делаем (можно добавить Debug.LogWarning при необходимости) } public Vector3 GetSpawnPosition(Vector3 defaultPos) => _active ? _active.GetSpawnPosition() : defaultPos; public Vector2 GetSpawnForward(Vector2 defaultForward) => _active ? _active.GetForward() : defaultForward; // Если нужно сбросить прогресс public void ClearSaved() { if (persistBetweenSessions) { PlayerPrefs.DeleteKey(PrefKey); PlayerPrefs.Save(); } _active = null; } } }