StorySystem

This commit is contained in:
SoulliesOfficial
2026-07-07 01:28:27 -04:00
parent d031afd075
commit 7b7d069b84
105 changed files with 4852 additions and 2734 deletions

View File

@@ -0,0 +1,93 @@
using Sirenix.OdinInspector;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using Yarn.Unity;
namespace Ichni.Story.Dialogue
{
/// <summary>
/// 单个对话选项按钮的显示与交互控制器。
/// <para>
/// <list type="bullet">
/// <item><b>可用选项</b>:显示 <see cref="availableSprite"/>,点击时触发 <c>onSelected</c> 回调。</item>
/// <item><b>不可用选项</b>:显示 <see cref="unavailableSprite"/>,点击无效(但 Button 的
/// <c>interactable</c> 保持开启,以备未来扩展悬停提示等功能)。</item>
/// </list>
/// </para>
/// <para>
/// 由 <see cref="VNDialoguePresenter"/> 统一调用 <see cref="Setup"/> / <see cref="Cleanup"/>。
/// </para>
/// </summary>
public class ChoiceButton : MonoBehaviour
{
[Tooltip("按钮组件引用(挂载在同 GameObject 上的 Button。")]
public Button button;
[Tooltip("按钮背景 Image用于在 available / unavailable 状态间切换 Sprite。")]
public Image buttonBackground;
[Tooltip("选项文本 TMP。")]
public TMP_Text buttonText;
[SerializeField, HideInPlayMode]
[Tooltip("选项可用时的背景 Sprite。")]
private Sprite availableSprite;
[SerializeField, HideInPlayMode]
[Tooltip("选项不可用时的背景 Sprite。")]
private Sprite unavailableSprite;
// ── 运行时状态 ────────────────────────────────────────────────────
/// <summary>当前绑定的选项是否可供玩家选择。</summary>
private bool _isAvailable;
// ── 公共 API ─────────────────────────────────────────────────────
/// <summary>
/// 根据 <paramref name="option"/> 配置按钮并激活显示。
/// </summary>
/// <param name="option">Yarn 对话选项数据。<c>option.IsAvailable</c> 决定外观与交互行为。</param>
/// <param name="onSelected">
/// 玩家点击且选项可用时触发的回调。
/// 不可用选项点击不会触发此回调,但按钮保持 <c>interactable=true</c>。
/// </param>
public void Setup(DialogueOption option, System.Action<DialogueOption> onSelected)
{
gameObject.SetActive(true);
_isAvailable = option.IsAvailable;
// 设置选项文本
if (buttonText != null)
buttonText.text = option.Line.TextWithoutCharacterName.Text;
// 根据可用性切换背景图
if (buttonBackground != null)
buttonBackground.sprite = _isAvailable ? availableSprite : unavailableSprite;
// 注册点击监听:不可用选项点击静默忽略
if (button != null)
{
button.onClick.RemoveAllListeners();
button.onClick.AddListener(() =>
{
if (_isAvailable)
onSelected?.Invoke(option);
});
}
}
/// <summary>
/// 清除按钮监听并隐藏此按钮。
/// 在 <see cref="VNDialoguePresenter.RunOptionsAsync"/> 结束后统一调用。
/// </summary>
public void Cleanup()
{
if (button != null)
button.onClick.RemoveAllListeners();
gameObject.SetActive(false);
}
}
}