chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View File

@@ -0,0 +1,694 @@
# 10 · UI 模块
> **命名空间** `BaseGames.UI`
> **程序集** `BaseGames.UI`
> **路径** `Assets/Scripts/UI/`
> **依赖** `BaseGames.Core.Events`、`TextMeshPro`
---
## 目录
1. [Canvas 架构Persistent 场景内)](#1-canvas-架构)
2. [UIManager](#2-uimanager)
3. [HUDController](#3-hudcontroller)
4. [BossHPBar](#4-bosshpbar)
5. [PauseMenuController](#5-pausemenucontroller)
6. [DeathScreenController](#6-deathscreencontroller)
7. [SettingsPanelController](#7-settingspanelcontroller)
8. [SaveSlotController](#75-saveslotcontroller)
9. [SaveIndicator](#76-saveindicator)
10. [LoadingScreenManager](#77-loadingscreenmanager)
11. [IBossHPProvider 接口](#78-ibosshpprovider-接口)
12. [LoadingOverlay](#8-loadingoverlay)
13. [DialogueBoxHUD Overlay](#9-dialoguebox)
10. [FloatingDamageText伤害数字](#10-floatingdamagetext)
11. [ToastNotification通知弹窗](#11-toastnotification)
12. [InputDeviceIconSwitcher](#12-inputdeviceiconswitcher)
13. [PanelStack控制器导航](#13-panelstack)
14. [UI 事件频道清单](#14-ui-事件频道清单)
---
## 1. Canvas 架构
所有 Canvas 挂在 **Persistent 场景**内,全程常驻:
```
[UIRoot]
├── Canvas_HUD Sorting Order: 10 (Screen Space - Overlay)
│ ├── HPContainer ← HP 格子列表(水平 HorizontalLayoutGroup
│ ├── SoulGauge ← 灵力弧形进度条Image.fillAmount
│ ├── SpiritGauge ← 魄元进度条
│ ├── GeoCounter ← TMP 数字 + 图标
│ ├── SpringCharges ← 灵泉次数图标列
│ ├── FormIndicator ← 当前形态图标3 种形态)
│ ├── ToolSlotHUD ← 工具槽图标 + 次数
│ ├── AbilityHints ← 已解锁技能图标
│ ├── BossHPBar ← 默认隐藏
│ └── InteractPrompt ← 交互提示文字(默认隐藏)
├── Canvas_Menu Sorting Order: 20 (Screen Space - Overlay)
│ ├── MainMenuPanel ← 主菜单(游戏启动时显示)
│ ├── SaveSlotPanel ← 存档槽选择(新游戏/继续,主菜单子面板)
│ ├── PauseMenuPanel ← 暂停菜单(默认隐藏)
│ ├── DeathScreenPanel ← 死亡画面(默认隐藏)
│ ├── SettingsPanel ← 设置菜单(默认隐藏)
│ ├── MapPanel ← 地图(默认隐藏)
│ └── ShopPanel ← 商店(默认隐藏)
└── Canvas_Overlay Sorting Order: 30 (Screen Space - Overlay)
├── LoadingOverlay ← 全屏黑幕(过场遮罩)
├── DialogueBox ← 对话框(底部)
└── ToastContainer ← 通知弹窗容器(右上)
```
**SaveSlotPanel** 展示 3 个存档槽卡片,每张卡片显示角色形态图标、区域名称、游玩时长、存档时间、完成度百分比;由 `SaveSlotController` 驱动(`SaveManager.GetSlotSummaryAsync(slotIndex)` 提供数据)。
**SaveIndicator**:右下角小图标(软盘 + 旋转动画),在自动存档流程中显示(订阅 `EVT_SaveIndicatorVisible` BoolEventChannelSO`true` 触发淡入,`false` 触发淡出),告知玩家正在保存中。
---
## 2. UIManager
```csharp
// 路径: Assets/Scripts/UI/UIManager.cs
[DefaultExecutionOrder(+50)]
public class UIManager : MonoBehaviour
{
[Header("Canvas Roots")]
[SerializeField] private GameObject _hudRoot;
[SerializeField] private GameObject _pauseMenuRoot;
[SerializeField] private GameObject _deathScreenRoot;
[SerializeField] private GameObject _settingsRoot;
[SerializeField] private GameObject _mapRoot;
[SerializeField] private GameObject _shopRoot;
[Header("Event Channels - Subscribe")]
[SerializeField] private GameStateEventChannelSO _onGameStateChanged;
[SerializeField] private VoidEventChannelSO _onPauseRequested;
[SerializeField] private VoidEventChannelSO _onFastTravelOpen;
[SerializeField] private StringEventChannelSO _onShopOpen;
[SerializeField] private VoidEventChannelSO _onMapOpen;
private Stack<GameObject> _panelStack = new();
private void OnEnable()
{
_onGameStateChanged.OnEventRaised += HandleGameStateChanged;
_onPauseRequested.OnEventRaised += TogglePause;
_onFastTravelOpen.OnEventRaised += OpenMap;
_onShopOpen.OnEventRaised += OpenShop;
_onMapOpen.OnEventRaised += OpenMap;
}
private void OnDisable()
{
_onGameStateChanged.OnEventRaised -= HandleGameStateChanged;
_onPauseRequested.OnEventRaised -= TogglePause;
_onFastTravelOpen.OnEventRaised -= OpenMap;
_onShopOpen.OnEventRaised -= OpenShop;
_onMapOpen.OnEventRaised -= OpenMap;
}
private void HandleGameStateChanged(GameStateId state)
{
// HUD 在 Gameplay 和 BossFight 状态下均显示
bool showHud = state == GameStates.Gameplay || state == GameStates.BossFight;
_hudRoot.SetActive(showHud);
// ⚠️ GameStateId 为 struct不可用 switch用 if/else 比较
if (state == GameStates.Dead)
_deathScreenRoot.SetActive(true);
else if (state == GameStates.Cutscene)
_hudRoot.SetActive(false); // 过场动画隐藏 HUD
}
public void OpenPanel(GameObject panel)
{
if (_panelStack.Count > 0) _panelStack.Peek().SetActive(false);
panel.SetActive(true);
_panelStack.Push(panel);
}
public void CloseTopPanel()
{
if (_panelStack.Count == 0) return;
_panelStack.Pop().SetActive(false);
if (_panelStack.Count > 0) _panelStack.Peek().SetActive(true);
}
private void TogglePause() => OpenPanel(_pauseMenuRoot);
private void OpenShop(string npcId) => OpenPanel(_shopRoot);
private void OpenMap() => OpenPanel(_mapRoot);
}
```
---
## 3. HUDController
```csharp
// 路径: Assets/Scripts/UI/HUD/HUDController.cs
public class HUDController : MonoBehaviour
{
[Header("HP")]
[SerializeField] private Transform _hpContainer;
[SerializeField] private GameObject _hpCellPrefab; // 单格 HP 图标
[Header("Gauges")]
[SerializeField] private Image _soulGaugeFill;
[SerializeField] private Image _spiritGaugeFill;
[SerializeField] private TMP_Text _geoText;
[Header("Spring Charges")]
[SerializeField] private Transform _springContainer;
[SerializeField] private GameObject _springIconPrefab;
[Header("Form")]
[SerializeField] private Image[] _formIcons; // 3 forms
[Header("Interact Prompt")]
[SerializeField] private TMP_Text _interactText;
[SerializeField] private GameObject _interactPromptRoot;
[Header("Event Channels - Subscribe")]
[SerializeField] private IntEventChannelSO _onHPChanged;
[SerializeField] private IntEventChannelSO _onMaxHPChanged;
[SerializeField] private IntEventChannelSO _onSoulPowerChanged;
[SerializeField] private IntEventChannelSO _onSpiritPowerChanged;
[SerializeField] private IntEventChannelSO _onGeoChanged;
[SerializeField] private IntEventChannelSO _onSpringChargesChanged;
[SerializeField] private IntEventChannelSO _onFormChanged;
[SerializeField] private StringEventChannelSO _onShowInteractPrompt;
[SerializeField] private VoidEventChannelSO _onHideInteractPrompt;
private void OnEnable()
{
_onHPChanged.OnEventRaised += UpdateHP;
_onMaxHPChanged.OnEventRaised += RebuildHPCells;
_onSoulPowerChanged.OnEventRaised += val => _soulGaugeFill.fillAmount = val / 100f;
_onSpiritPowerChanged.OnEventRaised += val => _spiritGaugeFill.fillAmount = val / 100f;
_onGeoChanged.OnEventRaised += val => _geoText.text = val.ToString();
_onSpringChargesChanged.OnEventRaised += RebuildSpringIcons;
_onFormChanged.OnEventRaised += UpdateFormIcon;
_onShowInteractPrompt.OnEventRaised += ShowInteractPrompt;
_onHideInteractPrompt.OnEventRaised += HideInteractPrompt;
}
private void OnDisable() { /* 对称 -= */ }
private void UpdateHP(int current); // 更新 HP 格子激活/灰化状态
private void RebuildHPCells(int max); // 重建 HP 格子列表MaxHP 改变时)
private void RebuildSpringIcons(int charges);
private void UpdateFormIcon(int formIndex);
private void ShowInteractPrompt(string text);
private void HideInteractPrompt();
}
```
---
## 4. BossHPBar
```csharp
// 路径: Assets/Scripts/UI/HUD/BossHPBar.cs
public class BossHPBar : MonoBehaviour
{
[SerializeField] private TMP_Text _bossNameText;
[SerializeField] private Image _hpFill;
[SerializeField] private Transform _phaseMarkersRoot;
[SerializeField] private GameObject _phaseMarkerPrefab;
[Header("Event Channels")]
[SerializeField] private BoolEventChannelSO _onBossFightToggled; // true=开始false=结束
[SerializeField] private IntEventChannelSO _onBossHPChanged;
[SerializeField] private StringEventChannelSO _onBossNameSet;
[SerializeField] private IntEventChannelSO _onBossHPMaxSet;
private int _maxHP;
private void OnEnable()
{
_onBossFightToggled.OnEventRaised += OnBossFightToggled;
_onBossHPChanged.OnEventRaised += hp => _hpFill.fillAmount = (float)hp / _maxHP;
_onBossNameSet.OnEventRaised += name => _bossNameText.text = name;
_onBossHPMaxSet.OnEventRaised += max => _maxHP = max;
}
private void OnDisable()
{
_onBossFightToggled.OnEventRaised -= OnBossFightToggled;
_onBossHPChanged.OnEventRaised -= hp => _hpFill.fillAmount = (float)hp / _maxHP;
_onBossNameSet.OnEventRaised -= name => _bossNameText.text = name;
_onBossHPMaxSet.OnEventRaised -= max => _maxHP = max;
}
private void OnBossFightToggled(bool started)
{
if (started) StartCoroutine(SlideIn());
else StartCoroutine(SlideOut());
}
private IEnumerator SlideIn(); // 动画Boss 血条从屏幕底部滑入
private IEnumerator SlideOut(); // 动画Boss 血条滑出并隐藏
}
```
---
## 5. PauseMenuController
```csharp
// 路径: Assets/Scripts/UI/Menus/PauseMenuController.cs
public class PauseMenuController : MonoBehaviour
{
[SerializeField] private UIManager _uiManager;
[SerializeField] private Button _btnResume;
[SerializeField] private Button _btnSettings;
[SerializeField] private Button _btnMainMenu;
[SerializeField] private Button _btnQuit;
[Header("Event Channels")]
[SerializeField] private GameStateEventChannelSO _onGameStateChanged;
[SerializeField] private VoidEventChannelSO _onResumeRequested;
private void Awake()
{
_btnResume.onClick.AddListener(Resume);
_btnSettings.onClick.AddListener(() => _uiManager.OpenPanel(_settingsRoot));
_btnMainMenu.onClick.AddListener(GoToMainMenu);
_btnQuit.onClick.AddListener(Application.Quit);
}
private void Resume()
{
_onResumeRequested.Raise();
_uiManager.CloseTopPanel();
}
private void GoToMainMenu();
// 广播 EVT_SceneLoadRequest目标 = MainMenuScene
}
```
---
## 6. DeathScreenController
```csharp
// 路径: Assets/Scripts/UI/Menus/DeathScreenController.cs
public class DeathScreenController : MonoBehaviour
{
[SerializeField] private TMP_Text _deathMessage;
[SerializeField] private Button _btnRespawn;
[Header("Event Channels")]
[SerializeField] private VoidEventChannelSO _onPlayerDied;
[SerializeField] private VoidEventChannelSO _onDeathScreenConfirmed; // Raise → GameManager.RespawnCoroutine
private void OnEnable() => _onPlayerDied.OnEventRaised += OnPlayerDied;
private void OnDisable() => _onPlayerDied.OnEventRaised -= OnPlayerDied;
// ⚠️ EVT_PlayerDied 发出后需等待 1.5s 死亡动画,否则死亡画面会提前弹出
private void OnPlayerDied() => StartCoroutine(ShowAfterDelay(1.5f));
private IEnumerator ShowAfterDelay(float delay)
{
yield return new WaitForSeconds(delay);
Show();
}
private void Show()
{
gameObject.SetActive(true);
_btnRespawn.onClick.RemoveAllListeners();
_btnRespawn.onClick.AddListener(Confirm);
}
private void Confirm()
{
gameObject.SetActive(false);
_onDeathScreenConfirmed.Raise(); // GameManager 监听后执行 RespawnCoroutine
}
}
```
---
## 7. SettingsPanelController
```csharp
// 路径: Assets/Scripts/UI/Menus/SettingsPanelController.cs
// 驱动 SettingsManager 的全部 Set* 方法
public class SettingsPanelController : MonoBehaviour
{
[SerializeField] private SettingsManager _settings;
[Header("Audio")]
[SerializeField] private Slider _masterVolume;
[SerializeField] private Slider _bgmVolume;
[SerializeField] private Slider _sfxVolume;
[SerializeField] private Slider _ambientVolume;
[Header("Video")]
[SerializeField] private Toggle _vSyncToggle;
[SerializeField] private TMP_Dropdown _fpsDropdown;
[SerializeField] private TMP_Dropdown _resolutionDropdown;
private void Start()
{
// 从 SettingsManager 读取当前值并填充控件
// 绑定 onChange 事件 → 调用对应 _settings.Set*()
}
}
```
---
## 7.5 SaveSlotController
```csharp
// 路径: Assets/Scripts/UI/Menus/SaveSlotController.cs
// 驱动主菜单存档槽选择(新游戏 / 继续)
public class SaveSlotController : MonoBehaviour
{
[SerializeField] private SaveSlotUI[] _slotUIs; // 3 个存档槽 UI
[SerializeField] private SaveManager _saveManager;
public async UniTask RefreshAsync()
{
for (int i = 0; i < 3; i++)
{
var summary = await _saveManager.GetSlotSummaryAsync(i);
_slotUIs[i].Refresh(summary); // null = 空槽(显示“新局”)
}
}
public void OnSlotSelected(int slotIndex);
// 新局_saveManager.CreateSlot(slotIndex) → 启动游戏
// 继续_saveManager.LoadAsync(slotIndex) → 载入存档
}
// 单个存档槽卡片组件
public class SaveSlotUI : MonoBehaviour
{
[SerializeField] private TMP_Text _playtimeText;
[SerializeField] private TMP_Text _regionText;
[SerializeField] private TMP_Text _percentText;
[SerializeField] private Image _formIcon;
[SerializeField] private TMP_Text _lastSavedText;
[SerializeField] private GameObject _emptyIndicator; // 空槽提示
public void Refresh(SlotSummary summary);
}
```
---
## 7.6 SaveIndicator
```csharp
// 路径: Assets/Scripts/UI/SaveIndicator.cs
// 右下角存档进行中提示字
[RequireComponent(typeof(CanvasGroup))]
public class SaveIndicator : MonoBehaviour
{
[SerializeField] private CanvasGroup _cg;
[SerializeField] private float _fadeDuration = 0.2f;
[Header("Event Channels")]
// ⚠️ 统一使用单一 BoolEventChannelSO对齐 02_EventSystem §4 EVT_SaveIndicatorVisible 和 12_SaveModule §4/§6
[SerializeField] private BoolEventChannelSO _onSaveIndicatorVisible; // → EVT_SaveIndicatorVisible
private void OnEnable()
{
_onSaveIndicatorVisible.OnEventRaised += visible => FadeTo(visible ? 1f : 0f);
}
private void OnDisable()
{
_onSaveIndicatorVisible.OnEventRaised -= visible => FadeTo(visible ? 1f : 0f);
}
private void FadeTo(float target) => StartCoroutine(FadeCoroutine(target));
private IEnumerator FadeCoroutine(float target)
{
float start = _cg.alpha;
float t = 0;
while (t < _fadeDuration)
{
_cg.alpha = Mathf.Lerp(start, target, t / _fadeDuration);
t += Time.unscaledDeltaTime;
yield return null;
}
_cg.alpha = target;
}
}
```
---
## 7.7 LoadingScreenManager
```csharp
// 路径: Assets/Scripts/UI/LoadingScreenManager.cs
// 全屏加载面:进度条 + 提示文字 + 随机背景图
public class LoadingScreenManager : MonoBehaviour
{
[SerializeField] private GameObject _loadingRoot;
[SerializeField] private Image _progressFill; // 进度条 fillAmount
[SerializeField] private TMP_Text _tipText; // 载入提示
[SerializeField] private Image[] _backgroundArts; // 随机切换的背景图
[SerializeField] private string[] _tipKeys; // 本地化 Key 数组
[SerializeField] private float _minDisplayTime = 0.5f; // 载入面最少展示时长
[Header("Event Channels")]
[SerializeField] private VoidEventChannelSO _onLoadingStarted;
[SerializeField] private VoidEventChannelSO _onLoadingComplete;
[SerializeField] private FloatEventChannelSO _onLoadingProgressUpdated; // 01
private void OnEnable()
{
_onLoadingStarted.OnEventRaised += Show;
_onLoadingComplete.OnEventRaised += Hide;
_onLoadingProgressUpdated.OnEventRaised += SetProgress;
}
private void OnDisable()
{
_onLoadingStarted.OnEventRaised -= Show;
_onLoadingComplete.OnEventRaised -= Hide;
_onLoadingProgressUpdated.OnEventRaised -= SetProgress;
}
private void Show()
{
_loadingRoot.SetActive(true);
_progressFill.fillAmount = 0f;
// 随机选取背景图和提示文字
foreach (var bg in _backgroundArts) bg.enabled = false;
_backgroundArts[Random.Range(0, _backgroundArts.Length)].enabled = true;
_tipText.text = LocalizationManager.Get(_tipKeys[Random.Range(0, _tipKeys.Length)]);
}
private void Hide() => StartCoroutine(HideAfterMinTime());
private IEnumerator HideAfterMinTime()
{
// 确保载入面至少展示 _minDisplayTime 秒
yield return new WaitForSecondsRealtime(_minDisplayTime);
_loadingRoot.SetActive(false);
}
private void SetProgress(float value) => _progressFill.fillAmount = value;
}
```
---
## 7.8 IBossHPProvider 接口
```csharp
// 路径: Assets/Scripts/UI/HUD/IBossHPProvider.cs
// 解耦接口:让 BossHPBar 不直接依赖 BossBaseUI → Combat 逆向耐合)
// BossBase 在运行时实现此接口BossOrchestrator 配置到 BossHPBar._provider 中
public interface IBossHPProvider
{
string BossId { get; } // Boss 前缀 ID
string BossNameKey { get; } // 本地化 Key
float HPRatio { get; } // 01 实时 HP 比例
int TotalPhases { get; } // Boss 总阶段数为阶段标记数
float[] PhaseThresholds { get; } // 各阶段切换 HP 阈值
}
```
---
## 8. LoadingOverlay
```csharp
// 路径: Assets/Scripts/UI/LoadingOverlay.cs
// 由 SceneLoader 直接调用(或通过事件),控制全屏黑幕渐入渐出
public class LoadingOverlay : MonoBehaviour
{
[SerializeField] private CanvasGroup _canvasGroup;
[SerializeField] private float _fadeDuration = 0.3f;
[Header("Event Channels")]
[SerializeField] private BoolEventChannelSO _onLoadingOverlayRequested;
private void OnEnable() => _onLoadingOverlayRequested.OnEventRaised += SetVisible;
private void OnDisable() => _onLoadingOverlayRequested.OnEventRaised -= SetVisible;
private void SetVisible(bool visible) => StartCoroutine(FadeCoroutine(visible ? 1f : 0f));
private IEnumerator FadeCoroutine(float target)
{
float start = _canvasGroup.alpha;
float t = 0;
while (t < _fadeDuration)
{
_canvasGroup.alpha = Mathf.Lerp(start, target, t / _fadeDuration);
t += Time.unscaledDeltaTime;
yield return null;
}
_canvasGroup.alpha = target;
_canvasGroup.blocksRaycasts = target > 0.5f;
}
}
```
---
## 9. DialogueBox
```csharp
// 路径: Assets/Scripts/UI/DialogueBox.cs
// 挂在 Canvas_Overlay 下;由 DialogueManager 控制(见 14_NarrativeModule.md
public class DialogueBox : MonoBehaviour
{
[SerializeField] private TMP_Text _speakerNameText;
[SerializeField] private TMP_Text _dialogueText;
[SerializeField] private GameObject _continuePrompt;
// DialogueManager 直接调用(不通过事件频道,避免帧延迟)
public void Show(string speakerName, string text, bool showContinue);
public void Hide();
// 文字逐字打印协程
public IEnumerator TypeText(string text, float charDelay = 0.03f);
}
```
---
## 10. FloatingDamageText
```csharp
// 路径: Assets/Scripts/UI/FloatingDamageText.cs
// 从对象池取出,显示伤害数字,向上飘动后归还
public class FloatingDamageText : MonoBehaviour
{
[SerializeField] private TMP_Text _text;
[SerializeField] private float _floatDistance = 1.5f;
[SerializeField] private float _duration = 0.8f;
private string _poolKey = AddressKeys.UI_FloatingDmgText;
public void Show(Vector2 worldPosition, int damage, DamageType type);
// 1. 设置世界坐标Camera.main.WorldToScreenPoint → RectTransform
// 2. 颜色Normal=白, Fire=橙, Poison=绿, True=黄
// 3. 协程向上漂移 + alpha 淡出
// 4. 归还对象池
// 由 EVT_DamageDealt 频道触发HUDController 订阅后调用)
}
```
---
## 11. ToastNotification
```csharp
// 路径: Assets/Scripts/UI/ToastNotification.cs
// 右上角通知弹窗(能力解锁、成就、提示)
public class ToastNotification : MonoBehaviour
{
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _bodyText;
[SerializeField] private Image _icon;
[SerializeField] private float _displayDuration = 3f;
public void Show(string title, string body, Sprite icon = null);
private IEnumerator AutoHide();
}
// ToastManager管理通知队列一次只显示一条
public class ToastManager : MonoBehaviour
{
[SerializeField] private ToastNotification _toast;
private Queue<(string title, string body, Sprite icon)> _queue = new();
[Header("Event Channels")]
[SerializeField] private StringEventChannelSO _onAchievementUnlocked; // 广播成就名
// ... 其他通知来源
public void Enqueue(string title, string body, Sprite icon = null);
}
```
---
## 12. InputDeviceIconSwitcher
```csharp
// 路径: Assets/Scripts/UI/InputDeviceIconSwitcher.cs
// 检测输入设备切换KB/手柄),自动替换 UI 按键图标
public class InputDeviceIconSwitcher : MonoBehaviour
{
[SerializeField] private InputDeviceIconSetSO _kbIconSet;
[SerializeField] private InputDeviceIconSetSO _padIconSet;
[Header("Event Channel")]
[SerializeField] private BoolEventChannelSO _onDeviceChanged; // true=手柄
private void OnEnable() => _onDeviceChanged.OnEventRaised += SwitchIconSet;
private void OnDisable() => _onDeviceChanged.OnEventRaised -= SwitchIconSet;
private void SwitchIconSet(bool isGamepad);
// 广播给所有 InputIconImage 组件(自行从 IconSet 查找对应 Sprite
}
```
---
## 13. PanelStack
```csharp
// 已集成在 UIManager 内部OpenPanel / CloseTopPanel
// 控制器导航规则:
// - 每次 OpenPanel 时设置 EventSystem.SetSelectedGameObject(panel.defaultButton)
// - Escape / 手柄 B 键 → 触发 CloseTopPanel
// - Stack 为空时 → 若在 Gameplay 状态则无操作,若在 MainMenu 则弹出退出确认
```
---
## 14. UI 事件频道清单
| 资产名 | 类型 | Raise 方 | Subscribe 方 |
|--------|------|---------|-------------|
| `EVT_GameStateChanged` | `GameStateEventChannelSO` | `GameManager` | `UIManager` |
| `EVT_PlayerDied` | `VoidEventChannelSO` | `PlayerStats` | `DeathScreenController``GameManager` |
| `EVT_DeathScreenConfirmed` | `VoidEventChannelSO` | `DeathScreenController`Respawn 按钮) | `GameManager`(启动 RespawnCoroutine |
| `EVT_ShowInteractPrompt` | `StringEventChannelSO` | `InteractableDetector` | `HUDController` |
| `EVT_HideInteractPrompt` | `VoidEventChannelSO` | `InteractableDetector` | `HUDController` |
| `EVT_BossFightToggled` | `BoolEventChannelSO`true=开始false=结束) | `BossOrchestrator` | `BossHPBar``AudioManager`(切 Boss BGM |
| `EVT_BossHPChanged` | `IntEventChannelSO` | `BossBase` | `BossHPBar` |
| `EVT_BossNameSet` | `StringEventChannelSO` | `BossOrchestrator` | `BossHPBar` |
| `EVT_BossHPMaxSet` | `IntEventChannelSO` | `BossBase` | `BossHPBar` |
| `EVT_LoadingOverlay` | `BoolEventChannelSO` | `SceneLoader` | `LoadingOverlay` |
| `EVT_DamageDealt` | `DamageInfoEventChannelSO` | `HurtBox` | `HUDController`(生成伤害数字)、`AchievementManager` |
| `EVT_AchievementUnlocked` | `StringEventChannelSO` | `AchievementManager` | `ToastManager` |
| `EVT_AbilityUnlocked` | `StringEventChannelSO`abilityId | `PlayerStats.UnlockAbility` | `ToastManager``HUDController` |
| `EVT_PlayerFormChanged` | `IntEventChannelSO` | `FormController` | `HUDController``SkillHUD` |
| `EVT_InputDeviceChanged` | `BoolEventChannelSO` | 输入系统(设备切换回调) | `InputDeviceIconSwitcher` |
| `EVT_LoadingStarted` | `VoidEventChannelSO` | `SceneLoader` | `LoadingScreenManager` |
| `EVT_LoadingComplete` | `VoidEventChannelSO` | `SceneLoader` | `LoadingScreenManager` |
| `EVT_LoadingProgressUpdated` | `FloatEventChannelSO` | `SceneLoader` | `LoadingScreenManager` |
| `EVT_SaveIndicatorVisible` | `BoolEventChannelSO`true=显示false=隐藏) | `SaveManager.SaveAsync()` | `SaveIndicator` |