152 lines
5.1 KiB
C#
152 lines
5.1 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using Cielonos.MainGame;
|
||
using SickscoreGames.HUDNavigationSystem;
|
||
using Sirenix.OdinInspector;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.Core.Interaction
|
||
{
|
||
public partial class InteractableObjectBase : SerializedMonoBehaviour
|
||
{
|
||
public InteractionTrigger interactionTrigger;
|
||
public HUDNavigationElement navigation;
|
||
|
||
[HideInInspector]
|
||
public List<InteractionChoice> choices;
|
||
|
||
/// <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);
|
||
}
|
||
|
||
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;
|
||
navigation.useIndicatorDistanceText = false;
|
||
}
|
||
|
||
public virtual void ExitTriggerAction()
|
||
{
|
||
navigation.showIndicator = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 运行时启用或禁用此可交互对象。
|
||
/// 禁用后:触发区碰撞体关闭,HUD 指示器隐藏,choices 不再注册给玩家。
|
||
/// 用于单次使用节点(MechanicalTable、MedicalStation)使用完毕后的 Exhausted 状态。
|
||
/// </summary>
|
||
public void SetInteractable(bool enabled)
|
||
{
|
||
interactionTrigger.GetComponent<Collider>().enabled = enabled;
|
||
navigation.showIndicator = enabled && navigation.showIndicator;
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将此交互对象永久标记为"已耗尽"(单次使用后),并禁用交互。
|
||
/// 处于耗尽状态的对象不会因为脱离战斗状态而重新启用交互。
|
||
/// </summary>
|
||
public virtual void SetExhausted()
|
||
{
|
||
isExhausted = true;
|
||
SetInteractable(false);
|
||
}
|
||
}
|
||
|
||
#if UNITY_EDITOR
|
||
public partial class InteractableObjectBase
|
||
{
|
||
private void Reset()
|
||
{
|
||
Setup();
|
||
}
|
||
|
||
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;
|
||
/// <summary>
|
||
/// 此选项是否可执行。false 时 UI 灰显,按下 R 键也不会触发 action。
|
||
/// </summary>
|
||
public bool isInteractable;
|
||
|
||
public InteractionChoice(string name, Action action, bool isInteractable = true)
|
||
{
|
||
this.choiceName = name;
|
||
this.action = action;
|
||
this.isInteractable = isInteractable;
|
||
}
|
||
}
|
||
} |