Files
Cielonos/Assets/Scripts/Core/Interaction/InteractableObjectBase.cs

152 lines
5.1 KiB
C#
Raw Normal View History

2026-02-13 09:22:11 -05:00
using System;
using System.Collections.Generic;
2026-06-12 17:11:39 -04:00
using Cielonos.MainGame;
2026-02-13 09:22:11 -05:00
using SickscoreGames.HUDNavigationSystem;
using Sirenix.OdinInspector;
using UnityEngine;
namespace Cielonos.Core.Interaction
{
2026-05-10 11:47:55 -04:00
public partial class InteractableObjectBase : SerializedMonoBehaviour
2026-02-13 09:22:11 -05:00
{
public InteractionTrigger interactionTrigger;
public HUDNavigationElement navigation;
[HideInInspector]
public List<InteractionChoice> choices;
2026-06-27 12:52:03 -04:00
/// <summary>标记该交互物是否已使用/耗尽,若为 true则不再允许交互且不会因为战斗结束而被重新激活。</summary>
public bool isExhausted = false;
protected virtual void OnEnable()
{
// 监听全局游戏阶段变化,以在战斗开始/结束时自动锁定/解锁交互
if (RunManager.Instance != null)
{
RunManager.Instance.OnPhaseChanged += HandlePhaseChanged;
HandlePhaseChanged(RunManager.Instance.currentPhase);
}
}
protected virtual void OnDisable()
{
// 注销游戏阶段监听,避免内存泄漏
if (RunManager.Instance != null)
{
RunManager.Instance.OnPhaseChanged -= HandlePhaseChanged;
}
}
/// <summary>处理游戏阶段变化的监听回调,在战斗期间禁用交互,战斗外启用。</summary>
private void HandlePhaseChanged(RunPhase phase)
{
if (isExhausted) return;
// 如果当前处于战斗或Boss战阶段则禁止交互否则开启交互
bool isCombat = phase == RunPhase.InCombat || phase == RunPhase.InBoss;
SetInteractable(!isCombat);
}
2026-02-13 09:22:11 -05:00
private void Awake()
{
choices = new List<InteractionChoice>();
InitializeChoices();
}
}
public partial class InteractableObjectBase
{
protected virtual void InitializeChoices()
{
// Override in derived classes to set up interaction choices
}
public virtual void EnterTriggerAction()
{
navigation.showIndicator = true;
2026-06-27 12:52:03 -04:00
navigation.useIndicatorDistanceText = false;
2026-02-13 09:22:11 -05:00
}
public virtual void ExitTriggerAction()
{
navigation.showIndicator = false;
}
2026-05-10 11:47:55 -04:00
/// <summary>
/// 运行时启用或禁用此可交互对象。
/// 禁用后触发区碰撞体关闭HUD 指示器隐藏choices 不再注册给玩家。
/// 用于单次使用节点MechanicalTable、MedicalStation使用完毕后的 Exhausted 状态。
/// </summary>
public void SetInteractable(bool enabled)
{
interactionTrigger.GetComponent<Collider>().enabled = enabled;
navigation.showIndicator = enabled && navigation.showIndicator;
2026-06-12 17:11:39 -04:00
if (!enabled)
{
var player = MainGameManager.Player;
if (player != null && player.interactionSc != null && player.interactionSc.currentInteractable == this)
{
// 从玩家的选择列表中移除此物体的所有选项,防止残留选项造成后续按 R 键误触发
foreach (var choice in choices)
{
player.interactionSc.currentChoices.Remove(choice);
}
// 清除控制器引用的当前交互对象,并隐藏 UI Area
player.interactionSc.RemoveCurrentInteractable(this);
}
}
2026-05-10 11:47:55 -04:00
}
2026-06-27 12:52:03 -04:00
/// <summary>
/// 将此交互对象永久标记为"已耗尽"(单次使用后),并禁用交互。
/// 处于耗尽状态的对象不会因为脱离战斗状态而重新启用交互。
/// </summary>
public virtual void SetExhausted()
{
isExhausted = true;
SetInteractable(false);
}
2026-02-13 09:22:11 -05:00
}
#if UNITY_EDITOR
public partial class InteractableObjectBase
{
private void Reset()
{
Setup();
}
2026-06-27 12:52:03 -04:00
2026-02-13 09:22:11 -05:00
private void Setup()
{
if (interactionTrigger == null)
{
interactionTrigger = GetComponentInChildren<InteractionTrigger>();
interactionTrigger.interactableObject = this;
}
if (navigation == null)
{
navigation = GetComponentInChildren<HUDNavigationElement>();
}
}
}
#endif
public class InteractionChoice
{
public string choiceName;
public Action action;
2026-06-12 17:11:39 -04:00
/// <summary>
/// 此选项是否可执行。false 时 UI 灰显,按下 R 键也不会触发 action。
/// </summary>
public bool isInteractable;
public InteractionChoice(string name, Action action, bool isInteractable = true)
2026-02-13 09:22:11 -05:00
{
this.choiceName = name;
this.action = action;
2026-06-12 17:11:39 -04:00
this.isInteractable = isInteractable;
2026-02-13 09:22:11 -05:00
}
}
}