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,512 @@
# 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.00 = 完全关闭)
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<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 的对比度:
```csharp
void ApplyContrastBoost(float boost)
{
var ca = globalVolume.profile.TryGet<ColorAdjustments>(out var adj);
adj.contrast.value = Mathf.Lerp(0f, 50f, boost); // 0 ~ 50PostProcess 单位)
}
```
---
## 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因为游戏无配音这实质上是强制开启的此选项更多用于控制**字幕样式**
字幕面板配置:
```
SubtitlePanelCanvas
├── BackgroundImageRectTransform 根据文字内容自动扩展)
│ opacity: subtitleBackgroundOpacity0.7 默认)
│ color: #000000
└── SubtitleTextTextMeshPro
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<float>() > 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(避免信息超载)