Files
zeling_v2/Docs/Design/57_PhysicsLayerMatrix.md
2026-05-08 11:04:00 +08:00

245 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 57 · 物理层矩阵Physics Layer Matrix
> **命名空间** `BaseGames.Physics`(配置层)
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
> **关联** 04_CombatSystemHitBox/HurtBox· 06_EnemySystem · 13_ProjectileSystem · 24_GroundDetectionSystem · 40_LiquidSwimSystem
---
## 目录
1. [Layer 定义总表](#1-layer-定义总表)
2. [碰撞矩阵Layer Collision Matrix](#2-碰撞矩阵layer-collision-matrix)
3. [Physics Material 目录](#3-physics-material-目录)
4. [Rigidbody2D 使用规范](#4-rigidbody2d-使用规范)
5. [Trigger vs Collider 使用规范](#5-trigger-vs-collider-使用规范)
6. [Layer 相关代码规范](#6-layer-相关代码规范)
7. [常见错误与排查](#7-常见错误与排查)
---
## 1. Layer 定义总表
Unity 物理层Layer 0~31固定分配不允许随意挪用
| Layer ID | 名称 | 用途 |
|---------|------|------|
| 0 | `Default` | 场景中无特殊需求的静态物件(不参与物理计算的装饰物)|
| 1 | `TransparentFX` | Unity 内置,粒子特效(不参与碰撞)|
| 2 | `Ignore Raycast` | Unity 内置,不参与任何 Raycast |
| 3 | `(保留)` | — |
| 4 | `Water` | Unity 内置(本项目不使用,用 LiquidZone 代替)|
| 5 | `UI` | Unity 内置UI 层 |
| 6 | `(保留)` | — |
| 7 | `(保留)` | — |
| **8** | `Ground` | 地面、平台(玩家/敌人站立的实体碰撞)|
| **9** | `OneWayPlatform` | 单向平台(可从下方穿越,从上方落下后站立)|
| **10** | `Wall` | 垂直墙壁(可抓附的墙体)|
| **11** | `Hazard` | 伤害区域(荆棘/熔岩地面/毒液,无碰撞体阻挡,仅触发 Trigger|
| **12** | `Player` | 玩家 Prefab 主体 Collider |
| **13** | `PlayerHitBox` | 玩家攻击判定区HitBox|
| **14** | `PlayerHurtBox` | 玩家受击区HurtBox|
| **15** | `Enemy` | 敌人主体 Collider |
| **16** | `EnemyHitBox` | 敌人攻击判定区HitBox|
| **17** | `EnemyHurtBox` | 敌人受击区HurtBox|
| **18** | `Projectile` | 弹射物玩家射出的子弹、Boss 弹幕)|
| **19** | `EnemyProjectile` | 敌人弹射物(与 Projectile 分层,防止玩家弹射物误伤自己)|
| **20** | `ParryTarget` | 可弹反的弹射物HurtBox 对 Parry 检测,见 05_ParrySystem|
| **21** | `Interactable` | 可交互物件触发区IInteractable Trigger|
| **22** | `LiquidZone` | 液态区域Trigger见 40_LiquidSwimSystem|
| **23** | `AbilityGate` | 能力门触发区Trigger见 14_ProgressionSystem|
| **24** | `Pickup` | 掉落物/收集品Trigger靠近自动吸附|
| **25** | `Room` | 房间边界触发区Trigger触发场景加载/卸载)|
| **26** | `CameraZone` | Cinemachine 约束区域Trigger不参与物理|
| **27** | `VFX` | VFX 粒子(仅视觉,不参与碰撞)|
| **28** | `NavMesh` | 寻路 AgentPathBerserker2d 专属,不与普通物理交互)|
| **29** | `MagicWall` | 魔法障壁(`Ghost` 层忽略此层,实现太虚斩/地行术穿越)|
| **30** | `Ghost` | 玩家施放太虚斩/地行术激活期间切换到此层;忽略 `MagicWall` 碰撞 |
| **31** | `PhantomBody` | 残阴术灵体 Rigidbody2D可触发 `PhantomInteractable`,忽略其余实体碰撞 |
---
## 2. 碰撞矩阵Layer Collision Matrix
**✅ = 相互检测碰撞 / Trigger 触发** | **─ = 忽略(不检测)**
> 仅列出有意义的组合,其余均为 `─`。
| | Ground | OWPlatform | Wall | Hazard | Player | PlayerHB | PlayerHurtB | Enemy | EnemyHB | EnemyHurtB | Projectile | EnemyProj | ParryTarget | Interactable | LiquidZone | Pickup | Room |
|--|--------|-----------|------|--------|--------|---------|------------|-------|---------|-----------|-----------|----------|------------|-------------|-----------|--------|------|
| **Ground** | ─ | ─ | ─ | ─ | ✅ | ─ | ─ | ✅ | ─ | ─ | ✅ | ✅ | ─ | ─ | ─ | ─ | ─ |
| **OWPlatform** | ─ | ─ | ─ | ─ | ✅ | ─ | ─ | ✅ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **Wall** | ─ | ─ | ─ | ─ | ✅ | ─ | ─ | ✅ | ─ | ─ | ✅ | ✅ | ─ | ─ | ─ | ─ | ─ |
| **Hazard** | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **Player** | ✅ | ✅ | ✅ | ✅(T) | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ✅(T) | ─ | ✅(T) | ✅(T) | ✅(T) | ✅(T) |
| **PlayerHitBox** | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **PlayerHurtBox** | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ✅(T) | ✅(T) | ─ | ─ | ─ | ─ |
| **Enemy** | ✅ | ✅ | ✅ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **EnemyHitBox** | ─ | ─ | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **EnemyHurtBox** | ─ | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ |
| **Projectile** | ✅ | ─ | ✅ | ─ | ─ | ─ | ✅(T) | ─ | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **EnemyProjectile** | ✅ | ─ | ✅ | ─ | ✅(T) | ─ | ✅(T) | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
| **ParryTarget** | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ | ─ |
> (T) = 仅 Trigger 检测OnTriggerEnter2D / OnTriggerStay2D不产生物理推力
### 新增层补充矩阵Ghost / MagicWall / PhantomBody
| | Ground | OWPlatform | Wall | MagicWall | Player | Enemy | Interactable | PhantomInteractable |
|--|--------|-----------|------|-----------|--------|-------|-------------|--------------------|
| **Ghost** | ✅ | ✅ | ✅ | ❌ 忽略 | ─ | ─ | ✅(T) | ✅(T) |
| **MagicWall** | ─ | ─ | ─ | ─ | ✅ | ✅ | ─ | ─ |
| **PhantomBody** | ❌ 忽略 | ❌ 忽略 | ❌ 忽略 | ❌ 忽略 | ─ | ─ | ─ | ✅(T) |
> - **Ghost**:玩家变换为幽灵层后,与 `MagicWall` 无碰撞(穿越),但仍与地面/墙壁碰撞(地行术需要站在地面上遁行)。
> - **PhantomBody**:残阴术灵体完全忽略地面/墙壁,仅 Trigger 触发 `PhantomInteractable``Interactable` 子层)。
> - `SoftTerrain`(松软地面)**不需要独立物理层**:使用 `Ground` 层,`GroundDiveState` 通过 `Physics2D.OverlapPoint()` 的返回值检查是否挂载 `SoftTerrain` 组件来判断地形类型。
### 矩阵关键设计决策
| 决策 | 原因 |
|------|------|
| `Enemy` 不与 `EnemyProjectile` 碰撞 | 防止 Boss 弹幕打到自己身上 |
| `Projectile` 不与 `Enemy` 碰撞(走 EnemyHurtBox| 弹射物不推动敌人刚体,只通过 HurtBox 触发伤害 |
| `PlayerHitBox` 不与 `Ground/Wall` 碰撞 | 防止近地攻击被地面碰撞遮挡 |
| `Hazard` 只触发 `Player`,不触发 `Enemy` | 敌人在自己的陷阱中不受伤 |
| `ParryTarget` 不与任何层碰撞 | 弹反检测由 `ParrySystem``OverlapCircle` 主动查询,无需被动碰撞 |
---
## 3. Physics Material 目录
存放路径:`Assets/Physics/Materials/`
| 资产名 | Friction | Bounciness | 使用对象 |
|--------|---------|-----------|---------|
| `PhysMat_Ground` | 0.4 | 0.0 | 地面碰撞体(普通地板)|
| `PhysMat_Ice` | 0.02 | 0.0 | 冰面地块(低摩擦)|
| `PhysMat_Bounce` | 0.2 | 0.8 | 弹跳蘑菇/弹射台 |
| `PhysMat_Player` | 0.0 | 0.0 | 玩家 Rigidbody2D Collider零摩擦防止卡墙|
| `PhysMat_Enemy` | 0.3 | 0.0 | 敌人 Rigidbody2D Collider |
| `PhysMat_Projectile` | 0.0 | 0.0 | 弹射物(与地面/墙壁碰撞时不反弹,由代码控制反弹逻辑)|
| `PhysMat_Liquid` | 0.0 | 0.0 | 液态区域边界(仅 Trigger但 PhysMat 仍设为零摩擦)|
### 摩擦力处理原则
- **玩家碰撞体摩擦力始终为 0**——移动完全由 `PlayerMovement` 的速度控制,不依赖物理摩擦
- 坡面行走不依赖摩擦力,而是使用地面法线修正移动方向(见 24_GroundDetectionSystem.md
- 弹跳效果不依赖 `Bounciness` 物理材质,而是在 `OnCollisionEnter2D` 中代码施加冲量(更可控)
---
## 4. Rigidbody2D 使用规范
| 对象类型 | Body Type | Interpolation | Collision Detection | Constraints |
|---------|-----------|--------------|--------------------|----|
| **玩家** | Dynamic | Interpolate | Continuous | FreezeRotation Z |
| **跟随平台(可移动地块)**| Kinematic | Interpolate | Continuous | — |
| **普通敌人(地面)** | Dynamic | Interpolate | Discrete | FreezeRotation Z |
| **飞行敌人** | Dynamic | Interpolate | Discrete | FreezeRotation Z |
| **弹射物** | Dynamic | None | Continuous | FreezeRotation Z |
| **可破坏物件** | Dynamic激活前 Kinematic| None | Discrete | — |
| **触发区域Hazard/LiquidZone 等)** | 无 Rigidbody2D | — | — | — |
**禁止行为**
- ❌ 不在 `Update()` 中直接修改 `transform.position`(会绕过物理,用 `Rigidbody2D.MovePosition`
- ❌ 不设置 `Rigidbody2D.velocity` 直接赋值(除非做瞬间冲刺,否则用 `AddForce`
- ❌ 不在运行时频繁切换 Body Type`Dynamic ↔ Kinematic` 切换有性能开销)
---
## 5. Trigger vs Collider 使用规范
| 用途 | 使用 Collider | 使用 Trigger |
|------|-------------|------------|
| 角色站立在地面上 | ✅ Collider | ❌ |
| HitBox / HurtBox 伤害检测 | ❌ | ✅ Trigger |
| 危险区域(荆棘)伤害 | ❌ | ✅ Trigger |
| 液态区域检测 | ❌ | ✅ Trigger |
| 交互提示范围InteractionPrompt| ❌ | ✅ Trigger |
| 房间边界(加载/卸载触发)| ❌ | ✅ Trigger |
| 镜头约束区域Cinemachine ConfinerBound| ✅ Collider设为 Trigger| 二者并存(见 Cinemachine 文档)|
| 弹射物与墙面碰撞(需反弹计算)| ✅ Collider | ❌ |
| 弹射物与 HurtBox | ❌ | ✅ Trigger |
**混合使用**(同一 Collider2D 同时作为 Collider 和 Trigger
-**禁止**——同一 Collider 不能同时是 Collider 和 Trigger语义混乱
- 需要两种功能时,在同一 GameObject 上添加两个 Collider2D 组件
---
## 6. Layer 相关代码规范
### 6.1 使用 LayerMask 常量,禁止硬编码数字
```csharp
// ✅ 正确
private static readonly int LayerGround = LayerMask.NameToLayer("Ground");
private static readonly LayerMask MaskGround = LayerMask.GetMask("Ground", "OneWayPlatform");
// ❌ 禁止
int layer = 8; // 硬编码 Layer ID
```
### 6.2 统一 LayerMask 常量类
```csharp
// Assets/Scripts/Core/Physics/Layers.cs
public static class Layers
{
public static readonly int Ground = LayerMask.NameToLayer("Ground");
public static readonly int OneWayPlatform = LayerMask.NameToLayer("OneWayPlatform");
public static readonly int Wall = LayerMask.NameToLayer("Wall");
public static readonly int Player = LayerMask.NameToLayer("Player");
public static readonly int PlayerHitBox = LayerMask.NameToLayer("PlayerHitBox");
public static readonly int PlayerHurtBox = LayerMask.NameToLayer("PlayerHurtBox");
public static readonly int Enemy = LayerMask.NameToLayer("Enemy");
public static readonly int EnemyHitBox = LayerMask.NameToLayer("EnemyHitBox");
public static readonly int EnemyHurtBox = LayerMask.NameToLayer("EnemyHurtBox");
public static readonly int Projectile = LayerMask.NameToLayer("Projectile");
public static readonly int EnemyProjectile = LayerMask.NameToLayer("EnemyProjectile");
public static readonly int Hazard = LayerMask.NameToLayer("Hazard");
public static readonly int LiquidZone = LayerMask.NameToLayer("LiquidZone");
public static readonly int Pickup = LayerMask.NameToLayer("Pickup");
public static readonly int Room = LayerMask.NameToLayer("Room");
// 技能专属层
public static readonly int Ghost = LayerMask.NameToLayer("Ghost"); // 太虚斩/地行术幽灵层
public static readonly int PhantomBody = LayerMask.NameToLayer("PhantomBody"); // 残阴术灵体层
public static readonly int MagicWall = LayerMask.NameToLayer("MagicWall"); // 魔法障壁Ghost 穿越)
// 复合 Mask常用组合
public static readonly LayerMask MaskSolidGround = LayerMask.GetMask("Ground", "OneWayPlatform");
public static readonly LayerMask MaskWallAndGround = LayerMask.GetMask("Ground", "OneWayPlatform", "Wall");
public static readonly LayerMask MaskAllHurtBox = LayerMask.GetMask("PlayerHurtBox", "EnemyHurtBox");
public static readonly LayerMask MaskEnemy = LayerMask.GetMask("Enemy", "EnemyHurtBox");
// Ghost 状态时的地面检测(排除 MagicWall但保留普通地面
public static readonly LayerMask MaskGhostGround = LayerMask.GetMask("Ground", "OneWayPlatform");
}
```
### 6.3 Layer 设置检查器CI 集成)
`Assets/Tests/EditMode/PhysicsLayerTests.cs` 中验证:
- 所有 Layer 名称正确注册
- Collision Matrix 中的关键对/忽略关系与本文档一致
- 玩家 Prefab 使用正确的 Layer
---
## 7. 常见错误与排查
| 症状 | 原因 | 修复 |
|------|------|------|
| 玩家无法站在地面上 | Player 与 Ground 的碰撞被关闭 | 检查 Collision Matrix |
| 攻击打不到敌人 | PlayerHitBox 与 EnemyHurtBox 碰撞关系未启用 | 勾选矩阵对应格 |
| 弹射物穿透地面 | Projectile 的 Collision Detection 设为 Discrete | 改为 Continuous |
| 危险区域不造成伤害 | Hazard 碰撞体忘记勾选 Is Trigger | 勾选 Is Trigger |
| 敌人被自己的弹幕打到 | Enemy 与 EnemyProjectile 未忽略 | 检查矩阵,确认忽略 |
| 近地面攻击被地面碰撞打断 | PlayerHitBox 与 Ground 未忽略 | 确认矩阵忽略该组合 |
| 单向平台两侧可以穿过 | OneWayPlatform 应用了标准碰撞 | 使用 `PlatformEffector2D` 组件 |
---
*本文档版本 1.0 · 2026-04 · 关联 04_CombatSystem / 13_ProjectileSystem / 24_GroundDetectionSystem*