Files
Cielonos/Assets/Scripts/MainGame/Interactions/NPCs/NpcBase.cs
SoulliesOfficial 7bc1e1722c 爆更
2026-06-05 04:21:00 -04:00

120 lines
3.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using Cielonos.Core.Interaction;
using Cielonos.MainGame.Narrative;
using Sirenix.OdinInspector;
using SLSUtilities.FunctionalAnimation;
using SLSUtilities.Narrative;
using UnityEngine;
namespace Cielonos.MainGame.Interactions
{
/// <summary>
/// NPC 交互基类。
/// 场景中的 NPC 挂载此脚本,交互时会自动将自身的 storyId 投递给 StoryDirector。
/// </summary>
public class NpcBase : InteractableObjectBase, IFuncAnimExecutor
{
#region Fields & Properties
[SerializeField]
protected CharacterData characterData;
[TitleGroup("Story Settings", "剧情与对话路由配置", Alignment = TitleAlignments.Centered)]
[SerializeField]
[Tooltip("对应 NarrativeEntry 剧情路由表中的 storyId (如 'OldMan')")]
protected string storyId;
/// <summary>NPC 的唯一故事 ID。</summary>
public string StoryId => storyId;
[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
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);
}
#endregion
}
}