Files
zeling_v2/Assets/Scripts/Progression/ProgressLock.cs
2026-05-13 09:19:54 +08:00

97 lines
3.4 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 UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.Progression
{
/// <summary>
/// 进程锁(架构 09_ProgressionModule §12
/// 单向/永久性阻挡,需满足特定条件(击败 Boss才能解锁。
/// 通过 ServiceLocator.GetOrDefault&lt;SaveManager&gt;() 读取进度,订阅 BossDefeated 事件实时响应。
/// </summary>
public class ProgressLock : MonoBehaviour, ISaveable
{
[Header("解锁条件")]
[SerializeField] private string _requiredBossId; // 空 = 不检查 Boss
[SerializeField] private string _requiredItemId; // 空 = 不检查道具P1 预留)
[Header("物理表现")]
[SerializeField] private GameObject _lockedVisuals; // 锁住状态视觉
[SerializeField] private GameObject _unlockedVisuals; // 开启状态视觉(可 null
[SerializeField] private Collider2D _blockCollider;
[Header("存档")]
[SerializeField] private string _lockId; // 唯一 ID存档记录开启状态
[Header("Event Channels")]
[SerializeField] private StringEventChannelSO _onBossDefeated; // EVT_BossDefeated
private readonly CompositeDisposable _subs = new();
private bool _isUnlocked;
private void Awake()
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
}
private void OnDestroy()
{
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
}
private void Start()
{
ApplyState(CheckUnlocked());
}
private void OnEnable()
{
_onBossDefeated?.Subscribe(OnBossDefeated).AddTo(_subs);
}
private void OnDisable()
{
_subs.Clear();
}
private void OnBossDefeated(string bossId)
{
if (!string.IsNullOrEmpty(_requiredBossId) && bossId != _requiredBossId) return;
if (CheckUnlocked()) ApplyState(true);
}
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
if (_isUnlocked && !string.IsNullOrEmpty(_lockId)
&& !data.World.OpenedDoors.Contains(_lockId))
data.World.OpenedDoors.Add(_lockId);
}
public void OnLoad(SaveData data)
{
// 状态由 CheckUnlocked() 读取 IsDoorOpened(从 SaveData.OpenedDoors),应于 Start() 和 OnBossDefeated() 重新评估
}
private bool CheckUnlocked()
{
var sm = ServiceLocator.GetOrDefault<ISaveService>();
if (sm == null) return false;
if (!string.IsNullOrEmpty(_requiredBossId) && !sm.IsBossDefeated(_requiredBossId))
return false;
return string.IsNullOrEmpty(_lockId) || sm.IsDoorOpened(_lockId);
}
private void ApplyState(bool unlocked)
{
_isUnlocked = unlocked;
if (_blockCollider != null) _blockCollider.enabled = !unlocked;
if (_lockedVisuals != null) _lockedVisuals.SetActive(!unlocked);
if (_unlockedVisuals != null) _unlockedVisuals.SetActive(unlocked);
}
}
}