130 lines
4.4 KiB
C#
130 lines
4.4 KiB
C#
using System.Collections.Generic;
|
||
using Cielonos.Core.Interaction;
|
||
using DG.Tweening;
|
||
using Sirenix.OdinInspector;
|
||
using SLSUtilities.UI;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.UI
|
||
{
|
||
/// <summary>
|
||
/// 交互选项列表 UI 页面。
|
||
/// 玩家进入可交互物体范围时由 PlayerInteractionSubcontroller 调用 Show(),离开时调用 Hide()。
|
||
/// 当选项数量为 1 时,直接显示单个选项而不需要导航;
|
||
/// 当选项数量大于 1 时,玩家可用鼠标滚轮或上/下键切换高亮选项,R 键执行。
|
||
/// </summary>
|
||
public class InteractionUIArea : UIElementBase
|
||
{
|
||
[Title("容器")]
|
||
[Tooltip("单个选项条目的预制体,需包含 InteractionChoiceItem 组件。")]
|
||
[SerializeField] private GameObject choiceItemPrefab;
|
||
|
||
[Tooltip("选项条目的父节点(Layout Group)。")]
|
||
[SerializeField] private RectTransform choiceContainer;
|
||
|
||
private readonly List<InteractionChoiceItem> _items = new List<InteractionChoiceItem>();
|
||
|
||
private void Start()
|
||
{
|
||
Hide();
|
||
}
|
||
|
||
// ====================================================================
|
||
// 对外接口
|
||
// ====================================================================
|
||
|
||
/// <summary>
|
||
/// 显示选项列表并高亮指定索引的选项。
|
||
/// 由 PlayerInteractionSubcontroller.SetCurrentInteractable() 调用。
|
||
/// </summary>
|
||
public void Show(List<InteractionChoice> 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);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新高亮选项。由 PlayerInteractionSubcontroller.NavigateChoice() 调用。
|
||
/// </summary>
|
||
public void UpdateHighlight(int selectedIndex)
|
||
{
|
||
for (int i = 0; i < _items.Count; i++)
|
||
{
|
||
_items[i].SetHighlighted(i == selectedIndex);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 隐藏选项列表。由 PlayerInteractionSubcontroller.RemoveCurrentInteractable() 调用。
|
||
/// </summary>
|
||
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<InteractionChoiceItem>();
|
||
|
||
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();
|
||
}
|
||
}
|
||
} |