Files
zeling_v2/Docs/Standards/LayerSpec.md
Joywayer fcd3e2dcdd PlayerMovementConfigSO.cs
新增 WallHangSpeed = 1f:正常抓墙(低于等于 wallGrabY,可蹬墙跳区间)的缓慢下滑速度
WallSlideSpeed 语义调整为:受限模式(高于 wallGrabY)的较快下滑速度
PlayerMovement.cs

ApplyWallSlide() 改为 ApplyWallSlide(float speed),由调用方传入对应速度
WallSlideState.cs

OnStateFixedUpdate:正常模式用 WallHangSpeed,受限模式用 WallSlideSpeed(两档清晰分离)
恢复反方向键脱离:脱离时同样调用 StartWallCoyote,wall coyote 窗口内仍能触发蹬墙跳
更新类头注释完整描述脱离方式和下滑速度档位Two wall slide improvements:
2026-05-21 15:58:46 +08:00

12 KiB
Raw Permalink Blame History

Unity Layer 命名与用途规范

版本1.0
创建日期2026-05
适用范围:项目所有 GameObject 的 Layer 分配
关联文档Standards/AssetFolderSpec.mdEditor/Tools/Physics2DLayerReport.cs


目录

  1. 概述
  2. Layer 清单
  3. Physics 2D 碰撞矩阵
  4. 使用规范
  5. 检查与修复工具

1. 概述

本项目使用固定的 Layer 名称集合来驱动 Physics 2D 碰撞矩阵、伤害判定、视线检测LOS、地面检测等核心系统。所有 Layer 必须在 Edit → Project Settings → Tags and Layers 中手动创建,名称必须与本文档一致(大小写敏感)。

重要:代码中通过 LayerMask.NameToLayer("LayerName") 引用 Layer若 Layer 不存在将返回 -1 并导致逻辑错误。创建场景对象时请优先使用 BaseGames → Scene → Place 菜单工具,该工具会自动校验并赋值 Layer。


2. Layer 清单

2.1 玩家相关

