using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Input;
using BaseGames.Player;
using BaseGames.Player.States;
using BaseGames.Progression;
namespace BaseGames.Support.AntiSoftlock
{
///
/// 防软锁系统(架构 16_SupportingModules §5)。
/// 检测玩家长时间静止且无法移动的情况,提供逃脱选项。
///
public class AntiSoftlockSystem : MonoBehaviour
{
[Header("配置")]
[Tooltip("玩家静止超过此秒数后显示逃脱提示")]
[SerializeField] private float _stuckThresholdSeconds = 30f;
[Tooltip("移动速度低于此值视为静止")]
[SerializeField] private float _minVelocityThreshold = 0.1f;
[Header("逃脱路径列表(按优先级降序排列)")]
[SerializeField] private RoomEscapeInfoSO[] _escapeOptions;
[Header("事件频道")]
[SerializeField] private SceneLoadRequestEventChannelSO _onSceneLoadRequest;
[SerializeField] private VoidEventChannelSO _onShowEscapeUI;
[SerializeField] private VoidEventChannelSO _onHideEscapeUI;
///
/// 玩家生成事件频道(PlayerController.Start() 广播)。
/// 替代 FindFirstObjectByType 的全场景扫描。
///
[SerializeField] private TransformEventChannelSO _onPlayerSpawned;
[Header("引用")]
[SerializeField] private InputReaderSO _input;
private PlayerController _player;
private Rigidbody2D _playerRb;
private float _stuckTimer;
private bool _escapeUIVisible;
private Vector2 _lastPos;
private readonly BaseGames.Core.Events.CompositeDisposable _subs = new();
private void OnEnable()
{
if (_onPlayerSpawned != null)
_onPlayerSpawned.Subscribe(OnPlayerSpawned).AddTo(_subs);
}
private void OnDisable() => _subs.Clear();
private void OnPlayerSpawned(Transform playerTransform)
{
if (playerTransform == null) return;
_player = playerTransform.GetComponent();
_playerRb = playerTransform.GetComponent();
_lastPos = playerTransform.position;
_stuckTimer = 0f;
}
private void Update()
{
if (_player == null || !_player.Stats.IsAlive) return;
Vector2 pos = _player.transform.position;
float vel = _playerRb != null ? _playerRb.velocity.magnitude : Vector2.Distance(pos, _lastPos) / Time.deltaTime;
if (vel > _minVelocityThreshold)
{
_stuckTimer = 0f;
_lastPos = pos;
if (_escapeUIVisible) HideEscapeUI();
return;
}
_lastPos = pos;
_stuckTimer += Time.deltaTime;
if (_stuckTimer >= _stuckThresholdSeconds && !_escapeUIVisible)
ShowEscapeUI();
}
private void ShowEscapeUI()
{
_escapeUIVisible = true;
_onShowEscapeUI?.Raise();
}
private void HideEscapeUI()
{
_escapeUIVisible = false;
_onHideEscapeUI?.Raise();
}
/// 执行最优先的逃脱路径(由 UI 按钮调用)。
public void ExecuteEscape()
{
var escape = ChooseBestEscape();
HideEscapeUI();
var sm = ServiceLocator.GetOrDefault();
string scene = string.IsNullOrEmpty(escape?.targetScene)
? sm?.LastCheckpointScene
: escape.targetScene;
string spawn = string.IsNullOrEmpty(escape?.spawnId)
? sm?.LastCheckpointSpawnId
: escape.spawnId;
_onSceneLoadRequest?.Raise(new SceneLoadRequest
{
SceneName = scene,
EntryId = spawn,
TransitionType = TransitionType.Scene,
IsRespawn = true,
});
}
private RoomEscapeInfoSO ChooseBestEscape()
{
if (_escapeOptions == null || _escapeOptions.Length == 0) return null;
RoomEscapeInfoSO best = null;
int bestPriority = int.MinValue;
foreach (var opt in _escapeOptions)
{
if (opt == null) continue;
if (opt.requiredAbility != BaseGames.Player.AbilityType.None
&& (_player?.Stats.HasAbility(opt.requiredAbility) == false)) continue;
if (opt.priority > bestPriority)
{
bestPriority = opt.priority;
best = opt;
}
}
return best;
}
}
}