18 KiB
62 · 无障碍功能系统(Accessibility System)
命名空间
BaseGames.Accessibility
所属文档集 ← 返回索引 · 总览
依赖BaseGames.UI·BaseGames.Input·BaseGames.Audio·BaseGames.Core.Events
关联 10_UISystem · 25_InputRebindingUI · 12_AudioSystem · 29_DifficultyModesGuide
重要声明 无障碍功能 ≠ 简单模式。无障碍选项服务于有不同能力需求的玩家,不改变游戏的挑战定义,与难度系统独立运作。
目录
- 无障碍设计哲学
- AccessibilitySettingsSO — 数据容器
- 视觉无障碍
- 运动敏感度设置
- 字幕与文字无障碍
- 输入辅助系统
- 音频无障碍
- 无障碍设置 UI
- SaveData 集成
- 平台无障碍合规
1. 无障碍设计哲学
1.1 核心立场
| 立场 | 说明 |
|---|---|
| 尊重需求多样性 | 色盲、运动障碍、听觉障碍玩家有同等权利享受完整游戏体验 |
| 非侵入性设计 | 无障碍选项默认关闭,不影响未开启的玩家的游戏体验 |
| 与难度系统分离 | 无障碍设置不出现在难度菜单中,避免"弱者选项"的负面暗示 |
| 独立专属入口 | 主菜单和暂停菜单均有独立的"无障碍"按钮(不与"设置"合并) |
1.2 支持目标用户群
| 用户需求 | 覆盖方案 |
|---|---|
| 色盲(红绿色盲/蓝黄色盲) | 色盲滤镜 + 可选高对比模式 |
| 畏光/光敏感癫痫 | 屏幕震动关闭 + 闪光效果弱化 + 闪光频率上限 |
| 运动晕眩 | 镜头晃动关闭 + 视野减少模式 |
| 上肢/手部运动障碍 | 连按→长按、自动弹反辅助、输入重绑定(见 25_InputRebindingUI) |
| 弱视 | 大字体模式、UI 高对比模式、游戏画面对比度增强 |
| 听觉障碍 | 全字幕(SFX 提示字幕)、视觉危险提示 |
2. AccessibilitySettingsSO — 数据容器
[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 实现,在最终合成阶段应用色彩矩阵变换:
// Assets/Scripts/Accessibility/ColorBlindFilter.cs
public class ColorBlindFilter : ScriptableRendererFeature
{
[SerializeField] ColorBlindMode _mode;
// 色彩矩阵(3×3,基于 Brettel et al. 1997 算法)
private static readonly Dictionary<ColorBlindMode, Matrix4x4> _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 的对比度:
void ApplyContrastBoost(float boost)
{
var ca = globalVolume.profile.TryGet<ColorAdjustments>(out var adj);
adj.contrast.value = Mathf.Lerp(0f, 50f, boost); // 0 ~ 50(PostProcess 单位)
}
4. 运动敏感度设置
4.1 屏幕震动控制
disableScreenShake 控制 Feel MMF CinemachineImpulse 和所有 ScreenShake 反馈:
// 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 时:
// VFXPool.SpawnParticle() 入口处检查
int particleCount = AccessibilityManager.Instance.Settings.reduceParticleEffects
? Mathf.CeilToInt(requestedCount * 0.5f) // 减少 50%
: requestedCount;
影响范围:攻击命中粒子、环境粒子、Dead 消散粒子。不影响:弹反特效(功能性视觉反馈)、危险区域边界粒子。
4.4 闪光频率保护
光敏感癫痫保护:AccessibilityValidator 在任何闪烁效果触发前检查频率限制:
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)。
[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 键 |
| 快速填充灵力 | — | — |
| (暂无其他连按操作) | — | — |
// InputAssistService.cs
public bool CheckMashInput(InputAction action, int requiredPresses)
{
if (!Settings.holdToMash)
return _mashCounter[action] >= requiredPresses; // 正常连按计数
// Hold to Mash:长按 0.5s 等效完成所有连按
return action.ReadValue<float>() > 0.5f &&
Time.unscaledTime - _holdStartTime[action] >= 0.5f;
}
6.3 粘性跳跃(Sticky Jump)
stickyJump = true 时,松开跳跃键后额外 0.1s 内仍然可以触发 CutJump(可变跳跃高度缩减):
// 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 效果:
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 输出增益:
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 入口位置
无障碍设置有 两个入口:
- 主菜单 → 设置 → 无障碍(独立标签页)
- 暂停菜单 → 无障碍快捷入口(显示当前最关键的 3 项状态)
8.2 设置面板结构
无障碍设置面板
├── 视觉
│ ├── 色盲模式(下拉:无/红色盲/绿色盲/蓝黄色盲/全色盲)
│ ├── 高对比度模式(开关)
│ └── 游戏对比度增强(滑块:0% ~ 100%)
│
├── 运动
│ ├── 关闭屏幕震动(开关)☆
│ ├── 镜头运动强度(滑块:0% ~ 100%)☆
│ ├── 减少粒子特效(开关)
│ └── 关闭频闪效果(开关)☆
│
├── 字幕
│ ├── 显示字幕(开关)
│ ├── 环境音效字幕(开关)
│ ├── 字体大小(滑块:75% ~ 200%)
│ ├── 字幕背景(开关)
│ └── 显示说话者名称(开关)
│
├── 输入辅助
│ ├── 弹反辅助(开关)☆
│ ├── 弹反窗口扩展(滑块:+0 ~ +0.2s,在弹反辅助开启时可用)
│ ├── 长按替代连按(开关)
│ └── 自动攀墙(开关)
│
└── 音频
├── 单声道模式(开关)
├── 左右声道平衡(滑块:左 ~ 右)
└── 视觉危险提示(开关)
☆ = 最常用选项,在暂停菜单快捷入口显示
8.3 预设方案
提供 3 个一键应用的预设(不覆盖用户的自定义设置,作为起点建议):
| 预设名 | 开启选项 |
|---|---|
| 运动友好 | 关闭屏幕震动 + 镜头运动强度 0% + 关闭频闪 |
| 视觉辅助 | 高对比度 + 对比度增强 60% + 字幕字体 150% |
| 操作辅助 | 弹反窗口 +0.1s + 长按替代连按 + 自动攀墙 |
9. SaveData 集成
无障碍设置存储于 独立存档槽(不随主存档数据,全局保存):
{
"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(避免信息超载)