(clienr) feat:事件定义

This commit is contained in:
m0_75251201
2025-08-28 15:07:36 +08:00
parent 9713ad9129
commit 56956f351f
17 changed files with 305 additions and 3063 deletions

View File

@ -1,43 +1,70 @@
// C#
using System.Collections; using System.Collections;
using System.Collections.Generic; // 新增用于List using System.Collections.Generic; // 提供List等通用集合类型
using Logging; using Logging; // 提供日志记录功能
using Managers; // 确保日志命名空间正确 using Managers; // 提供管理器接口和实现
using TMPro; using TMPro; // TextMeshPro文本组件命名空间
using UnityEngine; using UnityEngine; // Unity引擎核心命名空间
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement; // 场景管理命名空间
namespace Base namespace Base
{ {
// 请确保你在Unity Editor中将 'projectile' 的Inspector引用从 Gradient 更改为 CustomProgressBar /// <summary>
// 或者替换为你实际的进度条组件类型 /// <c>Launcher</c> 类负责管理游戏的初始化加载流程,包括管理器加载、进度条显示和场景切换
// 如果你没有 CustomProgressBar而想用 Image 或者别的,这些 Progress/Opacity 属性需要大幅修改。 /// </summary>
/// <remarks>
/// <para>请注意:虽然此处的 <c>progressBar</c> 变量类型被声明为 <c>Gradient</c>
/// 但其在代码中的使用方式(如访问 <c>color1</c>, <c>color2</c> 属性和调用 <c>Refresh()</c> 方法)
/// 强烈暗示它应引用一个具有类似 API 的自定义进度条组件,例如 <c>CustomProgressBar</c>。</para>
/// <para>如果您使用的是标准 <c>UnityEngine.UI.Image</c> 或其他组件来显示进度,
/// 则 <c>Progress</c> 和 <c>Opacity</c> 属性的实现逻辑需要根据实际组件的 API 进行大幅修改。</para>
/// </remarks>
public class Launcher : MonoBehaviour public class Launcher : MonoBehaviour
{ {
/// <summary>
/// 加载界面UI的根游戏对象。
/// </summary>
public GameObject loadingUI; public GameObject loadingUI;
// 假设 CustomProgressBar 是一个自定义组件,其 API 与原代码使用方式一致
// 如果这里是 UnityEngine.UI.Image需要完全改变 Progress 和 Opacity 的实现
public Gradient progressBar; // 自定义进度条组件
public TMP_Text describeText; // 描述文本
public float duration = 0.5f; // 每个步骤的过渡时间 /// <summary>
public float fadeDuration = 2f; // 不透明度渐隐的时间 /// 用于显示加载进度的自定义进度条组件。
/// <para>请参阅类注释以了解其声明类型与预期API的差异。</para>
/// </summary>
public Gradient progressBar;
private float _currentProgressValue = 0f; // 实际的当前进度值0-1 /// <summary>
private Color _initialTextColor; // 原始文本颜色,用于渐隐 /// 用于显示当前加载步骤描述的文本组件。
private Color _initialProgressBarColor1; // 原始进度条颜色1 /// </summary>
private Color _initialProgressBarColor2; // 原始进度条颜色2 public TMP_Text describeText;
// 存储所有需要加载和清理的管理器 /// <summary>
/// 进度条每个加载步骤的平滑过渡时间(秒)。
/// </summary>
public float duration = 0.5f;
/// <summary>
/// 加载完成后UI元素渐隐的时间
/// </summary>
public float fadeDuration = 2f;
private float _currentProgressValue = 0f; // 实际的当前进度值在0到1之间
private Color _initialTextColor; // 描述文本的原始颜色,用于渐隐效果
private Color _initialProgressBarColor1; // 进度条颜色1的原始值用于渐变
private Color _initialProgressBarColor2; // 进度条颜色2的原始值用于渐变
/// <summary>
/// 存储所有需要在启动时加载和在重载时清理的管理器实例列表。
/// </summary>
private List<ILaunchManager> _managersToLoad; private List<ILaunchManager> _managersToLoad;
// Progress 属性,更新进度条和颜色 /// <summary>
/// 获取或设置加载进度值范围为0到1。
/// 设置此属性将更新进度条的视觉显示和颜色。
/// </summary>
public float Progress public float Progress
{ {
set set
{ {
// 确保进度值在0到1之间提高健壮性 // 确保进度值在0到1之间提高系统健壮性
_currentProgressValue = Mathf.Clamp01(value); _currentProgressValue = Mathf.Clamp01(value);
if (progressBar) if (progressBar)
@ -50,17 +77,23 @@ namespace Base
} }
else else
{ {
// 后半段color2 保持白色color1 从初始色渐变到白色
progressBar.color2 = Color.white; progressBar.color2 = Color.white;
// 后半段color2 保持白色color1 从初始色渐变到白色
progressBar.color1 = Color.Lerp(_initialProgressBarColor1, Color.white, (_currentProgressValue - 0.5f) * 2); progressBar.color1 = Color.Lerp(_initialProgressBarColor1, Color.white, (_currentProgressValue - 0.5f) * 2);
} }
progressBar.Refresh(); // 通知自定义进度条组件更新显示 // 通知自定义进度条组件更新显示
// 注意UnityEngine.Gradient 作为数据结构没有 Refresh() 方法,
// 此调用表明 progressBar 实际上预期是一个具有此方法的自定义组件。
progressBar.Refresh();
} }
} }
get => _currentProgressValue; get => _currentProgressValue;
} }
// Opacity 属性,更新 UI 元素的透明度 /// <summary>
/// 获取或设置UI元素的整体不透明度范围0完全透明到1完全不透明
/// 设置此属性将更新进度条和描述文本的透明度。
/// </summary>
public float Opacity public float Opacity
{ {
set set
@ -78,38 +111,43 @@ namespace Base
c2.a = alpha; c2.a = alpha;
progressBar.color2 = c2; progressBar.color2 = c2;
// 通知自定义进度条组件更新显示。
// 注意UnityEngine.Gradient 作为数据结构没有 Refresh() 方法,
// 此调用表明 progressBar 实际上预期是一个具有此方法的自定义组件。
progressBar.Refresh(); progressBar.Refresh();
} }
if (describeText) if (describeText)
{ {
// 更新描述文本颜色的透明度 // 更新描述文本颜色的透明度
// 渐隐时,描述文本的透明度在 Opacity > 0.5f 时才开始渐变可见 // 渐隐时,描述文本的透明度在 Opacity > 0.5f 时才开始从0渐变到其原始透明度
var textAlpha = alpha > 0.5f ? Mathf.Lerp(0f, _initialTextColor.a, (alpha - 0.5f) * 2) : 0f; var textAlpha = alpha > 0.5f ? Mathf.Lerp(0f, _initialTextColor.a, (alpha - 0.5f) * 2) : 0f;
describeText.color = new Color(_initialTextColor.r, _initialTextColor.g, _initialTextColor.b, textAlpha); describeText.color = new Color(_initialTextColor.r, _initialTextColor.g, _initialTextColor.b, textAlpha);
} }
} }
} }
/// <summary>
/// 当脚本实例被启用时调用一次。
/// 用于初始化管理器列表并缓存UI元素的初始颜色。
/// </summary>
private void Awake() private void Awake()
{ {
// 在 Awake 中初始化管理器列表并注册,确保在 Start 之前完成 // 在 Awake 中初始化管理器列表,确保在 Start 之前完成所有管理器实例的注册
_managersToLoad = new List<ILaunchManager> _managersToLoad = new List<ILaunchManager>
{ {
new Logging.LoggerManagerWrapper(), // UnityLogger的包装器 new LoggerManagerWrapper(), // Unity日志的包装器
Managers.DefineManager.Instance, DefineManager.Instance,
Managers.PackagesImageManager.Instance, PackagesImageManager.Instance,
Managers.TileManager.Instance, TileManager.Instance,
Managers.AffiliationManager.Instance, AffiliationManager.Instance,
Managers.ItemResourceManager.Instance ItemResourceManager.Instance,
// 当未来有新的管理器时,只需在这里添加 Managers.NewManager.Instance EventManager.Instance,
}; };
// 缓存UI的初始颜色以便后续操作或重置 // 缓存UI的初始颜色以便后续操作(如渐隐)或重置
if (describeText != null) _initialTextColor = describeText != null ? describeText.color : Color.white; // 如果为空,则使用默认值
{
_initialTextColor = describeText.color;
}
if (progressBar != null) if (progressBar != null)
{ {
_initialProgressBarColor1 = progressBar.color1; _initialProgressBarColor1 = progressBar.color1;
@ -117,61 +155,66 @@ namespace Base
} }
else else
{ {
Debug.LogWarning("CustomProgressBar component not assigned to Launcher. Progress bar display may not work."); // 警告日志:自定义进度条组件未赋值给启动器。
Debug.LogWarning("自定义进度条组件未赋值给启动器,进度条可能无法正常显示。");
} }
} }
/// <summary>
/// 在Awake方法之后、首次帧更新之前调用。
/// 用于判断是否需要执行完整的加载流程并根据需要启动加载或隐藏加载UI。
/// </summary>
private void Start() private void Start()
{ {
// 如果 Program.Instance.needLoad 为 true表示需要完整的重新加载流程 // 如果 Program.Instance.needLoad 为 false表示游戏已加载或不需要重新加载直接隐藏加载UI
// 否则如果不需要加载直接禁用UI并返回
if (!Program.Instance.needLoad) if (!Program.Instance.needLoad)
{ {
loadingUI.SetActive(false); loadingUI.SetActive(false);
return; return;
} }
// 根据 Program.Instance.needLoad 的含义(需要重载), // 如果需要加载,则先清理所有管理器(用于重载或确保干净启动),再启动加载流程
// 在开始新的加载流程之前,先清理所有可能存在的旧管理器状态。 ClearAllManagers();
// 这确保了每次需要加载时,系统都处于一个干净的初始状态。
ClearAllManagers(); // <--- 关键修改在Load()之前调用ClearAllManagers() // 初始化游戏设置
Setting.Instance.Init();
// 初始化设置
Base.Setting.Instance.Init();
#if !DEBUG #if !DEBUG
// 在非DEBUG模式下从设置中获取过渡时间 // 在非DEBUG模式下游戏设置中获取加载和渐隐的持续时间
duration = Base.Setting.Instance.CurrentSettings.progressStepDuration; duration = Base.Setting.Instance.CurrentSettings.progressStepDuration;
fadeDuration = Base.Setting.Instance.CurrentSettings.exitAnimationDuration; fadeDuration = Base.Setting.Instance.CurrentSettings.exitAnimationDuration;
#endif #endif
Load(); // 启动加载流程内部会调用LoadAllManagers Load(); // 启动加载流程内部会调用LoadAllManagers
Program.Instance.needLoad = false; // 加载完成后重置标志 Program.Instance.needLoad = false; // 加载完成后重置加载标志
} }
/// <summary> /// <summary>
/// 启动游戏的加载流程。 /// 启动游戏的加载流程。
/// 该方法会激活加载UI重置进度与透明度并启动所有管理器的异步加载协程。
/// </summary> /// </summary>
public void Load() public void Load()
{ {
loadingUI.SetActive(true); // 激活加载UI loadingUI.SetActive(true); // 激活加载UI
Progress = 0f; // 重置进度 Progress = 0f; // 将进度重置为0
Opacity = 1f; // 重置透明度为完全不透明 Opacity = 1f; // 将UI透明度重置为完全不透明
StartCoroutine(LoadAllManagers()); StartCoroutine(LoadAllManagers());
} }
/// <summary> /// <summary>
/// 清理所有管理器,然后重新加载。用于游戏重载或场景切换后需要重新初始化所有数据的情况 /// 清理所有管理器,然后重新加载游戏数据
/// 此方法适用于游戏重载、场景切换后需要重新初始化所有数据的情况。
/// </summary> /// </summary>
public void Reload() public void Reload()
{ {
Debug.Log("<color=yellow>Performing a full reload of all managers...</color>"); // 日志:正在执行所有管理器的完整重新加载...
Debug.Log("<color=yellow>正在执行所有管理器的完整重新加载...</color>");
StopAllCoroutines(); // 停止当前所有正在运行的加载协程,避免冲突 StopAllCoroutines(); // 停止当前所有正在运行的加载协程,避免冲突
ClearAllManagers(); // 清理所有管理器 ClearAllManagers(); // 清理所有管理器数据
Load(); // 重新加载游戏数据 Load(); // 重新加载游戏数据
} }
/// <summary> /// <summary>
/// 遍历所有已注册的管理器调用它们的 Clear 方法。 /// 遍历所有已注册的管理器,并安全地调用它们的 Clear 方法以释放资源或重置状态
/// </summary> /// </summary>
private void ClearAllManagers() private void ClearAllManagers()
{ {
@ -183,37 +226,39 @@ namespace Base
} }
catch (System.Exception ex) catch (System.Exception ex)
{ {
Debug.LogError($"<color=red>Error clearing manager {manager.StepDescription}:</color> {ex.Message}\n{ex.StackTrace}"); // 错误日志:清理管理器时发生异常。
Debug.LogError($"<color=red>清理管理器 '{manager.StepDescription}' 时出错:</color> {ex.Message}\n{ex.StackTrace}");
} }
} }
} }
/// <summary> /// <summary>
/// 协程:按顺序加载所有管理器。 /// 协程:按顺序加载所有注册的管理器。
/// 该方法会在加载过程中更新描述文本、平滑过渡进度条,并安全初始化每个管理器。
/// </summary> /// </summary>
/// <returns>一个 <see cref="IEnumerator"/>,用于协程。</returns>
private IEnumerator LoadAllManagers() private IEnumerator LoadAllManagers()
{ {
for (var i = 0; i < _managersToLoad.Count; i++) for (var i = 0; i < _managersToLoad.Count; i++)
{ {
var manager = _managersToLoad[i]; var manager = _managersToLoad[i];
// 更新描述文本,从管理器实例中获取 // 更新描述文本,显示当前正在加载的管理器步骤描述
if (describeText != null) if (describeText != null)
{ {
describeText.text = manager.StepDescription; describeText.text = manager.StepDescription;
} }
// 计算当前阶段的目标进度 // 计算当前阶段的目标进度
var targetProgress = (float)(i + 1) / _managersToLoad.Count; var targetProgress = (float)(i + 1) / _managersToLoad.Count;
// 平滑过渡进度条到下一个目标进度 // 平滑过渡进度条到下一个目标进度
yield return SmoothTransitionTo(targetProgress); yield return SmoothTransitionTo(targetProgress);
// 初始化对应的管理器,并进行异常处理 // 初始化对应的管理器,并处理可能发生的异常
yield return InitializeManagerSafely(manager); yield return InitializeManagerSafely(manager);
// 模拟耗时如果管理器Init方法本身很快可以 uncomment // yield return new WaitForSeconds(0.1f); // 此行代码可用于模拟每个管理器加载的耗时,默认不启用。
// yield return new WaitForSeconds(0.1f);
} }
// 所有管理器加载完成后的处理 // 所有管理器加载完成后的处理
@ -221,19 +266,22 @@ namespace Base
{ {
describeText.text = "加载完成!"; describeText.text = "加载完成!";
} }
Progress = 1f; // 确保进度条最终达到100% // 确保进度条最终达到100%
Progress = 1f;
// 开始渐隐效果 // 启动加载UI的渐隐效果
yield return FadeOutProgressBar(); yield return FadeOutProgressBar();
// 所有加载和动画结束后可以考虑卸载加载UI或跳转到主场景 // 所有加载和动画结束后可以考虑卸载加载UI或跳转到主场景
// ToScene("MainGameScene"); // 如果有需要,在这里跳转到主游戏场景 // ToScene("MainGameScene"); // 如果有需要,可以在此处调用静态方法跳转到主游戏场景
} }
/// <summary> /// <summary>
/// 尝试安全地初始化单个管理器,并捕获任何异常。 /// 尝试安全地初始化单个管理器实例,并捕获任何可能发生的异常。
/// 如果初始化失败将记录错误日志并更新UI提示。
/// </summary> /// </summary>
/// <param name="manager">要初始化的管理器实例。</param> /// <param name="manager">要初始化的管理器实例。</param>
/// <returns>一个 <see cref="IEnumerator"/>,用于协程。</returns>
private IEnumerator InitializeManagerSafely(ILaunchManager manager) private IEnumerator InitializeManagerSafely(ILaunchManager manager)
{ {
var initSuccess = false; var initSuccess = false;
@ -241,36 +289,38 @@ namespace Base
try try
{ {
manager.Init(); // 调用管理器的 Init 方法 manager.Init(); // 调用管理器的 Init 方法进行初始化
initSuccess = true; initSuccess = true;
} }
catch (System.Exception ex) catch (System.Exception ex)
{ {
initException = ex; // 捕获异常 initException = ex; // 捕获初始化过程中抛出的异常
} }
if (!initSuccess && initException != null) if (!initSuccess && initException != null)
{ {
// 记录错误日志 // 记录错误日志:初始化管理器时出现错误。
Debug.LogError($"<color=red>初始化管理器 '{manager.StepDescription}' 时出错:</color> {initException.Message}\n{initException.StackTrace}"); Debug.LogError($"<color=red>初始化管理器 '{manager.StepDescription}' 时出错:</color> {initException.Message}\n{initException.StackTrace}");
if (describeText != null) if (describeText != null)
{ {
describeText.text = $"{manager.StepDescription} (初始化失败)"; describeText.text = $"{manager.StepDescription} (初始化失败)"; // 更新UI显示失败信息
} }
// 这里可以添加更复杂的错误处理,例如显示错误弹窗,或者重试逻辑 // 这里可以添加更复杂的错误处理逻辑,例如显示错误弹窗、记录到特定日志文件或允许用户选择重试。
// yield break; // 如果错误严重,可以选择停止后续加载 // yield break; // 如果错误严重到无法继续,可以选择停止后续加载流程。
} }
yield return null; // 确保协程继续执行,即使没有做任何事 yield return null; // 确保协程继续执行,无论初始化成功与否
} }
/// <summary> /// <summary>
/// 协程:平滑过渡进度条到指定的目标进度。 /// 协程:平滑过渡进度条的当前值到指定的目标进度。
/// 使用 <c>Mathf.SmoothStep</c> 实现自然加速和减速的过渡效果。
/// </summary> /// </summary>
/// <param name="targetProgress">目标进度值 (0-1)。</param> /// <param name="targetProgress">目标进度值 (0到1之间)。</param>
/// <returns>一个 <see cref="IEnumerator"/>,用于协程。</returns>
private IEnumerator SmoothTransitionTo(float targetProgress) private IEnumerator SmoothTransitionTo(float targetProgress)
{ {
var startProgress = _currentProgressValue; // 获取当前进度作为起始点 var startProgress = _currentProgressValue; // 获取当前进度作为过渡的起始点
var elapsedTime = 0f; var elapsedTime = 0f;
while (elapsedTime < duration) while (elapsedTime < duration)
@ -278,7 +328,7 @@ namespace Base
elapsedTime += Time.deltaTime; elapsedTime += Time.deltaTime;
// 使用 SmoothStep 实现更自然的加速和减速过渡效果 // 使用 SmoothStep 实现更自然的加速和减速过渡效果
var t = Mathf.SmoothStep(0f, 1f, elapsedTime / duration); var t = Mathf.SmoothStep(0f, 1f, elapsedTime / duration);
Progress = Mathf.Lerp(startProgress, targetProgress, t); Progress = Mathf.Lerp(startProgress, targetProgress, t); // 在起始和目标进度之间插值
yield return null; yield return null;
} }
@ -286,8 +336,9 @@ namespace Base
} }
/// <summary> /// <summary>
/// 协程渐隐加载UI的透明 /// 协程:平滑渐隐加载UI的所有元素,使其透明度从完全不透明过渡到完全透明。
/// </summary> /// </summary>
/// <returns>一个 <see cref="IEnumerator"/>,用于协程。</returns>
private IEnumerator FadeOutProgressBar() private IEnumerator FadeOutProgressBar()
{ {
var elapsedTime = 0f; var elapsedTime = 0f;
@ -306,7 +357,7 @@ namespace Base
} }
/// <summary> /// <summary>
/// 静态方法:加载指定名称的场景。 /// 静态方法:加载指定名称的Unity场景。
/// </summary> /// </summary>
/// <param name="scene">要加载的场景名称。</param> /// <param name="scene">要加载的场景名称。</param>
public static void ToScene(string scene) public static void ToScene(string scene)
@ -314,7 +365,4 @@ namespace Base
SceneManager.LoadScene(scene); SceneManager.LoadScene(scene);
} }
} }
} }

