14 KiB
14 KiB
57 · 物理层矩阵(Physics Layer Matrix)
命名空间
BaseGames.Physics(配置层)
所属文档集 ← 返回索引 · 总览
关联 04_CombatSystem(HitBox/HurtBox)· 06_EnemySystem · 13_ProjectileSystem · 24_GroundDetectionSystem · 40_LiquidSwimSystem
目录
- Layer 定义总表
- 碰撞矩阵(Layer Collision Matrix)
- Physics Material 目录
- Rigidbody2D 使用规范
- Trigger vs Collider 使用规范
- Layer 相关代码规范
- 常见错误与排查
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 |
寻路 Agent(PathBerserker2d 专属,不与普通物理交互) |
| 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 常量,禁止硬编码数字
// ✅ 正确
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 常量类
// 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