114 lines
3.8 KiB
C#
114 lines
3.8 KiB
C#
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
using BaseGames.Core;
|
||
using BaseGames.Core.Events;
|
||
using BaseGames.Core.Save;
|
||
|
||
namespace BaseGames.World
|
||
{
|
||
/// <summary>
|
||
/// 管理死亡遗骸(Death Shade)的生命周期与持久化。
|
||
///
|
||
/// 挂载位置:Persistent 场景的根 GameObject(DontDestroyOnLoad)。
|
||
///
|
||
/// 流程:
|
||
/// 玩家死亡 → OnPlayerDied:记录死亡位置与灵珠量,在当前场景生成遗骸。
|
||
/// 切换场景 → OnSceneLoaded:若新场景即遗骸所在场景,自动生成遗骸。
|
||
/// 回收遗骸 → OnShadeCollected:清除待存储的遗骸数据。
|
||
/// 存档 → OnSave:将遗骸数据(null = 无遗骸)写入 SaveData.Player.DeathShade。
|
||
/// 读档 → OnLoad:从 SaveData 恢复遗骸数据;实际 GameObject 在下次进入该场景时生成。
|
||
/// </summary>
|
||
public class DeathShadeManager : SaveableMonoBehaviour
|
||
{
|
||
[SerializeField] private DeathShade _shadePrefab;
|
||
[SerializeField] private VoidEventChannelSO _onPlayerDied;
|
||
[SerializeField] private StringEventChannelSO _onShadeCollected;
|
||
|
||
private DeathShadeSaveData _pendingSave;
|
||
private DeathShade _activeShade;
|
||
|
||
private readonly CompositeDisposable _subs = new();
|
||
|
||
protected override void OnEnable()
|
||
{
|
||
base.OnEnable();
|
||
_onPlayerDied? .Subscribe(OnPlayerDied) .AddTo(_subs);
|
||
_onShadeCollected?.Subscribe(OnShadeCollected).AddTo(_subs);
|
||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||
}
|
||
|
||
protected override void OnDisable()
|
||
{
|
||
base.OnDisable();
|
||
_subs.Clear();
|
||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||
}
|
||
|
||
private void OnPlayerDied()
|
||
{
|
||
var playerGo = GameObject.FindWithTag("Player");
|
||
if (playerGo == null) return;
|
||
|
||
int lingZhu = playerGo.GetComponent<ILingZhuProvider>()?.CurrentLingZhu ?? 0;
|
||
var pos = (Vector2)playerGo.transform.position;
|
||
string sceneId = SceneManager.GetActiveScene().name;
|
||
|
||
if (_activeShade != null)
|
||
{
|
||
Destroy(_activeShade.gameObject);
|
||
_activeShade = null;
|
||
}
|
||
|
||
_pendingSave = new DeathShadeSaveData
|
||
{
|
||
PosX = pos.x,
|
||
PosY = pos.y,
|
||
SceneId = sceneId,
|
||
LingZhuAmount = lingZhu,
|
||
};
|
||
|
||
TrySpawnShade(sceneId);
|
||
}
|
||
|
||
private void OnSceneLoaded(Scene scene, LoadSceneMode _)
|
||
{
|
||
_activeShade = null; // 前一场景的 GameObject 已被 Unity 卸载
|
||
TrySpawnShade(scene.name);
|
||
}
|
||
|
||
private void TrySpawnShade(string sceneName)
|
||
{
|
||
if (_shadePrefab == null || _pendingSave == null) return;
|
||
if (_pendingSave.SceneId != sceneName) return;
|
||
|
||
_activeShade = Instantiate(_shadePrefab);
|
||
_activeShade.Initialize(
|
||
_pendingSave.LingZhuAmount,
|
||
_pendingSave.SceneId,
|
||
new Vector2(_pendingSave.PosX, _pendingSave.PosY));
|
||
}
|
||
|
||
private void OnShadeCollected(string _)
|
||
{
|
||
_pendingSave = null;
|
||
_activeShade = null;
|
||
}
|
||
|
||
public override void OnSave(SaveData data)
|
||
{
|
||
data.Player.DeathShade = _pendingSave;
|
||
}
|
||
|
||
public override void OnLoad(SaveData data)
|
||
{
|
||
if (_activeShade != null)
|
||
{
|
||
Destroy(_activeShade.gameObject);
|
||
_activeShade = null;
|
||
}
|
||
_pendingSave = data.Player.DeathShade;
|
||
// 遗骸 GameObject 将在 OnSceneLoaded 中按需生成
|
||
}
|
||
}
|
||
}
|