Layer 名称 挂载对象 用途说明
Player 玩家根节点 GameObject 玩家物理碰撞体(含 Rigidbody2D地面检测、存档点、检查点触发器通过此 Layer 筛选玩家
PlayerHurtBox 玩家子节点 HurtBox 接收伤害的碰撞体isTriggerEnemyHitBox / EnemyProjectile 命中此 Layer 时对玩家造成伤害
PlayerHitBox 玩家武器 / 技能 HitBox 发出伤害的碰撞体;命中 EnemyHurtBox 时触发对敌人的伤害判定
PlayerProjectile 玩家发射的投射物 玩家子弹;不与 PlayerHurtBoxEnemyProjectile 碰撞,命中 EnemyHurtBoxPlatform 时有效

2.2 敌人相关

Layer 名称 挂载对象 用途说明
Enemy 敌人根节点 GameObject 敌人物理碰撞体(含 Rigidbody2DPlatform 碰撞实现站立
EnemyHurtBox 敌人子节点 HurtBox 接收伤害的碰撞体isTriggerPlayerHitBox / PlayerProjectile 命中此 Layer 时对敌人造成伤害;EnemyHitBox 也可命中此 Layer敌人互伤HitBox 运行时排除自身根节点)
EnemyHitBox 敌人武器 HitBox / LethalTrap 主体 发出伤害的碰撞体;命中 PlayerHurtBox 时触发对玩家的伤害判定
EnemyProjectile 敌人发射的投射物 敌人子弹;不与 EnemyHurtBox 碰撞,命中 PlayerHurtBoxPlatform 时有效

2.3 地形相关

Layer 名称 挂载对象 用途说明
Platform 静态地面、移动平台、Tilemap 地形、障碍物 玩家与敌人站立的实体平台;PlayerMovement_groundLayerPlayerWallDetector_wallLayer(默认)均包含此 Layer投射物命中后销毁
OneWayPlatform 单向平台(静态) 玩家可从下方穿过、从上方站立的平台;挂载 PhantomPlatePlatformEffector2D + IDropThrough_groundLayer 必须包含此 Layer 才能检测 OnOneWayPlatform 状态
MovingOneWayPlatform 单向平台(移动) 会移动的单向平台;行为同 OneWayPlatform独立层便于移动脚本、AI 路径查询按层筛选
MidHeightOneWayPlatform 单向平台(半高) 半腰高度的单向平台;角色可从侧方穿越;行为同 OneWayPlatform
Wall 墙壁碰撞体(垂直面) 玩家攀墙检测(PlayerWallDetector 默认掩码包含 WallPlatform);若地形使用统一的 Tilemap 则墙壁可合并到 Platform Layer

2.4 触发区域

Layer 名称 挂载对象 用途说明
TriggerZone 存档点(CheckpointMarker)、存档台(SavePoint)、传送站(TeleportStation)、房间过渡(RoomTransition / DoorTransition)、相机区域(CameraArea 纯触发碰撞体isTrigger不参与物理阻挡统一使用此 Layer 方便在碰撞矩阵中集中管理

2.5 环境危险

Layer 名称 挂载对象 用途说明
HazardHitBox 对双方均造成伤害的环境危险落石、熔岩、毒区、AOE 爆炸范围等) 同时与 PlayerHurtBoxEnemyHurtBox 碰撞;区别于 EnemyHitBox(只对玩家),此 Layer 用于阵营中立的环境伤害源

2.6 特殊用途

Layer 名称 挂载对象 用途说明
PhantomBody 幽灵/幻象角色的实体碰撞体 PhantomInteractable 通过 other.gameObject.layer == PhantomBody 判断是否为幻象角色触发交互

3. Physics 2D 碰撞矩阵

以下为项目期望的碰撞配置,由 Physics2DLayerReport 工具维护与校验。

Layer A Layer B 应碰撞 说明
PlayerHitBox EnemyHurtBox 玩家攻击伤害敌人
EnemyHitBox PlayerHurtBox 敌人攻击伤害玩家
EnemyHitBox EnemyHurtBox 敌人可互相伤害HitBox 运行时排除自身根节点)
Player Platform 玩家站在实体平台上
Player OneWayPlatform 玩家站在单向平台上PlatformEffector2D 控制单向穿透)
Player MovingOneWayPlatform 玩家站在移动单向平台上
Player MidHeightOneWayPlatform 玩家站在半高单向平台上
Enemy Platform 敌人站在实体平台上
Enemy OneWayPlatform 敌人站在单向平台上
Enemy MovingOneWayPlatform 敌人站在移动单向平台上
Enemy MidHeightOneWayPlatform 敌人站在半高单向平台上
PlayerProjectile EnemyHurtBox 玩家投射物伤害敌人
PlayerProjectile PlayerHurtBox 玩家投射物不自伤
PlayerProjectile Platform 玩家投射物命中地形
EnemyProjectile PlayerHurtBox 敌人投射物伤害玩家
EnemyProjectile EnemyHurtBox 敌人投射物不自伤
EnemyProjectile Platform 敌人投射物命中地形
PlayerHitBox PlayerHurtBox 玩家不自伤
PlayerProjectile EnemyProjectile 子弹不互相碰撞Clash 系统单独处理)
HazardHitBox PlayerHurtBox 环境危险伤害玩家
HazardHitBox EnemyHurtBox 环境危险伤害敌人(中立伤害)
HazardHitBox PlayerHitBox 环境不触发拼刀
HazardHitBox EnemyHitBox 环境不触发拼刀

未在上表中列出的 Layer 对默认继承 Unity 全局设置(默认全部碰撞)。


4. 使用规范

4.1 Layer 赋值方式

  • 优先使用 SceneObjectPlacerTool(菜单 BaseGames → Scene → Place → …)自动赋值,避免遗漏。
  • 手动创建 GameObject 时,在 Inspector 顶部 Layer 下拉菜单中选择对应 Layer。
  • 代码中引用时,通过 LayerMask.NameToLayer("LayerName") 获取整型索引,或通过 LayerMask.GetMask("LayerA", "LayerB") 获取掩码值。
// 推荐:缓存到字段,避免每帧调用
private int _playerLayer;

void Awake()
{
    _playerLayer = LayerMask.NameToLayer("Player");
}

4.2 子节点继承规则

  • 玩家 / 敌人根节点与其 HurtBox、HitBox 必须分别挂不同 Layer,不可统一使用根节点 Layer。
  • LethalTrap(陷阱):主体用 EnemyHitBox,可弹起的子 HurtBoxEnemyHurtBox
  • 触发区域对象(存档点等)统一用 TriggerZone,不需要额外子节点分层。

