using System.Collections.Generic; using Cielonos.Core.Interaction; using DG.Tweening; using Sirenix.OdinInspector; using SLSUtilities.UI; using UnityEngine; namespace Cielonos.UI { /// /// 交互选项列表 UI 页面。 /// 玩家进入可交互物体范围时由 PlayerInteractionSubcontroller 调用 Show(),离开时调用 Hide()。 /// 当选项数量为 1 时,直接显示单个选项而不需要导航; /// 当选项数量大于 1 时,玩家可用鼠标滚轮或上/下键切换高亮选项,R 键执行。 /// public class InteractionUIArea : UIElementBase { [Title("容器")] [Tooltip("单个选项条目的预制体,需包含 InteractionChoiceItem 组件。")] [SerializeField] private GameObject choiceItemPrefab; [Tooltip("选项条目的父节点(Layout Group)。")] [SerializeField] private RectTransform choiceContainer; private readonly List _items = new List(); private void Start() { Hide(); } // ==================================================================== // 对外接口 // ==================================================================== /// /// 显示选项列表并高亮指定索引的选项。 /// 由 PlayerInteractionSubcontroller.SetCurrentInteractable() 调用。 /// public void Show(List choices, int selectedIndex) { gameObject.SetActive(true); canvasGroup.DOFade(1f, 0.25f).From(0).OnComplete(() => { canvasGroup.interactable = true; canvasGroup.blocksRaycasts = true; }).Play(); rectTransform.DOLocalMoveY(-50f, 0.25f).From(-250f).Play(); ClearItems(); if (choices == null || choices.Count == 0) { gameObject.SetActive(false); return; } foreach (InteractionChoice choice in choices) { InteractionChoiceItem item = CreateItem(); if (item != null) { item.Setup(choice.choiceName, choice.isInteractable); } } UpdateHighlight(selectedIndex); } /// /// 更新高亮选项。由 PlayerInteractionSubcontroller.NavigateChoice() 调用。 /// public void UpdateHighlight(int selectedIndex) { for (int i = 0; i < _items.Count; i++) { _items[i].SetHighlighted(i == selectedIndex); } } /// /// 隐藏选项列表。由 PlayerInteractionSubcontroller.RemoveCurrentInteractable() 调用。 /// public override void Hide() { canvasGroup.interactable = false; canvasGroup.blocksRaycasts = false; canvasGroup.DOFade(0f, 0.25f).OnComplete(() => { ClearItems(); gameObject.SetActive(false); }).Play(); rectTransform.DOLocalMoveY(-250f, 0.25f).Play(); } // ==================================================================== // 内部工具 // ==================================================================== private InteractionChoiceItem CreateItem() { if (choiceItemPrefab == null || choiceContainer == null) { Debug.LogError("[InteractionUIPage] choiceItemPrefab 或 choiceContainer 未在 Inspector 中配置。"); return null; } GameObject go = Instantiate(choiceItemPrefab, choiceContainer); InteractionChoiceItem item = go.GetComponent(); if (item == null) { Debug.LogError("[InteractionUIPage] choiceItemPrefab 缺少 InteractionChoiceItem 组件。"); Destroy(go); return null; } _items.Add(item); return item; } private void ClearItems() { foreach (InteractionChoiceItem item in _items) { if (item != null) Destroy(item.gameObject); } _items.Clear(); } } }