113 lines
3.9 KiB
C#
113 lines
3.9 KiB
C#
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<Checkpoint>(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<Checkpoint>(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;
|
||
}
|
||
}
|
||
} |