View File

@ -2,8 +2,13 @@ using System.Collections.Generic;
namespace Data namespace Data
{ {
public class LocationRangeDef:Define public class EntityEventDef:Define
{ {
public BuildingDef buildingDef;
public MonsterDef monster;
public CharacterDef character; // 要生成的实体Def的defName
public int count = 1; // 生成的数量
public float minRadius = 0f; // 最小距离(以格数单位) public float minRadius = 0f; // 最小距离(以格数单位)
public float maxRadius = 10f; // 最大距离(以格数单位) public float maxRadius = 10f; // 最大距离(以格数单位)
public int width = 5; // 宽度(以格数单位),指定一个方形区域 public int width = 5; // 宽度(以格数单位),指定一个方形区域

View File

@ -1,21 +1,8 @@
namespace Data namespace Data
{ {
public enum EventType
{
None,
SpawnCharacter,
SpawnBuilding,
SpawnBullet,
SpawnPickup,
SpawnDefaultEntity,
}
public class EventDef : Define public class EventDef : Define
{ {
public EventType eventType = EventType.None; public HediffEventDef hediffEvent;
public EntityDef entityDef_Character; // 用于 EventType.SpawnCharacter public EntityEventDef entityEvent;
public BuildingDef entityDef_Building; // 用于 EventType.SpawnBuilding
public BulletDef entityDef_Bullet; // 用于 EventType.SpawnBullet
public ItemDef entityDef_Pickup; // 用于 EventType.SpawnPickup
public EventDef() { }
} }
} }

View File

@ -1,9 +0,0 @@
namespace Data
{
public class FactionRequirementDef:Define
{
public string factionDefName; // 目标的派系DefName
public bool forAllPawnsInFaction = false; // 是否为该派系的所有Pawns添加Hediff
public int specificPawnCount = 1; // 如果不是所有Pawns指定数量
}
}

View File

@ -4,10 +4,7 @@ namespace Data
{ {
public class HediffDef:Define public class HediffDef:Define
{ {
// 默认安装的身体部位 (例如 "Lung", "Heart") public float time = -1;
public string defaultInstallPart = null;
// 是否阻止肺部疾病 (例如肺腐烂)
public bool preventsLungRot = false;
// Hediff的发展阶段列表 // Hediff的发展阶段列表
public List<HediffStageDef> stages = new List<HediffStageDef>(); public List<HediffStageDef> stages = new List<HediffStageDef>();
// 附加的组件列表 // 附加的组件列表

View File

@ -0,0 +1,11 @@
namespace Data
{
public class HediffEventDef:Define
{
public HediffDef hediff; // 要添加的HediffDef的defName
public float hediffSeverity = 1.0f; // 添加时Hediff的严重程度或进度
public AffiliationDef affiliation; // 目标的派系DefName
public bool forAllPawnsInFaction = false; // 是否为该派系的所有Pawns添加Hediff
public int specificPawnCount = 1; // 如果不是所有Pawns指定数量
}
}

View File

@ -4,7 +4,6 @@ namespace Data
{ {
public class ImageDef : Define public class ImageDef : Define
{ {
public string name;
public string path; public string path;
public int wCount; public int wCount;
public int hCount; public int hCount;
@ -13,7 +12,6 @@ namespace Data
public override bool Init(XElement xmlDef) public override bool Init(XElement xmlDef)
{ {
base.Init(xmlDef); base.Init(xmlDef);
name = defName;
return false; return false;
} }
} }

View File

@ -0,0 +1,13 @@
namespace Data
{
public class StoryStageDef : Define
{
public float lastWaitTime = 0;
public EventDef eventDef;
public float nextWaitTime = 0;
}
public class StoryDef:Define
{
public StoryStageDef[] storyStage;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e11d701b7d8b4af0a947d630884bfeab
timeCreated: 1756306428

View File

@ -169,6 +169,7 @@ namespace Entity
// 协程引用 // 协程引用
private Coroutine _attackCoroutine; private Coroutine _attackCoroutine;
protected List<Hediff> hediffs;
[SerializeField] private float _hitBarUIShowTime = 5; [SerializeField] private float _hitBarUIShowTime = 5;

View File

@ -0,0 +1,15 @@
using Data;
namespace Entity
{
public class Hediff
{
public float Duration{get;private set;}
public Hediff(HediffDef def)
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: afec36ba23b944cf94ca944a8f8f35f4
timeCreated: 1756308924

View File

@ -1,181 +1,75 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Data; using Data;
using Entity;
using Prefab;
using UnityEngine; using UnityEngine;
using EventType = Data.EventType; using Utils;
using Random = System.Random;
namespace Managers namespace Managers
{ {
// 新增私有结构体,用于在事件队列中存储事件定义及其运行时上下文 class EventManager:Singleton<EventManager>,ILaunchManager
public struct EventPayload // Make it public if EventManager exposes it directly
{ {
public string DimensionId; private static Random _random = new();
public EventDef EventDefinition; public EventDef[] EventDefs { get; private set; }
public Vector3 Position; // 适用于 Character, Bullet, Pickup, DefaultEntity public string StepDescription => "正在载入事件";
public Vector3 Direction; // 仅适用于 Bullet
public Entity.Entity SourceEntity; // 仅适用于 Bullet (发射源)
public Vector3Int GridPosition; // 仅适用于 Building
}
public class EventManager : Utils.MonoSingleton<EventManager> public void Init()
{
private Queue<EventPayload> _eventQueue = new Queue<EventPayload>();
private EventManager()
{ {
/* Private constructor for singleton */ if(EventDefs!=null)
}
// ===================================
// 公共入队方法
// ===================================
public void EnqueueCharacterSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnCharacter ||
eventDef.entityDef_Character == null)
{
Debug.LogError(
$"EnqueueCharacterSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing characterDef for event '{eventDef?.defName ?? "Unknown"}'.");
return; return;
} EventDefs = DefineManager.Instance.QueryDefinesByType<EventDef>();
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnCharacter) enqueued for dimension {dimensionId} at {pos}.");
} }
public void EnqueueBuildingSpawnEvent(string dimensionId, EventDef eventDef, Vector3Int gridPos) public void Clear()
{ {
if (eventDef == null || eventDef.eventType != EventType.SpawnBuilding || EventDefs = null;
eventDef.entityDef_Building == null) }
{
Debug.LogError( public static void ExecuteEvent(EventDef eventDef)
$"EnqueueBuildingSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing buildingDef for event '{eventDef?.defName ?? "Unknown"}'."); {
if(eventDef == null)
return; return;
} if (eventDef.hediffEvent != null)
_eventQueue.Enqueue(new EventPayload
{ {
DimensionId = dimensionId, var entityList = EntityManage.Instance.FindEntitiesByFaction(Program.Instance.FocusedDimensionId,
EventDefinition = eventDef, eventDef.hediffEvent.affiliation.defName);
GridPosition = gridPos, List<Entity.Entity> filteredEntitiesTraditional = new();
}); foreach (var prefab in entityList)
Debug.Log($"Event '{eventDef.defName}' (SpawnBuilding) enqueued for dimension {dimensionId} at grid {gridPos}.");
}
public void EnqueueBulletSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos, Vector3 dir,
Entity.Entity source = null)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnBullet || eventDef.entityDef_Bullet == null)
{
Debug.LogError(
$"EnqueueBulletSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing bulletDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
Direction = dir,
SourceEntity = source,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnBullet) enqueued for dimension {dimensionId} at {pos}, dir {dir}.");
}
public void EnqueuePickupSpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnPickup || eventDef.entityDef_Pickup == null)
{
Debug.LogError(
$"EnqueuePickupSpawnEvent: Invalid EventDef, mismatched EventType ({eventDef?.eventType}), or missing itemDef for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnPickup) enqueued for dimension {dimensionId} at {pos}.");
}
public void EnqueueDefaultEntitySpawnEvent(string dimensionId, EventDef eventDef, Vector3 pos)
{
if (eventDef == null || eventDef.eventType != EventType.SpawnDefaultEntity)
{
Debug.LogError(
$"EnqueueDefaultEntitySpawnEvent: Invalid EventDef or mismatched EventType ({eventDef?.eventType}) for event '{eventDef?.defName ?? "Unknown"}'.");
return;
}
_eventQueue.Enqueue(new EventPayload
{
DimensionId = dimensionId,
EventDefinition = eventDef,
Position = pos,
});
Debug.Log($"Event '{eventDef.defName}' (SpawnDefaultEntity) enqueued for dimension {dimensionId} at {pos}.");
}
// ===================================
// 事件处理方法
// ===================================
/// <summary>
/// 处理所有在队列中的待处理事件。
/// </summary>
public void ProcessEvents()
{
while (_eventQueue.Count > 0)
{
EventPayload eventData = _eventQueue.Dequeue();
if (!Program.Instance.GetDimension(eventData.DimensionId))
{ {
Debug.LogWarning( var entity = prefab.entity;
$"Event '{eventData.EventDefinition.defName}' for dimension {eventData.DimensionId} dropped as dimension is no longer active."); if (entity is Character || entity is Monster)
continue; {
filteredEntitiesTraditional.Add(entity);
}
} }
var selectedElements = SelectRandomElements_FisherYates(filteredEntitiesTraditional, eventDef.hediffEvent.specificPawnCount);
// 核心:调用 EntityManage.Instance 的现有公共方法 foreach (var selectedElement in selectedElements)
switch (eventData.EventDefinition.eventType)
{ {
case EventType.SpawnCharacter:
EntityManage.Instance.GenerateEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Character, eventData.Position);
break;
case EventType.SpawnBuilding:
EntityManage.Instance.GenerateBuildingEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Building, eventData.GridPosition);
break;
case EventType.SpawnBullet:
EntityManage.Instance.GenerateBulletEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Bullet, eventData.Position, eventData.Direction,
eventData.SourceEntity);
break;
case EventType.SpawnPickup:
EntityManage.Instance.GeneratePickupEntity(eventData.DimensionId,
eventData.EventDefinition.entityDef_Pickup, eventData.Position);
break;
case EventType.SpawnDefaultEntity:
EntityManage.Instance.GenerateDefaultEntity(eventData.DimensionId, eventData.Position);
break;
case EventType.None:
default:
Debug.LogWarning(
$"EventManager: Unhandled or invalid event type: {eventData.EventDefinition.eventType} for event '{eventData.EventDefinition.defName}'.");
break;
} }
} }
} }
public static List<T> SelectRandomElements_FisherYates<T>(List<T> sourceList, int count)
protected override void OnStart()
{ {
throw new System.NotImplementedException(); if (sourceList == null) throw new ArgumentNullException(nameof(sourceList));
if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), "Count cannot be negative.");
if (count == 0) return new List<T>();
if (count >= sourceList.Count) return new List<T>(sourceList); // 如果n大于等于列表大小则返回所有元素副本
List<T> result = new List<T>(count); // 预分配容量
List<T> temp = new List<T>(sourceList); // 创建一个副本以避免修改原始列表
int n = temp.Count;
for (int i = 0; i < count; i++)
{
int k = _random.Next(i, n);
result.Add(temp[k]);
(temp[k], temp[i]) = (temp[i], temp[k]);
}
return result;
} }
} }
} }

View File

@ -22,20 +22,14 @@ namespace Managers
public Sprite defaultSprite; public Sprite defaultSprite;
/// <summary> /// <summary>
/// 存储所有已加载的纹理,按包ID和图像名称索引。 /// 存储所有已加载的纹理,按图像名称全局唯一的DefName索引。
/// </summary> /// </summary>
/// <remarks> public Dictionary<string, Texture2D> packagesImages = new();
/// 外层字典键是包ID内层字典键是图像名称。
/// </remarks>
public Dictionary<string, Dictionary<string, Texture2D>> packagesImages = new();
/// <summary> /// <summary>
/// 存储所有已创建的精灵,按包ID和精灵名称索引。 /// 存储所有已创建的精灵,按精灵名称全局唯一的DefName或其带索引后缀索引。
/// </summary> /// </summary>
/// <remarks> public Dictionary<string, Sprite> sprites = new();
/// 外层字典键是包ID内层字典键是精灵名称如果纹理被分割会包含索引后缀
/// </remarks>
public Dictionary<string, Dictionary<string, Sprite>> sprites = new();
/// <summary> /// <summary>
/// 获取当前启动步骤的描述。 /// 获取当前启动步骤的描述。
@ -49,21 +43,15 @@ namespace Managers
{ {
if (packagesImages.Count > 0) if (packagesImages.Count > 0)
{ {
// 如果已经加载过,直接返回 // 如果已经有数据,则跳过初始化,防止重复加载。
StepDescription = "包图像管理器已初始化。";
return; return;
} }
StepDescription = "正在加载默认精灵..."; // 更新加载步骤描述
defaultSprite = Resources.Load<Sprite>("Default/DefaultImage"); defaultSprite = Resources.Load<Sprite>("Default/DefaultImage");
if (defaultSprite == null) if (defaultSprite == null)
{ {
Debug.LogWarning("无法加载默认精灵 'Resources/Default/DefaultImage'。请确保文件存在。"); Debug.LogWarning("无法加载默认精灵 'Resources/Default/DefaultImage'。请确保文件存在。");
} }
StepDescription = "正在处理图像定义并创建精灵..."; // 更新加载步骤描述
InitImageDef(); InitImageDef();
StepDescription = "包图像管理器初始化完成。"; // 完成加载
} }
/// <summary> /// <summary>
@ -76,7 +64,7 @@ namespace Managers
if (imageDef == null || !imageDef.Any()) if (imageDef == null || !imageDef.Any())
{ {
Debug.Log($"在 DefineManager 中未找到任何 ImageDef 定义。({typeof(ImageDef).Name})"); Debug.Log($"在定义管理器中未找到任何图像定义。({nameof(ImageDef)})");
return; return;
} }
@ -84,7 +72,7 @@ namespace Managers
{ {
if (string.IsNullOrEmpty(ima.path) || string.IsNullOrEmpty(ima.packID)) if (string.IsNullOrEmpty(ima.path) || string.IsNullOrEmpty(ima.packID))
{ {
Debug.LogWarning($"跳过图像定义 '{ima?.name ?? ""}'因为它包含空路径或包ID。(路径: '{ima?.path ?? ""}', 包ID: '{ima?.packID ?? ""}')"); Debug.LogWarning($"跳过图像定义 '{ima?.defName ?? ""}'因为它包含空路径或包ID。(路径: '{ima?.path ?? ""}', 包ID: '{ima?.packID ?? ""}')");
continue; continue;
} }
@ -119,7 +107,7 @@ namespace Managers
var packageRoot = Managers.DefineManager.Instance.GetPackagePath(packageID); var packageRoot = Managers.DefineManager.Instance.GetPackagePath(packageID);
if (string.IsNullOrEmpty(packageRoot)) if (string.IsNullOrEmpty(packageRoot))
{ {
Debug.LogWarning($"图像定义 '{ima.name}' (包ID: {ima.packID}): 引用的包ID '{packageID}' 未找到或没有根路径。跳过图像加载。"); Debug.LogWarning($"图像定义 '{ima.defName}' (包ID: {ima.packID}): 引用的包ID '{packageID}' 未找到或没有根路径。跳过图像加载。");
continue; continue;
} }
@ -140,7 +128,7 @@ namespace Managers
var pack = Managers.DefineManager.Instance.GetDefinePackage(ima); var pack = Managers.DefineManager.Instance.GetDefinePackage(ima);
if (pack == null) if (pack == null)
{ {
Debug.LogError($"图像定义 '{ima.name}' (包ID: {ima.packID}): 源图像未找到对应的定义包。无法确定 '{ima.path}' 的完整路径。跳过。"); Debug.LogError($"图像定义 '{ima.defName}' (包ID: {ima.packID}): 源图像未找到对应的定义包。无法确定 '{ima.path}' 的完整路径。跳过。");
continue; continue;
} }
var fullPath = Path.Combine(pack.packRootPath, ima.path).Replace('\\', '/'); var fullPath = Path.Combine(pack.packRootPath, ima.path).Replace('\\', '/');
@ -158,31 +146,20 @@ namespace Managers
// 资源加载失败 // 资源加载失败
if (!texture) if (!texture)
{ {
Debug.LogError($"未能加载图像定义所在的纹理: '{ima.name}' (路径: '{ima.path}', 包ID: '{ima.packID}')。请验证路径和文件是否存在。"); Debug.LogError($"未能加载图像定义关联的纹理: '{ima.defName}' (路径: '{ima.path}', 包ID: '{ima.packID}')。请验证路径和文件是否存在。");
continue; continue;
} }
// 存储到包纹理字典(使用定义自身的 packID packagesImages[ima.defName] = texture;
var packId = ima.packID;
if (!packagesImages.ContainsKey(packId))
packagesImages[packId] = new Dictionary<string, Texture2D>();
// 警告:如果图片名重复,则覆盖
if (packagesImages[packId].ContainsKey(ima.name))
{
Debug.LogWarning($"包 '{packId}' 中名为 '{ima.name}' 的图像被多次定义。将覆盖之前的纹理引用。这可能表示配置错误。");
}
packagesImages[packId][ima.name] = texture; // 覆盖或添加
// 切分精灵 // 切分精灵
SplitTextureIntoSprites(packId, ima.name, texture, ima.hCount, ima.wCount, ima.pixelsPerUnit); SplitTextureIntoSprites(ima.defName, texture, ima.hCount, ima.wCount, ima.pixelsPerUnit);
} }
catch (Exception ex) catch (Exception ex)
{ {
// 捕获异常并打印详细错误信息 // 捕获异常并打印详细错误信息
Debug.LogError( Debug.LogError(
$"处理图像定义时出错: '{ima.name}' (路径: '{ima.path}', 包ID: '{ima.packID}')。异常: {ex.GetType().Name}: {ex.Message}\n堆栈跟踪: {ex.StackTrace}"); $"处理图像定义时出错: '{ima.defName}' (路径: '{ima.path}', 包ID: '{ima.packID}')。异常: {ex.GetType().Name}: {ex.Message}\n堆栈跟踪: {ex.StackTrace}");
} }
} }
} }
@ -190,14 +167,12 @@ namespace Managers
/// <summary> /// <summary>
/// 将纹理按指定行数和列数分割成多个精灵,并存储起来。 /// 将纹理按指定行数和列数分割成多个精灵,并存储起来。
/// </summary> /// </summary>
/// <param name="packId">精灵所属的包ID。</param> /// <param name="baseName">精灵的基础名称全局唯一的DefName。</param>
/// <param name="baseName">精灵的基础名称。</param>
/// <param name="texture">要分割的 <see cref="Texture2D"/> 对象。</param> /// <param name="texture">要分割的 <see cref="Texture2D"/> 对象。</param>
/// <param name="rows">水平分割的行数。</param> /// <param name="rows">水平分割的行数。</param>
/// <param name="cols">垂直分割的列数。</param> /// <param name="cols">垂直分割的列数。</param>
/// <param name="pixelsPerUnit">每个单元的像素数用于Sprite.Create。</param> /// <param name="pixelsPerUnit">每个单元的像素数用于Sprite.Create。</param>
private void SplitTextureIntoSprites( private void SplitTextureIntoSprites(
string packId,
string baseName, string baseName,
Texture2D texture, Texture2D texture,
int rows, int rows,
@ -206,7 +181,7 @@ namespace Managers
{ {
if (!texture) if (!texture)
{ {
Debug.LogError($"SplitTextureIntoSprites: 包 '{packId}' 中 '{baseName}' 提供的纹理为空。无法分割。"); Debug.LogError($"SplitTextureIntoSprites: '{baseName}' 提供的纹理为空。无法分割。");
return; return;
} }
@ -217,19 +192,11 @@ namespace Managers
var textureWidth = texture.width; var textureWidth = texture.width;
var textureHeight = texture.height; var textureHeight = texture.height;
if (!sprites.ContainsKey(packId)) // 创建未分割的完整精灵,使用原始名称 (baseName即 ImageDef.name)
sprites[packId] = new Dictionary<string, Sprite>();
// 创建未分割的完整精灵,使用原始名称
var fullSpriteRect = new Rect(0, 0, textureWidth, textureHeight); var fullSpriteRect = new Rect(0, 0, textureWidth, textureHeight);
// 警告:如果精灵名重复,则覆盖
if (sprites[packId].ContainsKey(baseName))
{
Debug.LogWarning($"包 '{packId}' 中名为 '{baseName}' 的精灵已存在。将覆盖之前的完整精灵定义。");
}
var fullSprite = Sprite.Create(texture, fullSpriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit); var fullSprite = Sprite.Create(texture, fullSpriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
fullSprite.name = baseName; // 确保 Sprite.name 被设置 fullSprite.name = baseName; // 确保 Sprite.name 被设置
sprites[packId][baseName] = fullSprite; sprites[baseName] = fullSprite;
// 如果不分割rows和cols都为1提前返回 // 如果不分割rows和cols都为1提前返回
if (rows == 1 && cols == 1) if (rows == 1 && cols == 1)
@ -240,7 +207,7 @@ namespace Managers
// 检查纹理尺寸是否可被分割数整除 // 检查纹理尺寸是否可被分割数整除
if (textureWidth % cols != 0 || textureHeight % rows != 0) if (textureWidth % cols != 0 || textureHeight % rows != 0)
{ {
Debug.LogError($"包 '{packId}' 中 '{baseName}' 的纹理尺寸 ({textureWidth}x{textureHeight}) 不能被指定的行数 ({rows}) 和列数 ({cols}) 完美整除。子精灵将不会生成或可能不正确。仅显示完整精灵。"); Debug.LogError($"'{baseName}' 的纹理尺寸 ({textureWidth}x{textureHeight}) 不能被指定的行数 ({rows}) 和列数 ({cols}) 完美整除。子精灵将不会生成或可能不正确。仅显示完整精灵。");
return; // 终止子精灵分割,只保留完整的精灵 return; // 终止子精灵分割,只保留完整的精灵
} }
@ -253,18 +220,11 @@ namespace Managers
{ {
Rect spriteRect = new(col * tileWidth, row * tileHeight, tileWidth, tileHeight); Rect spriteRect = new(col * tileWidth, row * tileHeight, tileWidth, tileHeight);
var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit); var sprite = Sprite.Create(texture, spriteRect, new Vector2(0.5f, 0.5f), pixelsPerUnit);
// 精灵索引计算方式 // 精灵索引计算方式
var index = (rows - row - 1) * cols + col; var index = (rows - row - 1) * cols + col;
var spriteName = $"{baseName}_{index}"; var spriteName = $"{baseName}_{index}";
sprite.name = spriteName; sprite.name = spriteName;
sprites[spriteName] = sprite;
// 警告:如果子精灵名重复,则覆盖
if (sprites[packId].ContainsKey(spriteName))
{
Debug.LogWarning($"包 '{packId}' 中名为 '{spriteName}' 的精灵已存在。将覆盖之前的子精灵定义。这可能表示配置错误。");
}
sprites[packId][spriteName] = sprite;
} }
} }
} }
@ -299,36 +259,24 @@ namespace Managers
/// <summary> /// <summary>
/// 根据 <see cref="ImageDef"/> 对象获取对应的精灵。 /// 根据 <see cref="ImageDef"/> 对象获取对应的精灵。
/// </summary> /// </summary>
/// <param name="ima">包含精灵包ID和名称的 <see cref="ImageDef"/> 对象。</param> /// <param name="ima">包含精灵名称的 <see cref="ImageDef"/> 对象。</param>
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns> /// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
public Sprite GetSprite(ImageDef ima) public Sprite GetSprite(ImageDef ima)
{ {
if (ima == null) return defaultSprite; if (ima == null) return defaultSprite;
return GetSprite(ima.packID, ima.name); return GetSprite(ima.packID, ima.defName);
} }
/// <summary> /// <summary>
/// 根据包ID和精灵名称获取对应的精灵。 /// 根据包ID和精灵名称获取对应的精灵。
/// </summary> /// </summary>
/// <param name="packID">精灵所属的包ID。如果为空,则会遍历所有包查找。</param> /// <param name="packID">精灵所属的包ID。此参数在此版本中已不再用于字典查找,但为保持兼容性而保留。</param>
/// <param name="name">精灵的名称。</param> /// <param name="name">精灵的名称全局唯一的DefName。</param>
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns> /// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
public Sprite GetSprite(string packID, string name) public Sprite GetSprite(string packID, string name)
{ {
if (string.IsNullOrEmpty(packID)) if (sprites.TryGetValue(name, out var sprite))
{ return sprite;
// 如果packID为空遍历所有包以name查找
foreach (var kvp in sprites)
{
if (kvp.Value.TryGetValue(name, out var sprite))
return sprite;
}
}
else if (sprites.TryGetValue(packID, out var dict))
{
if (dict.TryGetValue(name, out var sprite))
return sprite;
}
// 如果未找到,返回默认精灵 // 如果未找到,返回默认精灵
return defaultSprite; return defaultSprite;
@ -337,14 +285,40 @@ namespace Managers
/// <summary> /// <summary>
/// 根据包ID、基础名称和索引获取被分割的子精灵。 /// 根据包ID、基础名称和索引获取被分割的子精灵。
/// </summary> /// </summary>
/// <param name="packID">精灵所属的包ID。</param> /// <param name="packID">精灵所属的包ID。此参数在此版本中已不再用于字典查找,但为保持兼容性而保留。</param>
/// <param name="name">精灵的基础名称。</param> /// <param name="name">精灵的基础名称全局唯一的DefName。</param>
/// <param name="index">子精灵的索引。</param> /// <param name="index">子精灵的索引。</param>
/// <returns>如果找到对应的子精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns> /// <returns>如果找到对应的子精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
public Sprite GetSprite(string packID, string name, int index) public Sprite GetSprite(string packID, string name, int index)
{ {
var fullName = $"{name}_{index}"; var fullName = $"{name}_{index}";
return GetSprite(packID, fullName); return GetSprite(packID, fullName);
}
// ---------- 新增的查询接口 ----------
/// <summary>
/// 根据精灵名称全局唯一的DefName获取对应的精灵。
/// </summary>
/// <param name="name">精灵的名称。</param>
/// <returns>如果找到对应的精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
public Sprite GetSprite(string name)
{
if (sprites.TryGetValue(name, out var sprite))
return sprite;
return defaultSprite;
}
/// <summary>
/// 根据基础名称全局唯一的DefName和索引获取被分割的子精灵。
/// </summary>
/// <param name="name">精灵的基础名称。</param>
/// <param name="index">子精灵的索引。</param>
/// <returns>如果找到对应的子精灵,则返回该精灵;否则返回 <see cref="defaultSprite"/>。</returns>
public Sprite GetSprite(string name, int index)
{
var fullName = $"{name}_{index}";
return GetSprite(fullName);
} }
} }
} }

File diff suppressed because one or more lines are too long