From 82d5212dfd75cbda806313150228d45968154b45 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Mon, 20 Jul 2026 15:46:52 +0800 Subject: [PATCH] =?UTF-8?q?@=20docs(scaffold):=20=E6=95=8C=E4=BA=BA?= =?UTF-8?q?=E7=A2=B0=E6=92=9E=E4=BD=93=20Sprite=20=E9=A9=B1=E5=8A=A8=20+?= =?UTF-8?q?=20=E7=BB=9F=E4=B8=80=20Box=20+=20=E5=85=A8=E5=91=98=E6=8E=A5?= =?UTF-8?q?=E8=A7=A6=E4=BC=A4=E5=AE=B3=E5=8C=BA=20=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 脚手架生成的敌人(含 Boss):主体/HurtBox/ContactDamageZone 三者统一 BoxCollider2D、 同尺寸、底部对齐 y=0;尺寸由向导默认 Sprite 的包围盒推导(留空回退硬编码);每个 敌人都有 ContactDamageZone。只改脚手架+向导,不动现有 prefab。 Co-Authored-By: Claude Opus 4.8 (1M context) @ --- ...nemy-sprite-driven-box-colliders-design.md | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 Docs/superpowers/specs/2026-07-10-enemy-sprite-driven-box-colliders-design.md diff --git a/Docs/superpowers/specs/2026-07-10-enemy-sprite-driven-box-colliders-design.md b/Docs/superpowers/specs/2026-07-10-enemy-sprite-driven-box-colliders-design.md new file mode 100644 index 00000000..bf9358ac --- /dev/null +++ b/Docs/superpowers/specs/2026-07-10-enemy-sprite-driven-box-colliders-design.md @@ -0,0 +1,116 @@ +# 敌人碰撞体:Sprite 驱动 + 统一 Box + 全员接触伤害区 —— 设计文档 + +- 日期:2026-07-10 +- 范围:**只改脚手架 `SceneObjectPlacerTool` 与向导 `CharacterWizardWindow`**;不动现有 prefab(用户后续手动重生成替换)。 + +## 目标 + +脚手架生成的每个敌人(含 Boss)满足: +1. **主体碰撞体、HurtBox、ContactDamageZone 三者统一为 `BoxCollider2D`**,尺寸完全一致、**底部对齐 y=0**(敌人原点在碰撞体底部,参考 E001;供 PathBerserker2d NavAgent 检测原点落在导航线上)。 +2. 三者尺寸由**向导指定的默认 Sprite 的包围盒**(`sprite.bounds.size`)推导;Sprite 留空则回退到各敌人现有的硬编码尺寸(不破坏无 sprite 的旧行为)。 +3. **每个敌人 + Boss 都有 ContactDamageZone**(接触伤害区);不需要接触伤害的敌人由策划把该节点置为非激活。 + +## 背景(现状) + +- `SceneObjectPlacerTool` 的 `CreateBodyCollider(go, type, size)` 已支持 Box/Capsule/Circle + `AlignColliderBottomToPivot`(底部对齐)。主体默认 Box。 +- HurtBox 各敌人现为 `CapsuleCollider2D`(E001 已是 Box);ContactDamageZone 参差:E001=Box、E003/E006=Circle、**E002/E004/E005/ChaoFeng 缺失**。 +- 尺寸为每敌人硬编码(如 E001 body 0.6×0.8,E002 0.5×0.7…)。 +- `EnsureCollidersAreTriggers(go)` 助手已存在(把节点全部 Collider2D 设 trigger)。 +- `CharacterWizardWindow` 小怪/ Boss Tab 已有"主体碰撞器类型"EnumField,调 `PlaceSpecificEnemy(id, colliderType)` / `PlaceChaoFeng`。 + +## 设计 + +### A. 向导:默认 Sprite 字段(可选) + +- 小怪 Tab、Boss Tab 各加一个 `UnityEditor.UIElements.ObjectField`(`objectType = typeof(Sprite)`),标签"默认外观 Sprite(碰撞体尺寸依据,可留空)",绑定 `Sprite _enemyDefaultSprite`(Boss 用同一字段或独立 `_bossDefaultSprite`,实现上用一个 `_defaultSprite` 即可,按当前 Tab 复用)。 +- 放置按钮把选中 Sprite 传入:`PlaceSpecificEnemy(id, colliderType, _defaultSprite)`、`PlaceChaoFeng(colliderType, _defaultSprite)`。 + +### B. 脚手架:Sprite 驱动 + 统一 Box + 全员接触伤害区 + +**新增两个助手:** + +```csharp +// Sprite 有则用其世界包围盒尺寸,否则回退。 +private static Vector2 SpriteSizeOr(Sprite s, Vector2 fallback) + => s != null ? (Vector2)s.bounds.size : fallback; + +// 建 HurtBox + ContactDamageZone 两个子节点,均为 Box、同尺寸、底部对齐、isTrigger。 +// contactEnabled:BodyContactDamage 初始启用状态(不需要接触伤害的敌人可置 false 或后续置节点非激活)。 +// 返回创建的 (hurtBox, bodyContact, contactHitBox) 供上层按需接线。 +private static (HurtBox hurt, BodyContactDamage contact, HitBox contactHitBox) + SetupHurtAndContactBoxes(GameObject root, Vector2 size, bool contactEnabled, List report) +{ + // HurtBox 子节点 + var hurtT = GetOrCreateChild(root.transform, "HurtBox"); + SetLayer(hurtT.gameObject, "EnemyHurtBox", report); + var hurtBox2D = GetOrAddComponent(hurtT.gameObject); + hurtBox2D.size = size; hurtBox2D.isTrigger = true; + AlignColliderBottomToPivot(hurtBox2D); + var hurtBox = GetOrAddComponent(hurtT.gameObject); + EnsureCollidersAreTriggers(hurtT.gameObject); + + // ContactDamageZone 子节点 + var contactT = GetOrCreateChild(root.transform, "ContactDamageZone"); + SetLayer(contactT.gameObject, "EnemyHitBox", report); + var contactBox = GetOrAddComponent(contactT.gameObject); + contactBox.size = size; contactBox.isTrigger = true; + AlignColliderBottomToPivot(contactBox); + var contactHitBox = GetOrAddComponent(contactT.gameObject); + var bodyContact = GetOrAddComponent(contactT.gameObject); + bodyContact.enabled = contactEnabled; + EnsureCollidersAreTriggers(contactT.gameObject); + return (hurtBox, bodyContact, contactHitBox); +} +``` + +**每个 `PlaceExxx` 签名加可选 sprite;用它推导 size、赋给 SpriteRenderer、走统一助手:** + +```csharp +public static void PlaceE0xx(EnemyBodyColliderType bodyCollider = EnemyBodyColliderType.Box, + Sprite defaultSprite = null) +{ + ... + Vector2 size = SpriteSizeOr(defaultSprite, /*该敌人原硬编码 fallback*/); + var sr = SetupSpriteRenderer(visual.gameObject); + if (defaultSprite != null) sr.sprite = defaultSprite; // 视觉与碰撞体一致 + CreateBodyCollider(go, bodyCollider, size); // 主体 Box(size)、底部对齐 + var (hurtBox, bodyContact, contactHitBox) = + SetupHurtAndContactBoxes(go, size, contactEnabled: true, report); + // 该敌人特有接线(如 E001:contactEnabled=false + 把 bodyContact 绑给 ContactChaseAbility._contactDamage; + // contactHitBox 绑 CMB_DS_EnemyBody 伤害源)。 + ... +} +``` + +- **主体默认 Box**(`EnemyBodyColliderType.Box`);Capsule/Circle 选项保留但默认 Box。三者尺寸都 = `size`。 +- **接触伤害默认启用**(碰到即伤):`contactEnabled: true`;**E001 例外** `contactEnabled: false`(其 ContactChaseAbility 在冲刺期开启接触伤害),并把 `bodyContact` 绑到 `ContactChaseAbility._contactDamage`。 +- ContactDamageZone 的 HitBox 绑默认伤害源 `CMB_DS_EnemyBody`(沿用 E001 现有做法)。 +- Boss `PlaceChaoFeng` 同样通过助手补 ContactDamageZone(默认启用,策划按需置非激活)。 +- 全部走 `AlignColliderBottomToPivot`(底部对齐,中心在底部)。 + +### C. 不动现有 prefab + +现有 7 个 prefab 不由本次修改,用户用更新后的脚手架手动重生成替换。 + +## 影响文件 + +- `Assets/_Game/Scripts/Editor/Scene/SceneObjectPlacerTool.cs`:新增 `SpriteSizeOr` / `SetupHurtAndContactBoxes`;改 7 个 `PlaceExxx`(E001-E006) + `PlaceChaoFeng` 用统一助手 + sprite 参数;替换原 Capsule/Circle 的 HurtBox/ContactDamageZone 创建;给缺失的 4 个敌人补 ContactDamageZone。 +- `Assets/_Game/Scripts/Editor/Character/CharacterWizardWindow.cs`:加 `_defaultSprite` 字段 + ObjectField;放置调用传 sprite。 + +## 验证 + +- 编译 0 错误。 +- 反射/直接调用各 `PlaceExxx` 生成到临时场景对象,校验: + - 主体/HurtBox/ContactDamageZone 都是 `BoxCollider2D`。 + - HurtBox/ContactDamageZone `isTrigger=true`,主体 `isTrigger=false`。 + - 三者 `size` 一致(= sprite 包围盒 或 fallback)。 + - 三者底部对齐(`offset.y == size.y * 0.5`)。 + - 每个敌人 + Boss 均存在 ContactDamageZone(BodyContactDamage 组件在)。 + - E001:BodyContactDamage 初始 disabled 且已绑到 ContactChaseAbility。 +- 用一张测试 Sprite 走一次向导放置,确认碰撞体尺寸 = sprite 包围盒、SpriteRenderer 用了该 sprite。 + +## 非目标 + +- 不改现有 prefab(用户手动重生成)。 +- 不改敌人 AI / 移动 / 伤害逻辑。 +- 不引入 sprite 紧密网格/物理形状(用完整包围盒即可)。