2025-08-28 15:07:36 +08:00
|
|
|
|
using System;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
using System.Collections.Generic;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
using System.Reflection;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
using Data;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
using EventWorkClass;
|
2025-08-28 15:07:36 +08:00
|
|
|
|
using Utils;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
using UnityEngine;
|
2025-09-08 00:13:12 +08:00
|
|
|
|
using Base;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
|
|
|
|
|
namespace Managers
|
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 事件管理器,负责事件的加载、注册和执行。
|
|
|
|
|
/// 遵循单例模式,并在启动流程中扮演一个管理器角色。
|
|
|
|
|
/// </summary>
|
2025-09-08 00:13:12 +08:00
|
|
|
|
class EventManager : Singleton<EventManager>, ILaunchManager, ITick // 实现 ITick 接口
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 存储所有已加载的事件定义,键为事件名称,值为对应的事件工作类实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Dictionary<string, EventWorkClassBase> EventDefs { get; private set; } = null;
|
|
|
|
|
|
2025-09-08 00:13:12 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 存储所有已加载的故事定义,键为故事名称,值为对应的故事定义实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public Dictionary<string, StoryDef> StoryDefs { get; private set; } = null;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 存储当前正在播放的所有故事实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly List<StoryPlayer> _activeStoryPlayers = new List<StoryPlayer>();
|
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取当前加载步骤的描述,用于启动流程的进度显示。
|
|
|
|
|
/// </summary>
|
2025-09-08 00:13:12 +08:00
|
|
|
|
public string StepDescription => "正在载入事件和故事";
|
2025-08-27 19:56:49 +08:00
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
2025-09-08 00:13:12 +08:00
|
|
|
|
/// 初始化事件管理器,从定义管理器中加载所有事件定义和故事定义。
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// </summary>
|
2025-08-28 15:07:36 +08:00
|
|
|
|
public void Init()
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
// 如果事件和故事定义已经加载,则直接返回,避免重复初始化。
|
|
|
|
|
if (EventDefs != null && StoryDefs != null)
|
2025-08-27 19:56:49 +08:00
|
|
|
|
return;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
|
2025-09-08 00:13:12 +08:00
|
|
|
|
// 从定义管理器查询并加载所有事件定义。
|
|
|
|
|
var eventDefs = DefineManager.Instance.QueryDefinesByType<EventDef>();
|
2025-09-03 18:13:29 +08:00
|
|
|
|
EventDefs = new Dictionary<string, EventWorkClassBase>();
|
2025-09-08 00:13:12 +08:00
|
|
|
|
var loadedEventCount = 0;
|
|
|
|
|
foreach (var def in eventDefs)
|
2025-09-03 18:13:29 +08:00
|
|
|
|
{
|
|
|
|
|
if (EventDefs.ContainsKey(def.defName))
|
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
Debug.LogWarning($"警告:事件名称重复,已跳过加载名称为 '{def.defName}' 的事件定义。");
|
2025-09-03 18:13:29 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var eventWorker = GetAndInstantiateEventWorker(def.workClass);
|
|
|
|
|
if (eventWorker == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:未能找到或实例化名称为 '{def.workClass}' 的事件工作类,已跳过加载名称为 '{def.defName}' 的事件定义。");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2025-09-08 00:13:12 +08:00
|
|
|
|
eventWorker.Init(def.parameter);
|
2025-09-03 18:13:29 +08:00
|
|
|
|
EventDefs.Add(def.defName, eventWorker);
|
2025-09-08 00:13:12 +08:00
|
|
|
|
loadedEventCount++;
|
|
|
|
|
}
|
|
|
|
|
Debug.Log($"事件管理器初始化完成,共载入 {loadedEventCount} 个事件。");
|
|
|
|
|
|
|
|
|
|
// 从定义管理器查询并加载所有故事定义。
|
|
|
|
|
var storyDefs = DefineManager.Instance.QueryDefinesByType<StoryDef>();
|
|
|
|
|
StoryDefs = new Dictionary<string, StoryDef>();
|
|
|
|
|
var loadedStoryCount = 0;
|
|
|
|
|
foreach (var storyDef in storyDefs)
|
|
|
|
|
{
|
|
|
|
|
if (StoryDefs.ContainsKey(storyDef.defName))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:故事名称重复,已跳过加载名称为 '{storyDef.defName}' 的故事定义。");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
StoryDefs.Add(storyDef.defName, storyDef);
|
|
|
|
|
loadedStoryCount++;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
}
|
2025-09-08 00:13:12 +08:00
|
|
|
|
Debug.Log($"事件管理器初始化完成,共载入 {loadedStoryCount} 个故事。");
|
|
|
|
|
|
|
|
|
|
// 将自身注册到时钟系统,以便每帧更新故事播放。
|
|
|
|
|
Clock.AddTick(this);
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
2025-09-08 00:13:12 +08:00
|
|
|
|
/// 清理事件管理器,释放所有已加载的事件和故事定义。
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// </summary>
|
2025-08-28 15:07:36 +08:00
|
|
|
|
public void Clear()
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
// 从时钟系统移除自身,停止接收Tick更新。
|
|
|
|
|
Clock.RemoveTick(this);
|
|
|
|
|
// 清理所有正在播放的故事实例。
|
|
|
|
|
_activeStoryPlayers.Clear();
|
|
|
|
|
// 释放事件定义字典。
|
2025-08-28 15:07:36 +08:00
|
|
|
|
EventDefs = null;
|
2025-09-08 00:13:12 +08:00
|
|
|
|
// 释放故事定义字典。
|
|
|
|
|
StoryDefs = null;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 执行指定名称的事件。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="eventName">要执行的事件的名称。</param>
|
|
|
|
|
/// <param name="dimensionID">事件执行的维度ID,如果为null,将使用当前焦点的维度ID。</param>
|
|
|
|
|
public void Action(string eventName, string dimensionID = null)
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
if (EventDefs == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"错误:事件管理器尚未初始化或已被清理。无法执行事件 '{eventName}'。");
|
2025-08-27 19:56:49 +08:00
|
|
|
|
return;
|
2025-09-03 18:13:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 00:13:12 +08:00
|
|
|
|
if (!EventDefs.TryGetValue(eventName, out var eventWorker))
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
Debug.LogWarning($"警告:未能找到名称为 '{eventName}' 的事件定义,已跳过执行该事件。");
|
|
|
|
|
return;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
2025-09-03 18:13:29 +08:00
|
|
|
|
// 假设 Program.Instance 和 FocusedDimensionId 存在且可访问。
|
|
|
|
|
// 如果 dimensionID 为 null,则使用当前焦点维度ID。
|
|
|
|
|
dimensionID ??= Program.Instance.FocusedDimensionId;
|
2025-09-08 00:13:12 +08:00
|
|
|
|
eventWorker.Run(dimensionID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 播放指定名称的故事。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="storyName">要播放的故事的名称。</param>
|
|
|
|
|
/// <param name="dimensionID">故事执行的维度ID,如果为null,将使用当前焦点的维度ID。</param>
|
|
|
|
|
public void PlayStory(string storyName, string dimensionID = null)
|
|
|
|
|
{
|
|
|
|
|
if (StoryDefs == null || StoryDefs.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"错误:故事定义尚未加载或已被清理。无法播放故事 '{storyName}'。");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!StoryDefs.TryGetValue(storyName, out var storyDef))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:未能找到名称为 '{storyName}' 的故事定义,已跳过播放该故事。");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (storyDef.storyStage == null || storyDef.storyStage.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:故事 '{storyDef.defName}' 没有定义任何阶段,已跳过播放。");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保 dimensionID 有效,如果为 null 则使用当前焦点维度ID。
|
|
|
|
|
dimensionID ??= Program.Instance.FocusedDimensionId;
|
|
|
|
|
|
|
|
|
|
// 创建一个新的 StoryPlayer 实例并添加到活跃列表中。
|
|
|
|
|
var player = new StoryPlayer(storyDef, dimensionID, this);
|
|
|
|
|
_activeStoryPlayers.Add(player);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 每帧更新,用于驱动所有活跃故事的播放逻辑。
|
|
|
|
|
/// 作为 <see cref="ITick"/> 接口的实现,由时钟系统调用。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Tick()
|
|
|
|
|
{
|
|
|
|
|
if (_activeStoryPlayers.Count == 0) return;
|
|
|
|
|
|
|
|
|
|
// 获取自上一帧以来的时间增量。
|
|
|
|
|
var deltaTime = Time.deltaTime;
|
|
|
|
|
|
|
|
|
|
// 遍历所有正在播放的故事实例,并更新它们的状态。
|
|
|
|
|
// 为了避免在迭代过程中修改列表,先收集要移除的,再统一移除。
|
|
|
|
|
var playersToRemove = new List<StoryPlayer>();
|
|
|
|
|
foreach (var player in _activeStoryPlayers)
|
|
|
|
|
{
|
|
|
|
|
player.Update(deltaTime);
|
|
|
|
|
if (player.IsFinished)
|
|
|
|
|
{
|
|
|
|
|
playersToRemove.Add(player);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 移除所有已完成的故事实例。
|
|
|
|
|
foreach (var player in playersToRemove)
|
|
|
|
|
{
|
|
|
|
|
_activeStoryPlayers.Remove(player);
|
|
|
|
|
}
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
2025-09-03 18:13:29 +08:00
|
|
|
|
|
2025-09-08 00:13:12 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 将字符串颜色值解析为 <see cref="Color"/> 对象。
|
|
|
|
|
/// 支持十六进制颜色(如 "#RRGGBB" 或 "#AARRGGBB")或标准颜色名称。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="colorString">颜色字符串。</param>
|
|
|
|
|
/// <returns>解析后的 <see cref="Color"/> 对象。如果解析失败,返回白色。</returns>
|
|
|
|
|
private Color ParseColor(string colorString)
|
|
|
|
|
{
|
|
|
|
|
if (ColorUtility.TryParseHtmlString(colorString, out var color))
|
|
|
|
|
{
|
|
|
|
|
return color;
|
|
|
|
|
}
|
|
|
|
|
Debug.LogWarning($"警告:无法解析颜色字符串 '{colorString}'。使用默认白色。");
|
|
|
|
|
return Color.white; // 默认返回白色
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据类名从指定命名空间和程序集下获取并实例化一个 <see cref="EventWorkClassBase"/> 的子类。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="className">要实例化的类的短名称(不包含命名空间)。</param>
|
|
|
|
|
/// <param name="targetNamespace">目标类所在的完整命名空间。</param>
|
|
|
|
|
/// <param name="assemblyToSearch">要搜索的程序集。如果为 null,将搜索 <see cref="EventWorkClassBase"/> 所在的程序集。</param>
|
|
|
|
|
/// <returns>实例化后的 <see cref="EventWorkClassBase"/> 对象,如果找不到或不符合条件则返回 null。</returns>
|
|
|
|
|
public static EventWorkClassBase GetAndInstantiateEventWorker(
|
|
|
|
|
string className,
|
|
|
|
|
string targetNamespace = "EventWorkClass", // 默认命名空间
|
|
|
|
|
Assembly assemblyToSearch = null) // 默认程序集
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
// 1. 确定要搜索的程序集。
|
|
|
|
|
if (assemblyToSearch == null)
|
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
// 默认从 EventWorkClassBase 所在的程序集查找,通常其实现类也位于此程序集。
|
2025-09-03 18:13:29 +08:00
|
|
|
|
assemblyToSearch = typeof(EventWorkClassBase).Assembly;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 构造完整的类型名称。
|
2025-09-06 12:25:55 +08:00
|
|
|
|
var fullTypeName = $"{targetNamespace}.{className}";
|
2025-09-03 18:13:29 +08:00
|
|
|
|
Type targetType = null;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
// 3. 尝试直接从程序集获取类型。
|
|
|
|
|
targetType = assemblyToSearch.GetType(fullTypeName);
|
2025-08-27 19:56:49 +08:00
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
// 4. 进行类型检查。
|
|
|
|
|
if (targetType == null)
|
2025-08-27 19:56:49 +08:00
|
|
|
|
{
|
2025-09-03 18:13:29 +08:00
|
|
|
|
Debug.LogError($"错误:在程序集 '{assemblyToSearch.FullName}' 的命名空间 '{targetNamespace}' 中未找到类 '{className}'。");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
// 检查是否是 EventWorkClassBase 的子类。
|
|
|
|
|
if (!typeof(EventWorkClassBase).IsAssignableFrom(targetType))
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"错误:类 '{fullTypeName}' 不是 '{typeof(EventWorkClassBase).FullName}' 的子类。");
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
// 检查是否可以实例化(非抽象类,非接口)。
|
|
|
|
|
if (targetType.IsAbstract || targetType.IsInterface)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"错误:类 '{fullTypeName}' 是抽象类或接口,不能直接实例化。");
|
|
|
|
|
return null;
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 18:13:29 +08:00
|
|
|
|
// 5. 实例化对象。
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 使用 Activator.CreateInstance 实例化对象。它默认调用无参公共构造函数。
|
2025-09-06 12:25:55 +08:00
|
|
|
|
var instance = Activator.CreateInstance(targetType);
|
2025-09-03 18:13:29 +08:00
|
|
|
|
return instance as EventWorkClassBase;
|
|
|
|
|
}
|
|
|
|
|
catch (MissingMethodException ex)
|
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
Debug.LogError($"错误:类 '{fullTypeName}' 没有公共的无参构造函数。详细信息: {ex.Message}");
|
2025-09-03 18:13:29 +08:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
2025-09-08 00:13:12 +08:00
|
|
|
|
Debug.LogError($"实例化类 '{fullTypeName}' 时发生未知错误。详细信息: {ex.Message}");
|
2025-09-03 18:13:29 +08:00
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-08 00:13:12 +08:00
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 表示一个正在播放的故事实例的状态机。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private class StoryPlayer
|
|
|
|
|
{
|
|
|
|
|
/// <summary> 故事播放阶段的状态枚举。 </summary>
|
|
|
|
|
private enum State
|
|
|
|
|
{
|
|
|
|
|
Initializing, // 刚开始,准备处理第一个阶段的 lastWaitTime
|
|
|
|
|
WaitingLastTime, // 等待当前阶段的 lastWaitTime
|
|
|
|
|
ExecutingStage, // 执行当前阶段的事件/消息
|
|
|
|
|
WaitingNextTime, // 等待当前阶段的 nextWaitTime
|
|
|
|
|
Finished // 故事播放完毕
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary> 获取当前正在播放的故事定义。 </summary>
|
|
|
|
|
public StoryDef StoryDef { get; private set; }
|
|
|
|
|
/// <summary> 获取故事播放所在的维度ID。 </summary>
|
|
|
|
|
public string DimensionID { get; private set; }
|
|
|
|
|
/// <summary> 获取一个值,表示故事是否已播放完毕。 </summary>
|
|
|
|
|
public bool IsFinished { get; private set; } = false;
|
|
|
|
|
|
|
|
|
|
// 事件管理器实例,用于调用 Action 和 ParseColor 方法。
|
|
|
|
|
private readonly EventManager _eventManager;
|
|
|
|
|
// 当前故事阶段的索引。
|
|
|
|
|
private int _currentStageIndex;
|
|
|
|
|
// 当前阶段的等待计时器。
|
|
|
|
|
private float _currentWaitTimer;
|
|
|
|
|
// 当前故事播放器所处的状态。
|
|
|
|
|
private State _currentState;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化 <see cref="StoryPlayer"/> 类的新实例。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="storyDef">要播放的故事定义。</param>
|
|
|
|
|
/// <param name="dimensionId">故事播放所在的维度ID。</param>
|
|
|
|
|
/// <param name="eventManager">事件管理器实例,用于执行事件和解析颜色。</param>
|
|
|
|
|
public StoryPlayer(StoryDef storyDef, string dimensionId, EventManager eventManager)
|
|
|
|
|
{
|
|
|
|
|
StoryDef = storyDef;
|
|
|
|
|
DimensionID = dimensionId;
|
|
|
|
|
_eventManager = eventManager;
|
|
|
|
|
_currentStageIndex = 0;
|
|
|
|
|
_currentWaitTimer = 0f;
|
|
|
|
|
_currentState = State.Initializing;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 每帧更新故事播放器的状态。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="deltaTime">自上一帧以来的时间增量。</param>
|
|
|
|
|
public void Update(float deltaTime)
|
|
|
|
|
{
|
|
|
|
|
if (IsFinished) return;
|
|
|
|
|
|
|
|
|
|
// 如果故事阶段定义为null或为空,则立即标记故事完成。
|
|
|
|
|
if (StoryDef.storyStage == null || StoryDef.storyStage.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:故事 '{StoryDef.defName}' 没有定义任何阶段,StoryPlayer 将立即完成。");
|
|
|
|
|
IsFinished = true;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var currentStage = StoryDef.storyStage[_currentStageIndex];
|
|
|
|
|
|
|
|
|
|
switch (_currentState)
|
|
|
|
|
{
|
|
|
|
|
case State.Initializing:
|
|
|
|
|
// 从当前阶段的 lastWaitTime 开始等待,如果 lastWaitTime 小于等于 0 则直接跳过等待执行阶段。
|
|
|
|
|
if (currentStage.lastWaitTime > 0)
|
|
|
|
|
{
|
|
|
|
|
_currentState = State.WaitingLastTime;
|
|
|
|
|
_currentWaitTimer = 0f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 没有 lastWaitTime,直接执行阶段。
|
|
|
|
|
_currentState = State.ExecutingStage;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case State.WaitingLastTime:
|
|
|
|
|
_currentWaitTimer += deltaTime;
|
|
|
|
|
if (_currentWaitTimer >= currentStage.lastWaitTime)
|
|
|
|
|
{
|
|
|
|
|
// 等待时间已到,切换到执行阶段。
|
|
|
|
|
_currentWaitTimer = 0f;
|
|
|
|
|
_currentState = State.ExecutingStage;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case State.ExecutingStage:
|
|
|
|
|
// 处理事件
|
|
|
|
|
if (currentStage.eventDef != null)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrEmpty(currentStage.eventDef.defName))
|
|
|
|
|
{
|
|
|
|
|
_eventManager.Action(currentStage.eventDef.defName, DimensionID);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Debug.LogWarning($"警告:故事 '{StoryDef.defName}' 阶段 {_currentStageIndex} 包含一个没有定义名称的事件,已跳过。");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理消息
|
|
|
|
|
if (currentStage.messageDef != null)
|
|
|
|
|
{
|
|
|
|
|
if (MessageManager.Instance == null)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"错误:MessageManager 实例不存在,无法显示故事 '{StoryDef.defName}' 的消息。");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var messageColor = _eventManager.ParseColor(currentStage.messageDef.color);
|
|
|
|
|
MessageManager.Instance.DisplayMessage(currentStage.messageDef.text, currentStage.messageDef.type, messageColor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 决定下一个状态
|
|
|
|
|
if (currentStage.nextWaitTime > 0)
|
|
|
|
|
{
|
|
|
|
|
_currentState = State.WaitingNextTime;
|
|
|
|
|
_currentWaitTimer = 0f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 没有 nextWaitTime,直接推进到下一个阶段。
|
|
|
|
|
AdvanceToNextStage();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case State.WaitingNextTime:
|
|
|
|
|
_currentWaitTimer += deltaTime;
|
|
|
|
|
if (_currentWaitTimer >= currentStage.nextWaitTime)
|
|
|
|
|
{
|
|
|
|
|
// 等待时间已到,推进到下一个阶段。
|
|
|
|
|
_currentWaitTimer = 0f;
|
|
|
|
|
AdvanceToNextStage();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case State.Finished:
|
|
|
|
|
// 故事已经完成,不再更新。
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 推进到下一个故事阶段,或标记故事完成。
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void AdvanceToNextStage()
|
|
|
|
|
{
|
|
|
|
|
_currentStageIndex++;
|
|
|
|
|
if (_currentStageIndex < StoryDef.storyStage.Length)
|
|
|
|
|
{
|
|
|
|
|
// 还有后续阶段,重置状态以处理下一个阶段的 lastWaitTime。
|
|
|
|
|
_currentState = State.Initializing;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 所有阶段播放完毕,标记故事完成。
|
|
|
|
|
_currentState = State.Finished;
|
|
|
|
|
IsFinished = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-27 19:56:49 +08:00
|
|
|
|
}
|
2025-09-03 18:13:29 +08:00
|
|
|
|
}
|