2026-06-05 04:21:00 -04:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2026-06-02 12:55:39 -04:00
|
|
|
|
using Cielonos.Core.Interaction;
|
|
|
|
|
|
using Cielonos.MainGame.Narrative;
|
|
|
|
|
|
using Sirenix.OdinInspector;
|
2026-06-05 04:21:00 -04:00
|
|
|
|
using SLSUtilities.FunctionalAnimation;
|
|
|
|
|
|
using SLSUtilities.Narrative;
|
2026-06-02 12:55:39 -04:00
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Cielonos.MainGame.Interactions
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// NPC 交互基类。
|
|
|
|
|
|
/// 场景中的 NPC 挂载此脚本,交互时会自动将自身的 storyId 投递给 StoryDirector。
|
|
|
|
|
|
/// </summary>
|
2026-06-05 04:21:00 -04:00
|
|
|
|
public class NpcBase : InteractableObjectBase, IFuncAnimExecutor
|
2026-06-02 12:55:39 -04:00
|
|
|
|
{
|
2026-06-05 04:21:00 -04:00
|
|
|
|
#region Fields & Properties
|
|
|
|
|
|
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
protected CharacterData characterData;
|
|
|
|
|
|
|
2026-06-02 12:55:39 -04:00
|
|
|
|
[TitleGroup("Story Settings", "剧情与对话路由配置", Alignment = TitleAlignments.Centered)]
|
|
|
|
|
|
[SerializeField]
|
|
|
|
|
|
[Tooltip("对应 NarrativeEntry 剧情路由表中的 storyId (如 'OldMan')")]
|
|
|
|
|
|
protected string storyId;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>NPC 的唯一故事 ID。</summary>
|
|
|
|
|
|
public string StoryId => storyId;
|
|
|
|
|
|
|
2026-06-05 04:21:00 -04:00
|
|
|
|
[TitleGroup("Components & References", "组件与动作数据引用", Alignment = TitleAlignments.Centered)]
|
|
|
|
|
|
public Animator animator;
|
|
|
|
|
|
public AnimatorOverrideController animatorOverride;
|
|
|
|
|
|
public FuncAnimDataCollection fullBodyFuncAnims;
|
|
|
|
|
|
public VFXData vfxData;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>NPC 专属动画播放子模块</summary>
|
|
|
|
|
|
[HideInInspector]
|
|
|
|
|
|
public NpcFuncAnimSubmodule funcAnimSm;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>全局活跃 NPC 查找注册表 (通过 StoryId 和 GameObject 名字进行双重映射查找)</summary>
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region IFuncAnimExecutor Implementation
|
|
|
|
|
|
|
|
|
|
|
|
public Transform Transform => transform;
|
|
|
|
|
|
public Vector3 CenterPosition => transform.position;
|
|
|
|
|
|
public Animator Animator => animator;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Lifecycle Callbacks
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void OnEnable()
|
|
|
|
|
|
{
|
|
|
|
|
|
StoryDirector.ActiveNpcs[characterData.nameKey] = this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void OnDisable()
|
|
|
|
|
|
{
|
|
|
|
|
|
StoryDirector.ActiveNpcs.Remove(characterData.nameKey);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Start()
|
|
|
|
|
|
{
|
|
|
|
|
|
funcAnimSm = new NpcFuncAnimSubmodule(this);
|
|
|
|
|
|
if (fullBodyFuncAnims != null && fullBodyFuncAnims.animDataList != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (FuncAnimData animData in fullBodyFuncAnims.animDataList)
|
|
|
|
|
|
{
|
|
|
|
|
|
funcAnimSm.Add(animData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 推进时间、检测非循环动作结束以及执行重置
|
|
|
|
|
|
funcAnimSm?.Update(Time.deltaTime);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected virtual void LateUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 在物理表现计算完毕后分发每帧的特效/音效等事件
|
|
|
|
|
|
funcAnimSm?.UpdateEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Interaction Logic
|
|
|
|
|
|
|
2026-06-02 12:55:39 -04:00
|
|
|
|
protected override void InitializeChoices()
|
|
|
|
|
|
{
|
|
|
|
|
|
choices.Add(new InteractionChoice("Talk", Talk));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 触发对话。NPC 并不感知具体播放哪个 Yarn 节点,完全委托给 StoryDirector 进行状态评估。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public virtual void Talk()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(storyId))
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogWarning($"[NpcBase] {gameObject.name} 未配置 storyId,无法启动对话。");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (StoryDirector.Instance == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("[NpcBase] 启动对话失败:场景中未找到 StoryDirector 实例!");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
StoryDirector.Instance.PlayStory(storyId);
|
|
|
|
|
|
}
|
2026-06-05 04:21:00 -04:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
2026-06-02 12:55:39 -04:00
|
|
|
|
}
|
|
|
|
|
|
}
|