using System.Collections.Generic; using Cielonos.Core.Interaction; using Cielonos.MainGame.UI; using SLSUtilities.UI; using UnityEngine; namespace Cielonos.MainGame.Characters { public class PlayerInteractionSubcontroller : SubcontrollerBase { public Player player => owner; /// 当前进入触发区的所有交互选项(由 InteractionTrigger 维护)。 public List currentChoices = new List(); /// 当前高亮(选中)的选项索引。 public int currentChoiceIndex { get; private set; } /// 当前激活的可交互对象(最近一次进入触发区的对象)。 public InteractableObjectBase currentInteractable { get; private set; } /// /// 当有 UIPage 打开时为 true,此时交互 UI 被挂起、交互操作被屏蔽。 /// private bool _isSuspended; public override void Initialize() { base.Initialize(); player.operationSc.OnInteract += ExecuteCurrentChoice; player.operationSc.OnNavigateInteractionChoice += NavigateChoice; // 订阅 UIPageManager 的输入阻塞事件,联动 InteractionUIArea 的显隐 if (UIPageManager.Instance != null) { UIPageManager.Instance.OnInputBlockChanged += OnUIInputBlockChanged; } } private void OnDestroy() { if (UIPageManager.Instance != null) { UIPageManager.Instance.OnInputBlockChanged -= OnUIInputBlockChanged; } } // ==================================================================== // UIPage 联动 // ==================================================================== /// /// 当任何 UIPage 打开/关闭时由 UIPageManager 触发。 /// blocked = true:有 UIPage 打开 → 挂起 InteractionUIArea(隐藏但不清除状态)。 /// blocked = false:所有 UIPage 关闭 → 若仍在交互范围内则恢复显示。 /// private void OnUIInputBlockChanged(bool blocked) { _isSuspended = blocked; if (blocked) { // 仅隐藏 UI,不清除 currentInteractable / currentChoices PlayerCanvas.InteractionUIArea?.Hide(); } else { // 所有页面关闭后,若仍在交互范围内,恢复 InteractionUIArea if (currentInteractable != null && currentChoices.Count > 0) { PlayerCanvas.InteractionUIArea?.Show(currentChoices, currentChoiceIndex); } } } // ==================================================================== // 进入 / 离开触发区 // ==================================================================== /// 由 InteractionTrigger 在进入触发区时调用,记录当前激活对象并显示选项 UI。 public void SetCurrentInteractable(InteractableObjectBase interactable) { currentInteractable = interactable; currentChoiceIndex = 0; // 自动跳到第一个可用的选项 SnapToFirstInteractable(); // 若当前没有 UIPage 打开,才显示交互选项 if (!_isSuspended) { PlayerCanvas.InteractionUIArea?.Show(currentChoices, currentChoiceIndex); } } /// 由 InteractionTrigger 在退出触发区时调用,清除当前激活对象并隐藏选项 UI。 public void RemoveCurrentInteractable(InteractableObjectBase interactable) { if (currentInteractable != interactable) return; currentInteractable = null; PlayerCanvas.InteractionUIArea?.Hide(); } // ==================================================================== // 导航与执行 // ==================================================================== /// /// 导航选中索引。delta = 1(向下/滚轮向下),delta = -1(向上/滚轮向上)。 /// 会自动跳过 isInteractable = false 的选项。 /// 若处于挂起状态(有 UIPage 打开),忽略导航。 /// public void NavigateChoice(int delta) { if (_isSuspended) return; if (currentChoices.Count == 0) return; int startIndex = currentChoiceIndex; int next = currentChoiceIndex; do { next = (next + delta + currentChoices.Count) % currentChoices.Count; if (next == startIndex) break; // 绕了一圈,无可用选项,保持原位 } while (!currentChoices[next].isInteractable); currentChoiceIndex = next; PlayerCanvas.InteractionUIArea?.UpdateHighlight(currentChoiceIndex); } /// /// 执行当前高亮的选项。若该选项 isInteractable = false 或处于挂起状态,则什么都不做。 /// public void ExecuteCurrentChoice() { if (_isSuspended) return; if (currentChoices.Count == 0) return; if (currentChoiceIndex < 0 || currentChoiceIndex >= currentChoices.Count) return; InteractionChoice choice = currentChoices[currentChoiceIndex]; if (!choice.isInteractable) { Debug.Log($"[InteractionSc] 选项 '{choice.choiceName}' 当前不可用。"); return; } choice.action?.Invoke(); } // ==================================================================== // 内部工具 // ==================================================================== /// 将 currentChoiceIndex 移到第一个 isInteractable = true 的选项。 private void SnapToFirstInteractable() { if (currentChoices.Count == 0) return; for (int i = 0; i < currentChoices.Count; i++) { int index = (currentChoiceIndex + i) % currentChoices.Count; if (currentChoices[index].isInteractable) { currentChoiceIndex = index; return; } } // 所有选项均不可用时,停在 0 currentChoiceIndex = 0; } } }