diff --git a/ProjectNLD/AI_Gen_Doc/暂停状态下技能释放流程说明.md b/ProjectNLD/AI_Gen_Doc/暂停状态下技能释放流程说明.md new file mode 100644 index 00000000000..50bc1631f45 --- /dev/null +++ b/ProjectNLD/AI_Gen_Doc/暂停状态下技能释放流程说明.md @@ -0,0 +1,393 @@ +# 暂停状态下技能释放流程说明 + +> 本文档由 AI 生成,用于说明暂停状态下玩家主动释放技能的完整流程逻辑。 + +## 功能概述 + +在战斗暂停状态下,玩家可以为多个单位预先选择技能释放位置。这些技能会被**缓存**起来,等到**解除暂停**后统一释放执行。 + +**核心特点**: +- 暂停时选择技能 → 缓存到字典 +- 解除暂停时 → 统一发送释放事件 +- 支持覆盖、取消已缓存的技能 + +--- + +## 核心类职责 + +| 类名 | 职责 | +|------|------| +| `SkillAreaSelector2` | 技能区域选择器,处理预览、选择、取消 | +| `SkillPauseCacheManager` | 暂停时技能缓存管理器,存储已缓存的技能数据 | +| `InPauseCacheSkillArea` | 显示已缓存技能的释放位置(特殊显示逻辑) | +| `GroundPlaneManager` | 地面面片管理器,负责实际的地面显示 | +| `CommonSkillAreaSelector` | 基类,处理暂停/恢复、事件注册 | +| `FightSkillPutManager` | 技能释放UI管理器 | + +--- + +## 技能释放类型枚举 + +**文件**:`Assets/Code/Scripts/GamePlay/Area/Skill/SkillAreaSelector2.cs` + +```csharp +public enum ECacheUseType +{ + RealUse, // 非暂停时,真正释放 + CacheUse, // 暂停时,缓存技能 + Cancel, // 取消技能选择 +} +``` + +--- + +## 完整流程 + +### 阶段1:进入技能预览 + +**入口方法**:`SkillAreaSelector2.EnterPreview(SkillHandle skill)` + +```csharp +public void EnterPreview(SkillHandle skill) +{ + // 隐藏其他区域显示 + AreaManager.instance.moveAreaView.Hide(); + AreaManager.instance.investigateAreaView.Hide(); + AreaManager.instance.attackArea.HideArea(); + + skillHandle = skill; + + // 通知UI打开界面 + FightSkillPutManager.Instance.EnterSkillPut(skill.owner); + + // 暂停游戏(记录当前速度) + _PauseGame(); + + // 计算技能范围、创建区域显示 + _CalcSkillCellIndex(); + _CreateSkillAreaBoard(); + + // 显示屏幕特效 + SkillManager.instance.screenEffect.Show(); + + // 预选格子和单位 + _PreSelectCellIndex(); + _PreSelectUnits(); + _AttachHighlights(); + + // 注册事件监听 + _RegisterEvents(); +} +``` + +### 阶段2:确认技能释放 + +**方法**:`SkillAreaSelector2._OnEventClickCellIndex(int cellIndex)` + +```csharp +protected override void _OnEventClickCellIndex(int cellIndex) +{ + if (!_preSelectCellIndexList.Contains(cellIndex)) + { + UITipsManager.ShowTips("无法在此处释放技能", EShowTipType.Error); + return; + } + + var cacheSkillHandle = skillHandle; + + if (_oldTimeSpeed == 0) // 之前是暂停状态 + { + // 取消选中 + LevelManager.Instance.CurrentLevel.UnSelectUnit(); + + // 暂停状态下不能释放技能, 改为暂存 + ExitPreview(ECacheUseType.CacheUse).Forget(); + + var eventData = new EventDataUseSkill() + { + sender = cacheSkillHandle.owner, + pointCellIndex = cellIndex, + }; + EventManager.Instance.Send(EventManager.EventName.UI_CACHE_SKILL, eventData); + } + else // 之前是运行状态 + { + ExitPreview(ECacheUseType.RealUse).Forget(); + + var eventData = new EventDataUseSkill() + { + sender = cacheSkillHandle.owner, + pointCellIndex = cellIndex, + }; + EventManager.Instance.Send(EventManager.EventName.UI_USE_SKILL, eventData); + } +} +``` + +### 阶段3:缓存技能 + +**文件**:`Assets/Code/Scripts/GamePlay/Level/SkillPauseCache/SkillPauseCacheManager.cs` + +```csharp +private void OnCacheSkill(EventDataUseSkill eventDataUseSkill) +{ + // 使用字典索引器,相同key会自动覆盖 + dicCacheSkill[eventDataUseSkill.sender] = eventDataUseSkill; + + // 设置目标格子 + eventDataUseSkill.sender.controlData.targetCellIndex = eventDataUseSkill.sender.transData.cellIndex; + eventDataUseSkill.sender.controlData.moveTargetCellIndex = eventDataUseSkill.sender.transData.cellIndex; + + // 触发对话事件 + if (EGameUnitType.Character == eventDataUseSkill.sender.gameunitType) + DialogueManager.Instance.OnFightUseSkill(eventDataUseSkill.sender); +} +``` + +### 阶段4:解除暂停时释放 + +```csharp +private void OnPauseStateChange() +{ + if (ELevelSpeed.Level_0 == curLevel.GetSpeed()) + return; + + // 遍历所有缓存的技能,发送释放事件 + foreach (EventDataUseSkill eventDataUseSkill in dicCacheSkill.Values) + { + EventManager.Instance.Send(EventManager.EventName.UI_USE_SKILL, eventDataUseSkill); + } + + // 清空缓存 + dicCacheSkill.Clear(); + + // 发送指挥官技能缓存事件 + EventManager.Instance.Send(EventManager.EventName.UseCacheCommanderSkill); +} +``` + +--- + +## 特殊显示逻辑 + +### InPauseCacheSkillArea 类 + +**文件**:`Assets/Code/Scripts/GamePlay/Area/Skill/InPauseCacheSkillArea.cs` + +**功能**:当玩家在暂停状态下选中一个已缓存技能的单位时,在地面上显示该单位技能将要释放的位置。 + +#### 事件监听 + +| 事件 | 处理方法 | 作用 | +|------|---------|------| +| `INFIGHT_PAUSE_CHANGED` | `_OnPauseChanged()` | 监听暂停状态变化 | +| `LevelUnitSelect` | `_OnUnitSelected()` | 选中单位时尝试显示缓存技能区域 | +| `LevelUnitUnSelect` | `_OnUnitUnSelected()` | 取消选中时隐藏显示 | + +#### 显示流程 + +```csharp +private void _ShowCachedSkillArea() +{ + // 1. 清除旧的显示 + GroundPlaneManager.Instance.UnregisterPlanes(this); + + if (_selectedUnit == null) + return; + + // 2. 获取单位的技能管理器 + var unitSkillManager = SkillManager.instance.GetUnitSkillManager(_selectedUnit); + + // 3. 获取主动技能 + var skillHandle = unitSkillManager.positiveSkill; + + // 4. 获取技能的显示区域ID + var showAreaId = skillHandle.runtimeData.configData.ShowAreaId; + + // 5. 查询缓存数据 + if (!SkillPauseCacheManager.Ins.TryGetChcheSkillData(_selectedUnit, out var skillData)) + { + return; // 无缓存数据,不显示 + } + + // 6. 计算技能影响的格子列表 + var getAreaCellIndexList = AreaManager.instance.GetCellIndexs(skillData.pointCellIndex, showAreaId); + + // 7. 注册地面显示 + GroundPlaneManager.Instance.RegisterPlanes( + getAreaCellIndexList, + GroundPlaneType.InPauseCacheSkill, // 专用显示类型 + this + ); +} +``` + +#### 显示资源 + +- **类型**:`GroundPlaneType.InPauseCacheSkill` +- **Prefab**:`Assets/Art_Out/Other/SkillArea/skill_inpause_preview_point.prefab` + +--- + +## 缓存技能的覆盖逻辑 + +当一个单位**已经缓存了技能**,玩家**再次为该单位选择技能释放位置**时,会直接**覆盖**之前的缓存数据。 + +### 覆盖机制 + +```csharp +// 使用字典的索引器赋值,如果key已存在则覆盖 +dicCacheSkill[eventDataUseSkill.sender] = eventDataUseSkill; +``` + +### 覆盖流程示例 + +| 步骤 | 操作 | dicCacheSkill 状态 | +|------|------|-------------------| +| 1 | 为单位A选择释放点(格子100) | `{ A → 格子100 }` | +| 2 | 再次为单位A选择释放点(格子200) | `{ A → 格子200 }` (覆盖) | +| 3 | 解除暂停 | 技能释放到格子200 | + +### 设计特点 + +| 特点 | 说明 | +|------|------| +| **自动覆盖** | 使用字典索引器,相同key自动覆盖 | +| **无确认提示** | 覆盖时不会提示玩家 | +| **每单位一个缓存** | 字典以 `GameUnit` 为key,每个单位最多只能缓存一个技能释放数据 | +| **对话重新触发** | 覆盖时会再次调用 `DialogueManager.OnFightUseSkill` | + +--- + +## 取消缓存技能的方式 + +| 方式 | 触发条件 | 处理逻辑 | +|------|---------|---------| +| **移动指令取消** | 给单位下达移动指令 | `INFIGHT_AUDIO_CLICK_MOVE` 事件 → `OnClearSkillCache()` → `dicCacheSkill.Remove(unit)` | +| **解除暂停释放** | 游戏恢复运行 | 遍历缓存发送 `UI_USE_SKILL` → 清空缓存 | +| **取消技能选择** | 点击取消按钮 | `ExitPreview(Cancel)` → 退出预览,不修改已有缓存 | + +### 移动指令取消 + +**文件**:`Assets/Code/Scripts/GamePlay/AI/AIManager.Directive.cs` + +```csharp +if (isPlayerOperate && unit is UnitCharacter character) +{ + EventManager.Instance.Send(EventManager.EventName.INFIGHT_AUDIO_CLICK_MOVE, character); +} +``` + +**文件**:`Assets/Code/Scripts/GamePlay/Level/SkillPauseCache/SkillPauseCacheManager.cs` + +```csharp +private void OnClearSkillCache(GameUnit gameUnit) +{ + dicCacheSkill.Remove(gameUnit); +} +``` + +--- + +## 关键事件 + +| 事件名 | 触发时机 | 处理者 | 结果 | +|--------|---------|--------|------| +| `UI_CACHE_SKILL` | 暂停时确认技能释放点 | `SkillPauseCacheManager` | 缓存技能数据 | +| `UI_USE_SKILL` | 非暂停时选择 / 解除暂停时 | `SkillManager` | 真正释放技能 | +| `INFIGHT_UI_CANCEL_USE_SKILL` | 点击取消按钮 | `SkillAreaSelector2` | 退出技能预览 | +| `INFIGHT_AUDIO_CLICK_MOVE` | 玩家操作单位移动 | `SkillPauseCacheManager` | 清除该单位的缓存技能 | +| `LevelFightUIPauseChange` | 暂停状态变化 | `SkillPauseCacheManager` | 解除暂停时释放所有缓存 | +| `LevelSpeedChange` | 游戏速度变化 | `SkillPauseCacheManager` | 解除暂停时释放所有缓存 | +| `LevelUnitSelect` | 选中单位 | `InPauseCacheSkillArea` | 显示该单位的缓存技能区域 | +| `LevelUnitUnSelect` | 取消选中 | `InPauseCacheSkillArea` | 隐藏缓存技能区域显示 | +| `INFIGHT_PAUSE_CHANGED` | 暂停状态变化 | `InPauseCacheSkillArea` | 解除暂停时隐藏显示 | + +--- + +## 关键数据结构 + +### SkillPauseCacheManager.dicCacheSkill + +```csharp +Dictionary dicCacheSkill; +``` + +### EventDataUseSkill + +```csharp +public class EventDataUseSkill +{ + public GameUnit sender; // 释放技能的单位 + public int pointCellIndex; // 技能释放的目标格子 +} +``` + +--- + +## 流程总结图 + +``` +玩家操作 系统响应 +───────────────────────────────────────────────────────────────────── + +① 暂停状态下点击角色技能 → 进入技能预览 + ├─ 暂停游戏 + ├─ 显示技能范围 + └─ 等待玩家选择 + +② 选择释放位置并确认 → 缓存技能 + 取消选中 + ├─ dicCacheSkill[unit] = data + └─ UnSelectUnit() + +③ 再次点击该单位 → 显示缓存技能区域 + └─ GroundPlaneManager 显示 + skill_inpause_preview_point + +④ 点击其他单位/取消选中 → 隐藏缓存技能区域 + └─ GroundPlaneManager 隐藏 + +⑤ 再次为该单位选择技能 → 覆盖缓存技能 + └─ dicCacheSkill[unit] = newData + +⑥ 给该单位下达移动指令 → 取消该单位的缓存技能 + └─ dicCacheSkill.Remove(unit) + +⑦ 解除暂停 → 释放所有缓存技能 + ├─ 遍历发送 UI_USE_SKILL + ├─ 清空 dicCacheSkill + └─ 隐藏所有缓存区域显示 +``` + +--- + +## 相关代码文件 + +| 文件路径 | 说明 | +|---------|------| +| `Assets/Code/Scripts/GamePlay/Area/Skill/SkillAreaSelector2.cs` | 技能区域选择器 | +| `Assets/Code/Scripts/GamePlay/Area/Skill/CommonSkillAreaSelector.cs` | 技能区域选择器基类 | +| `Assets/Code/Scripts/GamePlay/Area/Skill/InPauseCacheSkillArea.cs` | 暂停状态缓存技能区域显示 | +| `Assets/Code/Scripts/GamePlay/Level/SkillPauseCache/SkillPauseCacheManager.cs` | 技能暂停缓存管理器 | +| `Assets/Code/Scripts/GamePlay/Skill/SkillManager.cs` | 技能管理器 | +| `Assets/Code/Scripts/GamePlay/Skill/FightSkillPutManager.cs` | 技能释放UI管理器 | +| `Assets/Code/Scripts/GamePlay/UI/LevelFight/FightSceneUI/UISkillPutController.cs` | 技能释放UI控制器 | +| `Assets/Code/Scripts/GamePlay/GroundPlane/GroundPlaneManager.cs` | 地面面片管理器 | +| `Assets/Code/Scripts/GamePlay/GroundPlane/GroundPlaneType.cs` | 地面面片类型枚举 | +| `Assets/Code/Scripts/GamePlay/Common/PathDefine.cs` | 路径定义(包含预制体路径) | +| `Assets/Code/Scripts/GamePlay/AI/AIManager.Directive.cs` | AI指令管理(移动指令触发取消缓存) | + +--- + +## 注意事项 + +1. **显示时机**:只有在暂停状态下选中已缓存技能的单位时才会显示缓存区域 +2. **自动隐藏**:解除暂停时会自动隐藏所有缓存区域显示 +3. **资源预加载**:`skill_inpause_preview_point.prefab` 在关卡加载时预加载 +4. **每单位限制**:每个单位最多只能缓存一个技能,再次选择会覆盖 +5. **取消选中**:确认技能释放点后会自动取消选中该单位,方便玩家继续操作其他单位 + +--- + +*文档生成时间:2026-02-05* +*生成工具:Cursor AI Agent*