4.3 禁止事项

  • 禁止在代码中硬编码 Layer 整型编号(如 layer == 8),必须使用名称转换。
  • 禁止直接修改 ProjectSettings/TagManager.asset 中的 Layer 顺序(会导致所有已赋值对象 Layer 错乱)。
  • 禁止将 TriggerZone 对象的 Collider 设置为非 triggerisTrigger 必须为 true)。

6. 复杂场景处理模式

6.1 弹反投射物EnemyProjectile → 伤害敌人)

问题EnemyProjectile ↔ EnemyHurtBox = 不碰撞,弹反后的投射物无法对敌人造成伤害。

正确方案:运行时 Layer 切换(不新增 Layer

弹反成功时,将投射物的 Layer 从 EnemyProjectile 切换为 PlayerProjectile,同时反转飞行方向。Projectile 已有 SetFactionLayer(int ownerLayer) 方法,弹反逻辑只需调用它:

// HurtBox.ReceiveDamage() 弹反成功后步骤2
if (_parrySystem.ConsumeParry())
{
    // 若攻击来源是投射物,翻转其阵营 Layer
    if (info.SourceProjectile != null)
    {
        info.SourceProjectile.ReflectAsPlayerProjectile();
        // ReflectAsPlayerProjectile() 内部:
        //   gameObject.layer = LayerMask.NameToLayer("PlayerProjectile");
        //   rb.velocity = -rb.velocity;  // 反向
    }
    return;
}

注意:当前 DamageInfo 尚未携带 SourceProjectile 字段,实现此功能需要:

  1. DamageInfo 中添加 Projectile SourceProjectile 字段
  2. HitBox.OnTriggerEnter2D 通过 _attackerTransform.GetComponent<Projectile>() 填入
  3. Projectile 实现 ReflectAsPlayerProjectile() 方法

为什么不新建 ParriedProjectile 层?
PlayerProjectile 的语义本就是"对敌人有效、对玩家无效"的攻击来源,弹反后的投射物完全符合此语义,无需新层。


6.2 环境伤害(同时对玩家与敌人有效)

LethalTrap(陷阱)当前使用 EnemyHitBox 层,只对玩家生效,是有意为之的设计(跑酷陷阱不伤敌人)。

对于确实需要同时伤害双方的环境机关落石、熔岩、AOE 区域等),使用 HazardHitBox 层并配合 HazardHitBoxTrigger 组件(待实现),收到碰撞时向 PlayerHurtBoxEnemyHurtBox 均发送伤害:

HazardHitBox ↔ PlayerHurtBox  → 碰撞
HazardHitBox ↔ EnemyHurtBox   → 碰撞

6.3 敌人之间互伤(友伤/AOE

EnemyHitBox ↔ EnemyHurtBox = 碰撞 已在碰撞矩阵中开启。
自伤防护由 HitBox.OnTriggerEnter2D 的根节点比较负责:

if (other.transform.root == _attackerTransform.root) return; // 排除自身

这意味着:

  • 同一 GameObject 树的 EnemyHitBox 不会命中自身的 EnemyHurtBox
  • 敌人 A 的 HitBox 可以命中敌人 B 的 HurtBox (天然支持友伤)
  • Boss 的 AOE 技能可以对场景中所有其他敌人造成伤害

6.4 不需要细分的场景

以下场景不需要新增 Layer,通过 DamageInfo 字段在逻辑层区分即可:

场景 处理方式
区分攻击来源(玩家技能 vs 玩家普攻) DamageInfo.SkillId / DamageInfo.SourceId
不同类型伤害(物理 vs 魔法) DamageInfo.TypeDamageType 枚举)
Boss 阶段专属伤害规则 DamageInfo.TagsDamageTags 标记位)
不可弹反的攻击 DamageInfo.Flags 不含 CanBeParried
穿透无敌帧的伤害 DamageInfo.FlagsIgnoreIFrame

项目提供了 Physics2DLayerReport 编辑器工具,位于菜单:

BaseGames → Tools → Physics2D Layer Matrix → Check
BaseGames → Tools → Physics2D Layer Matrix → Auto Fix
  • Check:打印当前碰撞矩阵与期望配置的对比报告。
    • 正常
    • 当前配置与期望不符(需修复)
    • ⚠ Layer 不存在(需先在 Tags and Layers 中创建)
  • Auto Fix:自动将所有不符合期望的碰撞对修正为正确值,并持久化到 ProjectSettings

建议在以下时机运行 Check:新人入职初始化环境、合并来自其他分支的 ProjectSettings 变更后、新增 Layer 之后。