108 lines
4.0 KiB
C#
108 lines
4.0 KiB
C#
using BaseGames.Combat;
|
||
using BaseGames.Feedback;
|
||
using UnityEngine;
|
||
|
||
namespace BaseGames.World
|
||
{
|
||
/// <summary>
|
||
/// 假墙(秘密通道)。外观与普通墙相同,可通过攻击/接近揭示并穿越。
|
||
/// 揭示后禁用碰撞体(不销毁),状态通过 WorldStateRegistry 持久化。
|
||
/// WorldStateRegistrySaver(ISaveable)统一负责将 Door 分类写入存档。
|
||
/// </summary>
|
||
[RequireComponent(typeof(Collider2D))]
|
||
public class FalseWall : MonoBehaviour, IDamageable
|
||
{
|
||
public enum RevealCondition { Proximity, AttackOnce, AlwaysOpen }
|
||
|
||
[Header("识别")]
|
||
[SerializeField] private string _wallId;
|
||
|
||
[Header("揭示条件")]
|
||
[SerializeField] private RevealCondition _revealCondition = RevealCondition.AttackOnce;
|
||
[SerializeField] private float _proximityRadius = 2.0f;
|
||
|
||
[Header("组件引用")]
|
||
[SerializeField] private Collider2D _wallCollider;
|
||
[SerializeField] private SpriteRenderer _renderer;
|
||
[SerializeField] private SceneFeedback _revealFeedback;
|
||
|
||
[Header("World State")]
|
||
[Tooltip("绑定场景唯一的 WorldStateRegistry ScriptableObject,用于持久化揭示状态。")]
|
||
[SerializeField] private WorldStateRegistry _registry;
|
||
|
||
private bool _isRevealed;
|
||
|
||
// ── IDamageable ───────────────────────────────────────────────────────
|
||
public bool IsAlive => true;
|
||
public bool IsInvincible => _isRevealed;
|
||
public int Defense => 0;
|
||
|
||
public void TakeDamage(DamageInfo info)
|
||
{
|
||
if (_isRevealed || _revealCondition != RevealCondition.AttackOnce) return;
|
||
Reveal();
|
||
}
|
||
|
||
// ── Unity Lifecycle ───────────────────────────────────────────────────
|
||
|
||
private void Start()
|
||
{
|
||
if (_revealCondition == RevealCondition.AlwaysOpen)
|
||
{
|
||
SetPassThroughImmediate();
|
||
_isRevealed = true;
|
||
return;
|
||
}
|
||
|
||
// 从 WorldStateRegistry 恢复揭示状态(注册表由 WorldStateRegistrySaver.OnLoad 填充)
|
||
if (!string.IsNullOrEmpty(_wallId) && (_registry?.IsDoorOpened(_wallId) ?? false))
|
||
{
|
||
_isRevealed = true;
|
||
SetPassThroughImmediate();
|
||
}
|
||
}
|
||
|
||
private void OnTriggerEnter2D(Collider2D other)
|
||
{
|
||
if (_isRevealed || _revealCondition != RevealCondition.Proximity) return;
|
||
if (!other.CompareTag("Player")) return;
|
||
// Proximity 模式:仅播放 Shimmer 暗示,碰撞仍启用
|
||
_revealFeedback?.Play();
|
||
}
|
||
|
||
// ── Implementation ────────────────────────────────────────────────────
|
||
|
||
private void Reveal()
|
||
{
|
||
_isRevealed = true;
|
||
_registry?.MarkDoorOpened(_wallId);
|
||
_revealFeedback?.Play();
|
||
SetPassThroughImmediate();
|
||
}
|
||
|
||
private void SetPassThroughImmediate()
|
||
{
|
||
if (_wallCollider != null)
|
||
_wallCollider.enabled = false;
|
||
// 切换 Sprite 到透明/揭示帧(由子类或动画处理)
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
private void OnDrawGizmosSelected()
|
||
{
|
||
Gizmos.color = new Color(0.6f, 0.2f, 1f, 0.8f);
|
||
var col = GetComponent<Collider2D>();
|
||
if (col != null)
|
||
Gizmos.DrawWireCube(transform.position, col.bounds.size);
|
||
|
||
if (_revealCondition == RevealCondition.Proximity)
|
||
{
|
||
Gizmos.color = new Color(0.6f, 0.2f, 1f, 0.2f);
|
||
Gizmos.DrawWireSphere(transform.position, _proximityRadius);
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
}
|
||
|