Files
zeling_v2/Assets/Scripts/World/Puzzle/PuzzleSwitch.cs
2026-05-13 09:19:54 +08:00

111 lines
4.3 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.
// Assets/Scripts/World/Puzzle/PuzzleSwitch.cs
using System;
using Animancer;
using BaseGames.World;
using MoreMountains.Feedbacks;
using UnityEngine;
namespace BaseGames.Puzzle
{
public enum SwitchTriggerMode
{
InteractOnce, // 玩家交互一次,永久激活
InteractToggle, // 玩家交互切换开关
Pressure, // 踩上激活,离开停用
Hold, // 按住交互键持续激活
}
/// <summary>
/// 通用谜题开关,支持三种触发模式。
/// 实现 ISwitchable + IInteractable玩家手动触发
/// </summary>
[RequireComponent(typeof(Collider2D))]
public class PuzzleSwitch : MonoBehaviour, ISwitchable, IInteractable
{
[Header("触发模式")]
[SerializeField] private SwitchTriggerMode _mode = SwitchTriggerMode.InteractOnce;
[Header("状态")]
[SerializeField] private bool _startsActive = false;
[SerializeField] private string _switchId; // 持久化唯一 ID空串则不持久化
[Header("视觉")]
[SerializeField] private AnimancerComponent _animancer;
[SerializeField] private AnimationClip _activeClip;
[SerializeField] private AnimationClip _inactiveClip;
[SerializeField] private MMFeedbacks _activateFeedback;
[Header("持久化SO 注入,非 Instance 单例)")]
[SerializeField] private WorldStateRegistry _worldState;
private bool _isActive;
public bool IsActive => _isActive;
public event Action<bool> OnStateChanged;
private void Awake()
{
bool savedState = !string.IsNullOrEmpty(_switchId)
&& _worldState != null
&& _worldState.HasFlag("switch_" + _switchId);
_isActive = savedState || _startsActive;
}
private void Start()
{
if (_isActive && _activeClip != null) _animancer?.Play(_activeClip);
else if (_inactiveClip != null) _animancer?.Play(_inactiveClip);
}
// ── IInteractable ────────────────────────────────────────────────────
public string InteractPrompt => _mode == SwitchTriggerMode.Hold ? "按住交互" : "交互";
public bool CanInteract => true;
public void Interact(Transform player)
{
if (_mode == SwitchTriggerMode.InteractOnce && _isActive) return;
SetState(!_isActive);
}
public void OnPlayerEnterRange(Transform player) { }
public void OnPlayerExitRange() { }
// ── ISwitchable ──────────────────────────────────────────────────────
public void ForceState(bool active) => SetState(active);
// ── 压板模式 ──────────────────────────────────────────────────────────
private void OnTriggerEnter2D(Collider2D col)
{
if (_mode != SwitchTriggerMode.Pressure) return;
if (col.CompareTag("Player") || col.CompareTag("PushBox"))
SetState(true);
}
private void OnTriggerExit2D(Collider2D col)
{
if (_mode != SwitchTriggerMode.Pressure) return;
if (col.CompareTag("Player") || col.CompareTag("PushBox"))
SetState(false);
}
private void SetState(bool active)
{
if (_isActive == active) return;
_isActive = active;
if (active) _animancer?.Play(_activeClip);
else _animancer?.Play(_inactiveClip);
_activateFeedback?.PlayFeedbacks();
OnStateChanged?.Invoke(active);
// 持久化到 WorldStateRegistry激活添加标记停用清除标记
if (!string.IsNullOrEmpty(_switchId))
{
if (active) _worldState?.SetFlag("switch_" + _switchId);
else _worldState?.ClearFlag("switch_" + _switchId);
}
}
}
}