多轮审查和修复

This commit is contained in:
2026-05-12 15:34:08 +08:00
parent f55d2a57c3
commit ebbbb7332e
805 changed files with 838724 additions and 1905 deletions

View File

@@ -63,7 +63,7 @@ Week 14: MapModuleFog of War + 房间探索记录 + 传送点)
---
## 2. Week 10世界互动基础组件
## 2. Week 10世界互动基础组件 ✅ 完成2026-05-10
**参考文档**`08_WorldModule.md`
@@ -1012,7 +1012,7 @@ namespace BaseGames.Tutorial
---
## 3. Week 11液态谜题模块
## 3. Week 11液态谜题模块 ✅ 完成2026-05-11
**参考文档**`21_LiquidPuzzleModule.md`
@@ -1541,40 +1541,57 @@ public class UnderwaterAudioController : MonoBehaviour
```csharp
// Assets/Scripts/World/Liquid/WaterDangerState.cs
// ⚠️ 订阅 LiquidEventChannelSO携带 LiquidEvent struct非 LiquidZone 引用)
// ⚠️ 使用 PlayerStats.HasAbility 替代 AbilityInventorySO项目实际 API无额外 SO 依赖)
public class WaterDangerState : MonoBehaviour
{
[SerializeField] private LiquidPhysicsConfigSO _config;
[SerializeField] private AbilityInventorySO _abilityInventory; // 检查 swim 能力
[SerializeField] private PlayerStats _playerStats; // 检查 Swim 能力
[SerializeField] private LiquidEventChannelSO _onLiquidEntered; // EVT_LiquidEntered
[SerializeField] private LiquidEventChannelSO _onLiquidExited; // EVT_LiquidExited
[SerializeField] private FloatEventChannelSO _onDrownProgress; // 0~1 倒计时进度HUD 用)→ EVT_DrownProgress
[SerializeField] private VoidEventChannelSO _onPlayerDrowned; // 触发死亡 → EVT_PlayerDrowned
private float _drownTimer;
private bool _isActive;
public void OnEnterLiquid(LiquidZone zone)
private void OnEnable()
{
if (zone.Type != LiquidType.Water) return;
if (_abilityInventory.HasAbility(AbilityType.Swim)) return;
_isActive = true;
_drownTimer = _config.DrownTime;
if (_onLiquidEntered != null) _onLiquidEntered.OnEventRaised += OnEnterLiquid;
if (_onLiquidExited != null) _onLiquidExited.OnEventRaised += OnExitLiquid;
}
public void OnExitLiquid()
private void OnDisable()
{
if (_onLiquidEntered != null) _onLiquidEntered.OnEventRaised -= OnEnterLiquid;
if (_onLiquidExited != null) _onLiquidExited.OnEventRaised -= OnExitLiquid;
}
public void OnEnterLiquid(LiquidEvent evt)
{
if (evt.LiquidType != nameof(LiquidType.Water)) return;
if (_playerStats != null && _playerStats.HasAbility(AbilityType.Swim)) return;
_isActive = true;
_drownTimer = _config != null ? _config.DrownTime : 3f;
}
public void OnExitLiquid(LiquidEvent evt)
{
_isActive = false;
_drownTimer = _config.DrownTime;
_onDrownProgress.Raise(0f);
_drownTimer = _config != null ? _config.DrownTime : 3f;
_onDrownProgress?.Raise(0f);
}
private void Update()
{
if (!_isActive) return;
_drownTimer -= Time.deltaTime;
_onDrownProgress.Raise(1f - (_drownTimer / _config.DrownTime));
float drownTime = _config != null ? _config.DrownTime : 3f;
_onDrownProgress?.Raise(1f - (_drownTimer / drownTime));
if (_drownTimer <= 0f)
{
_isActive = false;
_onPlayerDrowned.Raise();
_onPlayerDrowned?.Raise();
}
}
}
@@ -1597,8 +1614,8 @@ public class UnderwaterPostProcessingController : MonoBehaviour
[SerializeField] private Volume _underwaterVolume; // 水下专属 VolumeWeightMode
[SerializeField] private float _blendInDuration = 0.3f;
[SerializeField] private float _blendOutDuration = 0.3f;
[SerializeField] private LiquidEventChannelSO _onLiquidEntered; // ⚠️ EVT_LiquidEnteredpayload: LiquidZone
[SerializeField] private VoidEventChannelSO _onLiquidExited; // ⚠️ EVT_LiquidExited
[SerializeField] private LiquidEventChannelSO _onLiquidEntered; // EVT_LiquidEnteredpayload: LiquidEvent struct
[SerializeField] private LiquidEventChannelSO _onLiquidExited; // EVT_LiquidExited(与 Enter 同类型,保持一致)
private Coroutine _blendCoroutine;
@@ -1613,12 +1630,12 @@ public class UnderwaterPostProcessingController : MonoBehaviour
_onLiquidExited.OnEventRaised -= OnLiquidExited;
}
private void OnLiquidEntered(LiquidZone zone)
private void OnLiquidEntered(LiquidEvent evt)
{
if (zone.Type != LiquidType.Water) return;
if (evt.LiquidType != nameof(LiquidType.Water)) return;
BlendVolume(1f, _blendInDuration);
}
private void OnLiquidExited() => BlendVolume(0f, _blendOutDuration);
private void OnLiquidExited(LiquidEvent evt) => BlendVolume(0f, _blendOutDuration);
private void BlendVolume(float target, float duration)
{
@@ -1641,7 +1658,7 @@ public class UnderwaterPostProcessingController : MonoBehaviour
---
## 4. Week 12进程模块护符/工具/技能)
## 4. Week 12进程模块护符/工具/技能)✅ 完成2026-05-10
**参考文档**`09_ProgressionModule.md`
@@ -2475,7 +2492,7 @@ public class HPContainerPickup : MonoBehaviour
---
## 5. Week 13任务与挑战房间
## 5. Week 13任务与挑战房间 ✅ 完成2026-05-11
**参考文档**`22_QuestChallengeModule.md`
@@ -3089,7 +3106,7 @@ public class QuestGiver : InteractableNPC
---
## 6. Week 14地图/商店/存档迁移
## 6. Week 14地图/商店/存档迁移 ✅ 完成P3-52026-05-11
**参考文档**`15_MapShopModule.md`
@@ -3624,6 +3641,58 @@ public static class SaveMigrator
## 7. 完成标准检查清单
### Week 10 已完成实现2026-05-10
| 文件 | 状态 | 说明 |
|------|------|------|
| `WorldStateRegistry.cs` | ✅ | ScriptableObjectContains/Mark 系列 API + HasFlag/SetFlag + LoadFromSave |
| `InteractableDetector.cs` | ✅ | OverlapCircleAll + FindNearest + InputReaderSO.InteractEvent 绑定 |
| `PlayerSpawnPoint.cs` | ✅ | TransitionId + SpawnPositionGizmo 绿球标记 |
| `RoomTransition.cs` | ✅ | IInteractable自动触发或按键广播 `scene|transitionId` 字符串 |
| `RoomController.cs` | ✅ | Start 切换 RoomCameraGetSpawnPoint 查询出生点 |
| `HazardZone.cs` | ✅ | 即死/定值伤害RespawnType 枚举 |
| `Collectible.cs` | ✅ | Geo/Item/HPOrb 三类PlayerStats 直接调用 |
| `DestructibleTile.cs` | ✅ | IDamageableCheckDestroyCondition virtual hookStart 读档恢复 |
| `DirectionalDestructible.cs` | ✅ | AttackSide 枚举 + SourcePosition 方向校验 |
| `DirectionalInteractable.cs` | ✅ | 三触发模式 + TriggerSide + OneShot 持久化 |
| `MagicWall.cs` | ✅ | Gizmo-only 标记,穿越靠 Layer Matrix |
| `SoftTerrain.cs` | ✅ | Marker 组件(无逻辑) |
| `PhantomInteractable.cs` | ✅ | 继承 DirectionalInteractable额外响应 PhantomBody 层 |
| `MovingPlatform.cs` | ✅ | LinearAB/WayPoints/TriggeredLinear + Passenger SetParent 方案 |
| `CrumblePlatform.cs` | ✅ | Warning/Crumbling/Gone/Respawn 四态协程 + MMF_Player |
| `FalseWall.cs` | ✅ | IDamageableProximity/AttackOnce/AlwaysOpen 三种揭示方式 |
| `BaseGames.World.asmdef` | ✅ | 新增 Input/Combat/Player/Camera/MoreMountains.Tools 引用 |
### P3-2 补充实现2026-05-12
| 文件 | 状态 | 说明 |
|------|------|------|
| `WorldMarkerEventChannelSO.cs` | ✅ | `BaseEventChannelSO<WorldMarker>` 事件频道;命名空间 `BaseGames.World` |
| `WorldMarker.cs` | ✅ | 场景导航标记点;`Activate()`/`Deactivate()` 广播事件频道;`WorldMarkerType` 枚举Objective/NPC/PointOfInterest/Exit/Secret |
| `BreadcrumbTracker.cs` | ✅ | 玩家位置历史追踪;`_recordInterval=2f`/`_maxCrumbs=20`/`_minMoveDistance=1f``GetRecentCrumbs(int)``IReadOnlyList<Vector2>`oldest→newest`Clear()` |
| `TutorialManager.cs` | ✅ | 单例 (`Instance`);实现 `ISaveable``ShowHint`/`CompleteHint`;进度写入 `SaveData.Tutorial`(非 PlayerPrefs与架构 12 §1 注解不同) |
| `TutorialHintUI.cs` | ✅ | HUD 提示 UI`Show(text, duration)` + `Hide()``AutoHideRoutine` 协程TMP_Text 标签 |
| `ContextualHintTrigger.cs` | ✅ | `[RequireComponent(Collider2D)]``_requiresAbility`/`_requiredAbility(AbilityType)` 条件;调用 `LocalizationManager.Get`;首次触发后 `gameObject.SetActive(false)` |
| `SaveData.cs` | ✅ | 追加 `TutorialSaveData Tutorial = new()`;新增 `TutorialSaveData` 类(含 `List<string> CompletedHintIds` |
| `BaseGames.Tutorial.asmdef` | ✅ | 引用 Core.Events/Core.Save/World/Player/Localization |
```
☑ InteractableDetectorOverlapCircleAll 检测最近交互物,驱动 UI 提示显示/隐藏(代码完成)
☑ WorldStateRegistryHashSet 持久化状态LoadFromSave/GetAllFlags 接口完成
☑ RoomTransition + RoomController + PlayerSpawnPoint房间切换框架完成待 SceneLoader 集成)
☑ HazardZone即死/定值伤害(代码完成,待 Unity 内配置 Layer 和 Tag 验证)
☑ CollectibleGeo/Item/HPOrb 拾取(代码完成,待 Unity 内配置 Prefab 验证)
☑ DestructibleTile + DirectionalDestructibleIDamageable + 方向校验(代码完成)
☑ DirectionalInteractable + PhantomInteractable三种触发模式 + WorldStateRegistry 持久化
☑ MagicWall + SoftTerrain标记组件无逻辑
☑ MovingPlatform三种移动模式 + Passenger SetParent 方案(代码完成)
☑ CrumblePlatform四态协程MMF_Player 反馈(代码完成)
☑ FalseWall三种揭示条件 + IDamageable代码完成
□ 场景内端对端验证(待 Unity 编辑器内装配 Prefab 并运行)
□ Console 无 ErrorUnity 编辑器内编译验证)
```
### Week 1114 待实施
```
□ RoomTransition触发切换 → 淡出 → 加载目标场景 → 玩家在对应 SpawnPoint 出生
□ HazardZone掉入深渊 → 瞬间死亡 → 正常死亡流程
@@ -3637,14 +3706,31 @@ public static class SaveMigrator
□ FormSkillSO切换形态 → 对应技能可用 → 释放消耗 SoulPower
□ QuestManager接任务 → 击杀指定敌人 → 进度推进 → 交任务 → 获得奖励
□ ChallengeRoom进入 → 锁门 → 三波敌人依次生成 → 通关 → 奖励 + 开门
MapPanel探索新房间后地图格子变亮已探索持久化重启后不重置
ShopController购买护符 → Geo 减少 → 护符进入 Inventory → 商店标记已售出
MapPanel探索新房间后地图格子变亮已探索持久化MapManager ISaveable 已实现
ShopController购买护符 → Geo 减少EVT_ItemPurchased→ 商店标记已售出IsUnique 机制)
□ 存档迁移:旧版本存档文件加载时无报错,缺失字段填充默认值
□ AddressReferenceGraphWindow菜单 BaseGames/Tools/Asset Reference Graph无孤儿 key红色标记
□ MapRoomDataEditorCustomEditor for MapRoomDataSOScene 内拖拽 GridPosition/GridSize 句柄无报错
□ Console 无 Error
```
### Week 14 已完成实现P3-5地图与商店模块
| 文件 | 状态 | 说明 |
|------|------|------|
| `MapRoomDataSO.cs` | ✅ | `MapRoomDataSO` + `MapDatabaseSO` + `RoomExitData` + `ExitDirection` |
| `MapManager.cs` | ✅ | ISaveable`[DefaultExecutionOrder(-700)]`;订阅 `EVT_RoomEntered``SetMapped` |
| `MapPanel.cs` | ✅ | `MapPanel` + `MapRoomCellUI`OnEnable 重建格子;`EVT_MapUpdated` 增量刷新 |
| `MapPlayerTracker.cs` | ✅ | `WorldToCell`18f/格LateUpdate 找所在房间;`NormalizedPositionInRoom` |
| `MapPin.cs` | ✅ | `MapPinManager` ISaveableMapPin/PinType 定义在 SaveData.cs 避免循环依赖) |
| `ShopItemSO.cs` | ✅ | `ShopItemSO` + `ShopItemType` 枚举CharmSO 引用 |
| `ShopInventorySO.cs` | ✅ | `ShopInventorySO` + `RestockPolicy` 枚举 |
| `ShopController.cs` | ✅ | ISaveable`TryPurchase``GetAvailableItems``Restock``ShopPanel` 存根 |
| `ShopNPC.cs` | ✅ | IInteractable`DialogueEventChannelSO` 触发招呼对话→打开商店 |
| `Editor/Map/MapRoomDataEditor.cs` | ✅ | `[CustomEditor(typeof(MapRoomDataSO))]`Scene 句柄拖拽;居中按钮 |
| `SaveData.cs` | ✅ | `MapSaveData``ExploredRooms/MappedRooms(List<string>)` + `Pins(List<MapPin>)` |
| `BaseGames.World.Map.asmdef` | ✅ | 新增 `BaseGames.Core.Save` + `BaseGames.Core.Events` 引用 |
| `BaseGames.World.Shop.asmdef` | ✅ | 新增 `BaseGames.Core.Save` + `BaseGames.Equipment` + `BaseGames.Dialogue` 引用 |
| `BaseGames.Editor.asmdef` | ✅ | 新增 `BaseGames.World.Map` 引用MapRoomDataEditor 需要) |
> **编辑器工具**`AddressReferenceGraphWindow``Assets/Editor/Assets/AddressReferenceGraphWindow.cs`)扫描所有 `.cs` 文件对 `AddressKeys.X` 的引用,标红孤儿 key0 引用),标黄单次引用 key标绿 ≥2 次引用 key支持导出 CSV架构 13 §11P3 优化)。
**Phase 3 完成后进入 Phase 4。**