# 62 · 无障碍功能系统(Accessibility System) > **命名空间** `BaseGames.Accessibility` > **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md) > **依赖** `BaseGames.UI` · `BaseGames.Input` · `BaseGames.Audio` · `BaseGames.Core.Events` > **关联** 10_UISystem · 25_InputRebindingUI · 12_AudioSystem · 29_DifficultyModesGuide > **重要声明** 无障碍功能 ≠ 简单模式。无障碍选项服务于有不同能力需求的玩家,不改变游戏的挑战定义,与难度系统独立运作。 --- ## 目录 1. [无障碍设计哲学](#1-无障碍设计哲学) 2. [AccessibilitySettingsSO — 数据容器](#2-accessibilitysettingsso--数据容器) 3. [视觉无障碍](#3-视觉无障碍) 4. [运动敏感度设置](#4-运动敏感度设置) 5. [字幕与文字无障碍](#5-字幕与文字无障碍) 6. [输入辅助系统](#6-输入辅助系统) 7. [音频无障碍](#7-音频无障碍) 8. [无障碍设置 UI](#8-无障碍设置-ui) 9. [SaveData 集成](#9-savedata-集成) 10. [平台无障碍合规](#10-平台无障碍合规) --- ## 1. 无障碍设计哲学 ### 1.1 核心立场 | 立场 | 说明 | |------|------| | **尊重需求多样性** | 色盲、运动障碍、听觉障碍玩家有同等权利享受完整游戏体验 | | **非侵入性设计** | 无障碍选项默认关闭,不影响未开启的玩家的游戏体验 | | **与难度系统分离** | 无障碍设置不出现在难度菜单中,避免"弱者选项"的负面暗示 | | **独立专属入口** | 主菜单和暂停菜单均有独立的"无障碍"按钮(不与"设置"合并)| ### 1.2 支持目标用户群 | 用户需求 | 覆盖方案 | |---------|---------| | 色盲(红绿色盲/蓝黄色盲)| 色盲滤镜 + 可选高对比模式 | | 畏光/光敏感癫痫 | 屏幕震动关闭 + 闪光效果弱化 + 闪光频率上限 | | 运动晕眩 | 镜头晃动关闭 + 视野减少模式 | | 上肢/手部运动障碍 | 连按→长按、自动弹反辅助、输入重绑定(见 25_InputRebindingUI)| | 弱视 | 大字体模式、UI 高对比模式、游戏画面对比度增强 | | 听觉障碍 | 全字幕(SFX 提示字幕)、视觉危险提示 | --- ## 2. AccessibilitySettingsSO — 数据容器 ```csharp [CreateAssetMenu(menuName = "Accessibility/AccessibilitySettings")] public class AccessibilitySettingsSO : ScriptableObject { // ── 视觉无障碍 ── [Header("色盲模式")] public ColorBlindMode colorBlindMode = ColorBlindMode.None; public bool highContrastMode = false; public float gameContrastBoost = 0f; // 0 ~ 1.0 // ── 运动无障碍 ── [Header("运动敏感度")] public bool disableScreenShake = false; public bool disableCameraMotion = false; // 关闭镜头摇移过渡 public float cameraMotionScale = 1f; // 0 ~ 1.0(0 = 完全关闭) public bool reduceParticleEffects = false; // 减少粒子密度 50% public bool disableFlashingEffects = false; // 禁止所有频率 > 3Hz 的闪烁 public int flashFrequencyLimit = 3; // 光敏保护:最大闪光频率(Hz) // ── 字幕 ── [Header("字幕系统")] public bool subtitlesEnabled = false; public bool sfxSubtitlesEnabled = false; // 环境音/危险音效的文字提示 public float subtitleFontSizeMultiplier = 1f; // 0.75 ~ 2.0 public bool subtitleBackgroundEnabled = true; // 字幕背景不透明框 public float subtitleBackgroundOpacity = 0.7f; public bool speakerNameEnabled = true; // ── 输入辅助 ── [Header("输入辅助")] public bool autoParryAssist = false; // 自动弹反辅助 public float parryWindowExtension = 0f; // 弹反窗口扩展(秒),0 ~ 0.2 public bool holdToMash = false; // 长按替代连按(如快速逃脱 QTE) public bool stickyJump = false; // 跳跃键释放容忍(松手后 0.1s 内仍可触发可变跳跃高度缩减) public bool autoClimb = false; // 接触墙面自动开始攀爬(无需按键) // ── 音频无障碍 ── [Header("音频无障碍")] public bool monoAudio = false; // 单声道模式(听觉障碍) public float leftRightBalance = 0f; // -1 ~ +1 public bool visualDangerIndicator = false; // 视觉危险提示(代替音效危险提示) } public enum ColorBlindMode { None, // 无(默认) Protanopia, // 红色盲 Deuteranopia, // 绿色盲 Tritanopia, // 蓝黄色盲 Achromatopsia, // 全色盲(高对比灰度) } ``` --- ## 3. 视觉无障碍 ### 3.1 色盲滤镜系统 使用 URP 2D 后处理 `ColorBlindFilter` 自定义 Pass 实现,在最终合成阶段应用色彩矩阵变换: ```csharp // Assets/Scripts/Accessibility/ColorBlindFilter.cs public class ColorBlindFilter : ScriptableRendererFeature { [SerializeField] ColorBlindMode _mode; // 色彩矩阵(3×3,基于 Brettel et al. 1997 算法) private static readonly Dictionary _matrices = new() { [ColorBlindMode.Protanopia] = new Matrix4x4( new Vector4(0.567f, 0.433f, 0.000f, 0), new Vector4(0.558f, 0.442f, 0.000f, 0), new Vector4(0.000f, 0.242f, 0.758f, 0), new Vector4(0, 0, 0, 1)), // Deuteranopia / Tritanopia / Achromatopsia 矩阵类似... }; public override void Create() { /* ... */ } public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) { if (_mode == ColorBlindMode.None) return; renderer.EnqueuePass(new ColorBlindPass(_matrices[_mode])); } } ``` **切换时机**:`AccessibilityManager.ApplySettings()` 在设置变更时调用,更新 Renderer Feature 参数。 ### 3.2 各色盲模式下的关键颜色调整 色盲滤镜作用于**全屏幕后处理**。此外,以下 UI 元素额外添加**图标/形状**辅助区分,不依赖单一颜色: | 元素 | 默认颜色方案 | 色盲辅助方案 | |------|-----------|------------| | HP(满)/ HP(空)| 绿色 / 灰色 | 实心圆 / 空心圆(形状区分)| | 可弹反电报 | 金色轮廓 | 金色轮廓 + 星形粒子 | | 不可弹反警告 | 红色轮廓 | 红色轮廓 + X 形覆盖 | | 危险液体区域 | 颜色区分 | 底部危险斜线纹样 | | 地图房间类型 | 颜色区分 | 颜色 + 图标(Boss头骨/存档灯/商店袋)| ### 3.3 高对比度模式 当 `highContrastMode = true` 时: - 全屏应用高对比后处理(Contrast +0.5, Saturation -0.3, Brightness 微调) - 所有敌人 + 玩家 + NPC 的轮廓线从标准宽度 (1px) 加粗为 **2px 高亮白色轮廓**(使用 `OutlinePass`) - 地图背景统一变为深灰,房间颜色鲜明化 ### 3.4 游戏对比度增强 `gameContrastBoost`(0-1.0)控制 Global Volume 中 Color Adjustment 的对比度: ```csharp void ApplyContrastBoost(float boost) { var ca = globalVolume.profile.TryGet(out var adj); adj.contrast.value = Mathf.Lerp(0f, 50f, boost); // 0 ~ 50(PostProcess 单位) } ``` --- ## 4. 运动敏感度设置 ### 4.1 屏幕震动控制 `disableScreenShake` 控制 **Feel MMF CinemachineImpulse** 和所有 **ScreenShake** 反馈: ```csharp // FeedbackSystem 的 ScreenShake 请求需经过此检查 public static bool CanPlayScreenShake() => !AccessibilityManager.Instance.Settings.disableScreenShake; ``` 当关闭时: - `MMFeedbacks` 中的 `MMF_CameraShake` 和 `MMF_CinemachineImpulse` 不执行 - 其余反馈(VFX、音效、时间缩放)正常执行 ### 4.2 镜头运动控制 `cameraMotionScale`(0-1.0)缩放以下镜头效果: | 效果 | 默认值 | Scale = 0 时 | |------|-------|------------| | 房间过渡镜头移动速度 | 正常 | 立即切换(无过渡动画)| | Cinemachine Damping(跟随延迟)| 0.3s | 0s(完全锁定)| | Boss 战的镜头拉远效果 | 启用 | 禁用 | | 死亡慢镜头特写 | 启用 | 跳过特写 | ### 4.3 粒子效果减少 当 `reduceParticleEffects = true` 时: ```csharp // VFXPool.SpawnParticle() 入口处检查 int particleCount = AccessibilityManager.Instance.Settings.reduceParticleEffects ? Mathf.CeilToInt(requestedCount * 0.5f) // 减少 50% : requestedCount; ``` 影响范围:攻击命中粒子、环境粒子、Dead 消散粒子。不影响:弹反特效(功能性视觉反馈)、危险区域边界粒子。 ### 4.4 闪光频率保护 光敏感癫痫保护:`AccessibilityValidator` 在任何闪烁效果触发前检查频率限制: ```csharp public class AccessibilityValidator { private float _lastFlashTime; // 在所有 HurtFlash / BossTransitionFlash / VoidShockwave 等调用前检查 public bool CanFlash() { var settings = AccessibilityManager.Instance.Settings; if (settings.disableFlashingEffects) return false; float minInterval = 1f / settings.flashFrequencyLimit; // 默认 1/3 ≈ 0.33s if (Time.unscaledTime - _lastFlashTime < minInterval) return false; _lastFlashTime = Time.unscaledTime; return true; } } ``` --- ## 5. 字幕与文字无障碍 ### 5.1 对话字幕 `subtitlesEnabled` 控制对话文字是否显示(默认 true,因为游戏无配音,这实质上是强制开启的;此选项更多用于控制**字幕样式**): 字幕面板配置: ``` SubtitlePanel(Canvas) ├── Background(Image,RectTransform 根据文字内容自动扩展) │ opacity: subtitleBackgroundOpacity(0.7 默认) │ color: #000000 └── SubtitleText(TextMeshPro) font: BitmapFont_Main(× subtitleFontSizeMultiplier) color: #E8E0D0 alignment: 居中 max line width: 屏幕宽度 × 0.7 ``` ### 5.2 环境音效字幕(SFX Subtitles) 当 `sfxSubtitlesEnabled = true` 时,**危险提示音效**会在屏幕边缘显示文字提示: | 音效 | SFX 字幕文本 | 显示位置 | |------|------------|---------| | Boss 攻击电报音 | [Boss 警告] | 屏幕顶部 | | 危险环境(毒素流动)| [危险液体流动声] | 屏幕左/右侧(来源方向)| | 背后敌人警报 | [背后有敌人] | 屏幕底部 | | 存档台激活 | [存档台激活] | 屏幕右上角 | SFX 字幕持续时间:2 秒,然后淡出(Fade 0.5s)。 ```csharp [CreateAssetMenu(menuName = "Accessibility/SFXSubtitleConfig")] public class SFXSubtitleConfigSO : ScriptableObject { public string audioClipId; // 关联的 AudioEventSO ID public string subtitleText; // 对应文字(需多语言化) public SubtitlePos position; // Top / Bottom / Left / Right public float displayDuration = 2f; } ``` ### 5.3 大字体支持 `subtitleFontSizeMultiplier`(0.75 ~ 2.0)影响: - 对话文字大小 - Lore 碎片文字大小 - 暂停菜单所有文字 HUD 数字(HP/Geo)固定大小(16px),不受影响——超大字体会覆盖游戏画面。 --- ## 6. 输入辅助系统 ### 6.1 自动弹反辅助(Auto Parry Assist) 当 `autoParryAssist = true` 时,弹反判定规则变更: ``` 正常弹反:玩家必须在攻击命中前的 ParryWindowMs 内按下弹反键 自动弹反辅助: 方式 A(窗口扩展):parryWindowExtension 额外增加弹反窗口(最大 +0.2s) 方式 B(自动触发):若玩家按下了攻击/弹反键,在 ±0.3s 内命中的可弹反攻击自动弹反 ``` **重要**:成就 `"完美弹反大师"` 在 `autoParryAssist = true` 时无法解锁。 ### 6.2 长按替代连按(Hold to Mash) 当 `holdToMash = true` 时,所有需要快速连按的操作改为长按: | 操作 | 原来 | 辅助后 | |------|------|-------| | 逃脱敌人抓取(QTE)| 快速连按 A 键 | 长按 A 键 | | 快速填充灵力 | — | — | | (暂无其他连按操作)| — | — | ```csharp // InputAssistService.cs public bool CheckMashInput(InputAction action, int requiredPresses) { if (!Settings.holdToMash) return _mashCounter[action] >= requiredPresses; // 正常连按计数 // Hold to Mash:长按 0.5s 等效完成所有连按 return action.ReadValue() > 0.5f && Time.unscaledTime - _holdStartTime[action] >= 0.5f; } ``` ### 6.3 粘性跳跃(Sticky Jump) `stickyJump = true` 时,松开跳跃键后额外 0.1s 内仍然可以触发 `CutJump`(可变跳跃高度缩减): ```csharp // PlayerMovement.cs public void HandleJumpRelease() { float tolerance = Settings.stickyJump ? 0.1f : 0f; if (Time.time - _jumpPressedTime > _jumpHoldDuration + tolerance) CutJump(); } ``` ### 6.4 自动攀墙(Auto Climb) `autoClimb = true` 时,玩家接触墙面自动进入 WallGrab 状态(无需主动按键)。 注意:需保留手动离开墙壁的操作(按反向移动键),避免误触导致无法脱离。 --- ## 7. 音频无障碍 ### 7.1 单声道模式 `monoAudio = true` 时,在 AudioMixer 的 Master 混音器上应用**单声道 DSP 效果**: ```csharp void ApplyMonoAudio(bool mono) { if (mono) masterMixer.SetFloat("MonoMix", 1f); // Custom DSP Parameter,将 L/R 混合 else masterMixer.SetFloat("MonoMix", 0f); } ``` ### 7.2 左右声道平衡 `leftRightBalance`(-1 ~ +1)调整 Master Mixer 的 L/R 输出增益: ```csharp void ApplyBalance(float balance) { float leftGain = balance <= 0 ? 1f : 1f - balance; float rightGain = balance >= 0 ? 1f : 1f + balance; masterMixer.SetFloat("LeftGain", Mathf.LinearToDecibels(leftGain)); masterMixer.SetFloat("RightGain", Mathf.LinearToDecibels(rightGain)); } ``` ### 7.3 视觉危险提示(Visual Danger Indicator) `visualDangerIndicator = true` 时,以下**原本只靠音效提示的危险**额外添加视觉提示: | 危险来源 | 音效原始提示 | 视觉替代 | |---------|-----------|---------| | Boss 范围攻击 | 低沉震鸣 | 地面发光红色警示线(1.5s 预警)| | 背后敌人接近 | 脚步声 | 屏幕边缘红色闪光条(来源方向)| | 蚀素区域边界 | 氛围嗡鸣 | 屏幕边缘蚀紫色渐变提示 | | 液体危险区 | 液体流动声 | 液体表面持续红色虚线框 | --- ## 8. 无障碍设置 UI ### 8.1 入口位置 无障碍设置有 **两个入口**: 1. **主菜单** → 设置 → 无障碍(独立标签页) 2. **暂停菜单** → 无障碍快捷入口(显示当前最关键的 3 项状态) ### 8.2 设置面板结构 ``` 无障碍设置面板 ├── 视觉 │ ├── 色盲模式(下拉:无/红色盲/绿色盲/蓝黄色盲/全色盲) │ ├── 高对比度模式(开关) │ └── 游戏对比度增强(滑块:0% ~ 100%) │ ├── 运动 │ ├── 关闭屏幕震动(开关)☆ │ ├── 镜头运动强度(滑块:0% ~ 100%)☆ │ ├── 减少粒子特效(开关) │ └── 关闭频闪效果(开关)☆ │ ├── 字幕 │ ├── 显示字幕(开关) │ ├── 环境音效字幕(开关) │ ├── 字体大小(滑块:75% ~ 200%) │ ├── 字幕背景(开关) │ └── 显示说话者名称(开关) │ ├── 输入辅助 │ ├── 弹反辅助(开关)☆ │ ├── 弹反窗口扩展(滑块:+0 ~ +0.2s,在弹反辅助开启时可用) │ ├── 长按替代连按(开关) │ └── 自动攀墙(开关) │ └── 音频 ├── 单声道模式(开关) ├── 左右声道平衡(滑块:左 ~ 右) └── 视觉危险提示(开关) ``` ☆ = 最常用选项,在暂停菜单快捷入口显示 ### 8.3 预设方案 提供 3 个一键应用的预设(不覆盖用户的自定义设置,作为起点建议): | 预设名 | 开启选项 | |-------|---------| | **运动友好** | 关闭屏幕震动 + 镜头运动强度 0% + 关闭频闪 | | **视觉辅助** | 高对比度 + 对比度增强 60% + 字幕字体 150% | | **操作辅助** | 弹反窗口 +0.1s + 长按替代连按 + 自动攀墙 | --- ## 9. SaveData 集成 无障碍设置存储于 **独立存档槽**(不随主存档数据,全局保存): ```json { "accessibility": { "colorBlindMode": "None", "highContrastMode": false, "gameContrastBoost": 0.0, "disableScreenShake": false, "disableCameraMotion": false, "cameraMotionScale": 1.0, "reduceParticleEffects": false, "disableFlashingEffects": false, "flashFrequencyLimit": 3, "subtitlesEnabled": false, "sfxSubtitlesEnabled": false, "subtitleFontSizeMultiplier": 1.0, "subtitleBackgroundEnabled": true, "subtitleBackgroundOpacity": 0.7, "speakerNameEnabled": true, "autoParryAssist": false, "parryWindowExtension": 0.0, "holdToMash": false, "stickyJump": false, "autoClimb": false, "monoAudio": false, "leftRightBalance": 0.0, "visualDangerIndicator": false } } ``` **文件路径**:`{persistentDataPath}/Settings/accessibility.json`(与游戏存档分离) **加载时机**:游戏启动时最优先加载,在主菜单显示前完成应用。 --- ## 10. 平台无障碍合规 ### 10.1 各平台基础要求 | 平台 | 要求 | 本文档覆盖 | |------|------|---------| | **Steam** | 无强制要求,但 Steam Deck 推荐色盲模式 | ✅ 色盲滤镜 | | **Nintendo Switch** | 无强制 accessibility 要求 | — | | **PlayStation** | TRC T178 系列:要求字幕 + 屏幕震动开关 | ✅ 字幕 + ✅ 震动开关 | | **Xbox** | ACS 认证:推荐支持 20+ 无障碍功能 | 部分覆盖 | ### 10.2 国际标准参考 本系统参考 **WCAG 2.1 Level AA** 和 **Game Accessibility Guidelines (gameaccessibilityguidelines.com)** 的以下条目: - Visual: 1.1(颜色不作唯一区分方式)、1.2(高对比文字)、1.4(调整大小) - Motor: 2.1(可配置按键映射)、2.2(可调整时间要求) - Deaf/Hard of Hearing: 3.1(字幕)、3.2(视觉警报) - Cognitive: 4.1(避免信息超载)