29 KiB
09 · 编辑器扩展
命名空间
BaseGames.Editor
所属文档集 ← 返回索引 · 总览
程序集BaseGames.Editor.asmdef(Editor-only,不打包进 Runtime)
目录
- 设计原则
- 自定义 Inspector 列表
- EditorWindow 工具列表
- Scene 视图 Gizmos 汇总
- Play Mode 调试叠加层
- ContextMenu 工具
- 编辑器菜单结构
- 自动化检查工具
- 高级工具集(补充)
1. 设计原则
- 编辑器扩展与运行时代码完全分离:所有编辑器扩展代码置于
Editor/文件夹,使用独立.asmdef - 工具服务于制作流程:每个工具针对具体的制作痛点,不做泛用性过度设计
- 视觉化优先:Gizmos 和自定义 Inspector 的目标是"看一眼就知道配置是否正确"
- 不破坏运行时行为:所有 Inspector 修改通过
SerializedObject.ApplyModifiedProperties()标准流程,支持撤销(Undo) - UI 技术选型:所有编辑器扩展统一使用 Unity UI Toolkit(UIElements),不使用 IMGUI(
OnGUI/EditorGUILayout)
UI Toolkit 统一规范
自定义 Inspector — 使用 CreateInspectorGUI() + BindProperty():
[CustomEditor(typeof(PlayerController))]
public class PlayerControllerEditor : Editor
{
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
// 默认字段绑定(替代 DrawDefaultInspector)
InspectorElement.FillDefaultInspector(root, serializedObject, this);
// 自定义运行时状态区
var statusFoldout = new Foldout { text = "运行时状态(Play Mode)" };
var stateLabel = new Label();
stateLabel.schedule.Execute(() =>
{
if (!EditorApplication.isPlaying) return;
var t = target as PlayerController;
stateLabel.text = $"State: {t.CurrentStateName} HP: {t.HP}/{t.MaxHP}";
}).Every(100); // 100ms 轮询
statusFoldout.Add(stateLabel);
// 调试按钮(Play Mode only)
var debugGroup = new VisualElement();
debugGroup.SetEnabled(false);
EditorApplication.playModeStateChanged += state =>
debugGroup.SetEnabled(state == PlayModeStateChange.EnteredPlayMode);
var hurtBtn = new Button(() => (target as PlayerController)?.TakeDamage(2)) { text = "Hurt 2" };
debugGroup.Add(hurtBtn);
root.Add(statusFoldout);
root.Add(debugGroup);
return root;
}
}
EditorWindow — 使用 CreateGUI() + 内置控件:
public class MyTool : EditorWindow
{
[MenuItem("BaseGames/My Tool")]
public static void Open() => GetWindow<MyTool>("My Tool");
public void CreateGUI()
{
var splitView = new TwoPaneSplitView(0, 260f, TwoPaneSplitViewOrientation.Horizontal);
var left = new ScrollView();
var right = new VisualElement();
splitView.Add(left);
splitView.Add(right);
rootVisualElement.Add(splitView);
}
}
§2–§9 各工具使用的关键 UI Toolkit 控件:
| 工具 | 关键控件 | 说明 |
|---|---|---|
| §2.x 自定义 Inspector | ProgressBar、Foldout、Button、Label |
CreateInspectorGUI() 替代 OnInspectorGUI() |
| §2.3 ParrySystem(时间轴) | 自绘 VisualElement(generateVisualContent + Painter2D) |
替代 GUI.Box 手绘条 |
| §3.1–3.4 简单 EditorWindow | ListView、Button、TextField |
CreateGUI() 替代 OnGUI() |
| §9.1 BT 验证器 | TreeView |
原生树形控件 |
| §9.2 进程流程图 | GraphView(UnityEditor.Experimental.GraphView) |
节点图;见注意事项 |
| §9.3 GameState 分析器 | MultiColumnListView |
矩阵视图 |
| §9.4 伤害模拟器 | TwoPaneSplitView + 自绘直方图(Painter2D) |
参数面板 + 分布图 |
| §9.7 装备预览 | TwoPaneSplitView + DropdownField |
响应式分栏 |
| §9.8 构建验证器 | MultiColumnListView + 可点击 Label |
多列结果 + 跳转 |
GraphView 注意:
UnityEditor.Experimental.GraphView标注为 Experimental,API 可能在 Unity 版本间变动。如遇稳定性问题,9.2 进程流程图可改为VisualElement手绘节点(generateVisualContent+Painter2D.DrawBezierCurve),无需依赖 Experimental API。
USS 样式文件存放:Assets/Editor/UI/USS/ — 统一样式变量(颜色、间距、字体大小),通过 styleSheets.Add() 挂载。
2. 自定义 Inspector 列表
2.1 PlayerController Inspector
目标:Play Mode 下直观监控玩家状态,快速触发测试。
布局规划:
┌─ PlayerController ─────────────────────────────────┐
│ ◈ 状态信息 │
│ ┌──────────────────────────────────────────────┐ │
│ │ Current State RunState │ │
│ │ HP ████████████░░ 8 / 10 │ │
│ │ Soul ███████░░░░░░░ 66 / 99 │ │
│ │ Geo 340 │ │
│ │ IsGrounded ✓ FacingDir → (+1) │ │
│ │ Invincible ░░░░░░░░░░ (0.00s remaining) │ │
│ └──────────────────────────────────────────────┘ │
│ ◈ 已解锁能力 │
│ ┌──────────────────────────────────────────────┐ │
│ │ [✓ Parry] [✓ DoubleJump] [✗ WallJump] │ │
│ │ [✗ AerialDash] [✗ Swim] │ │
│ └──────────────────────────────────────────────┘ │
│ ◈ 调试工具(Play Mode Only) │
│ [Force Idle] [Force Run] [Force Air] │
│ [Deal Damage: 2] [Deal Damage: 10] [Instant Kill] │
│ [Add Soul: 33] [Add Geo: 100] │
│ [Unlock All Abilities] [Lock All Abilities] │
└────────────────────────────────────────────────────┘
实现方式:继承 Editor,重写 CreateInspectorGUI() 返回 VisualElement 树。进度条使用 UI Toolkit ProgressBar 控件;Play Mode 限定区域通过 debugGroup.SetEnabled(EditorApplication.isPlaying) + EditorApplication.playModeStateChanged 回调控制显隐。
2.2 EnemyBase Inspector
目标:快速查看敌人 AI 状态,测试战斗参数。
┌─ EnemyBase ──────────────────────────────────────┐
│ ◈ 运行时状态(Play Mode) │
│ State: Controlled HP: █████████░ 90/100 │
│ BD Node: BD_MoveToPlayer (Running) │
│ Nav Status: Moving → (12.5, -3.0) [0.8m left] │
│ ◈ 属性配置 │
│ Stats SO: [ES_GruntWarrior ▼] │
│ AnimCfg : [EA_GruntWarrior ▼] │
│ ◈ 调试工具(Play Mode Only) │
│ [Force Stagger] [Force Death] [Reset HP] │
│ [Disable BD] [Enable BD] [Reload BD Tree] │
└──────────────────────────────────────────────────┘
2.3 ParrySystem Inspector
目标:可视化弹反时间轴,测试弹反参数。
┌─ ParrySystem ────────────────────────────────────┐
│ ◈ 时间轴预览 │
│ [▌ Startup ▌▌▌▌▌▌▌ Active Window ▌▌ Endlag ▌] │
│ 0.05s 0.28s 0.10s │
│ ◈ 运行时状态(Play Mode) │
│ State: Active Timer: 0.19s / 0.28s │
│ Window: ████████████░░░ 68% │
│ CounterW: ────────────── (Inactive) │
│ ◈ 调试工具 │
│ [Trigger Parry Success] [Trigger Parry Fail] │
│ [Open Counter Window] [Reset] │
└──────────────────────────────────────────────────┘
时间轴预览 在 Edit Mode 下也可显示(根据 ParryConfigSO 参数计算比例),方便策划调整数值时直观预览窗口比例。
2.4 RoomCameraBounds Inspector
目标:防止镜头边界配置错误。
┌─ RoomCameraBounds ───────────────────────────────┐
│ ◈ 边界检查 │
│ Bounds Size: (32.0, 18.0) │
│ Camera View (4.22 OrthoSize): (29.9, 16.8) │
│ Status: ✓ 边界大于镜头视野 │
│ ─────────────────────────────────────────────── │
│ [Preview Camera View in Scene] │
│ [自动调整 PolygonCollider2D 至最小安全尺寸] │
└──────────────────────────────────────────────────┘
2.5 DamageSourceSO Inspector
目标:策划配置攻击参数时,即时预览伤害计算和属性。
┌─ DamageSourceSO ─────────────────────────────────┐
│ ◈ 伤害预览 │
│ BaseDamage × Multiplier = Final │
│ 5 × 1.0 = 5 │
│ ◈ 击退预览 │
│ KnockbackForce: 8.0 Direction: → │
│ HitStun: 0.30s │
│ ◈ 属性标记 │
│ [CanBeParried ✓] [Unblockable ✗] [IgnoreIFrame ✗]│
│ ◈ 伤害类型 │
│ Type: Normal (物理) │
│ HitFxType: Slash │
└──────────────────────────────────────────────────┘
3. EditorWindow 工具列表
3.1 房间连接验证工具
菜单路径:BaseGames > World > Room Connection Validator
功能:
┌─ Room Connection Validator ──────────────────────────────────────┐
│ 扫描所有 Room_*.unity 场景中的 RoomTransition 组件 │
│ │
│ 房间 出口ID 目标场景 │
│ ────────────────────────────────────────────────────────────── │
│ Room_Forest_01 Door_To_Forest_02 ✓ Room_Forest_02 存在 │
│ Room_Forest_02 Door_To_Cave_01 ✓ Room_Cave_01 存在 │
│ Room_Cave_01 Door_To_Boss ✗ Boss_Cave 不存在 ⚠ │
│ │
│ SpawnPoint 检查: │
│ Room_Forest_02 缺少 SpawnPoint "SP_From_Forest_01_Door" ⚠ │
│ │
│ [重新扫描] [选中有错误的场景] [导出验证报告.md] │
└──────────────────────────────────────────────────────────────────┘
3.2 SO 事件频道监视器
菜单路径:BaseGames > Core > Event Channel Monitor
功能:Play Mode 下实时监听所有 SO 事件频道的触发情况。
┌─ Event Channel Monitor ──────────────────────────────────────────┐
│ [▶ Play Mode Only] [清除日志] [暂停记录] │
│ │
│ 时间 事件频道 数据 │
│ ────────────────────────────────────────────────────────────── │
│ 0.012s OnPlayerHPChanged value: 8 │
│ 0.013s OnHitConfirmed DMG:5, Knockback:8.0 │
│ 1.245s OnParrySuccess DMG:5, Flags: CanBeParried │
│ 1.248s OnPlayerHPChanged value: 8 (no change) │
│ 2.001s OnRoomEntered Transform: Room_Forest_01 │
│ │
│ [筛选频道: ___________] [仅显示Player] [仅显示Combat] │
└──────────────────────────────────────────────────────────────────┘
3.3 NavSurface 快速烘焙工具
菜单路径:BaseGames > Navigation > Quick Bake All Rooms
一键遍历所有场景中的 NavSurface,按顺序烘焙 PathBerserker2d 导航网格并保存场景:
┌─ NavSurface Bake Tool ──────────────────────────────────────────┐
│ 扫描到 NavSurface 数量: 12 │
│ │
│ Room_Forest_01: ✓ 已烘焙 (2024-01-01 12:00) │
│ Room_Forest_02: ⚠ 需要重新烘焙(场景已修改) │
│ Room_Cave_01: ✓ 已烘焙 │
│ │
│ [烘焙全部] [仅烘焙已修改] [验证所有路径连通性] │
└─────────────────────────────────────────────────────────────────┘
3.4 SaveData 查看器
菜单路径:BaseGames > World > SaveData Viewer
┌─ SaveData Viewer ───────────────────────────────────────────────┐
│ Slot 0 | Slot 1 | Slot 2 │
│ ───────────────────────────────────────────────────────────── │
│ Player: HP 5/5 | Geo 340 | Soul 66/99 │
│ Scene: Room_Forest_01 @ SP_Forest_01_Entry │
│ Abilities: Parry✓ DoubleJump✓ WallJump✗ Dash✗ Swim✗ │
│ Discovered: 3 rooms | Cleared: 1 | Bosses Defeated: 0 │
│ ───────────────────────────────────────────────────────────── │
│ [JSON 原始视图] [编辑并保存] [删除此存档] │
└─────────────────────────────────────────────────────────────────┘
4. Scene 视图 Gizmos 汇总
| 组件 | Gizmo 形状 | 颜色 | 说明 |
|---|---|---|---|
HitBox |
BoxWire | 橙色(激活:实心50%透明) | 攻击判定区域 |
HurtBox |
BoxWire | 绿色(受击中:红色闪烁) | 受击区域 |
SpawnPoint |
旗帜Icon + 文字 | 绿色 | 玩家出生点标识 |
RoomTransition |
箭头 → 目标场景文字 | 蓝色 | 房间出口方向 |
RoomCameraBounds |
Polygon + 内层相机视野矩形 | 青色 | 镜头约束范围 |
EnemyBase 检测范围 |
圆圈 | 黄色 | 玩家检测半径 |
EnemyBase 攻击范围 |
圆圈 | 红色(实线) | 攻击触发范围 |
EnemyBase 巡逻路径 |
线段 + 端点 | 蓝色虚线 | 巡逻 A~B 路径 |
EnemyBase 寻路目标 |
箭头 | 绿色 | 当前导航目标 |
EnemyBase 视线检测 |
射线 | 青色(遮挡:红色) | Raycast 视线 |
NavLink |
弧形箭头 | 紫色 | 导航跳跃链接 |
HazardZone |
BoxWire | 红色(实心30%透明) | 危险区域范围 |
AbilityUnlock |
星形Icon | 金色 | 能力解锁物件标识 |
SavePoint |
旗帜Icon(已激活/未激活) | 蓝色/灰色 | 存档点状态 |
ParrySystem(窗口中) |
圆圈动画 | 黄色 | 弹反窗口激活指示 |
5. Play Mode 调试叠加层
DebugOverlayWindow:按 F1 键(仅 Development Build 和 Editor 中)显示调试叠加层。
叠加层布局
┌─────────────────────────────────────────────────────────────────┐
│ [F1 关闭] FPS: 144 │
│ │
│ Player State: RunState HP: 8/10 Soul: 66 Geo: 340 │
│ IsGrounded: ✓ Facing: → Invincible: ✗ │
│ │
│ Active Camera: VCam_Explore Blend: Complete │
│ Current Room: Room_Forest_01 │
│ │
│ Enemies in Scene: 2 Alive: 1 Dead: 1 │
│ │
│ ─────────── 快捷键 ─────────────────────────────────────── │
│ F2 切换无敌 F3 加满 Soul F4 下一检查点 F5 重新加载场景 │
│ F6 切换 Gizmos F7 切换碰撞体显示 F8 切换 AI 暂停 │
└─────────────────────────────────────────────────────────────────┘
6. ContextMenu 工具
通过 Inspector 右键菜单([ContextMenu])调用,无需进入 Play Mode:
| 组件 | 右键菜单项 | 说明 |
|---|---|---|
EnemyStatsSO |
Print Stats Summary |
Console 打印该敌人完整属性表 |
DamageSourceSO |
Calculate DPS |
Console 打印理论 DPS(BaseDamage / AttackCooldown) |
RoomCameraBounds |
Fit to Room Tilemap |
自动调整 PolygonCollider2D 以包裹 Tilemap 边界 |
NavSurface |
Bake NavMesh |
立即烘焙此 NavSurface |
SavePoint |
Mark As Activated |
设置 SavePoint 为已激活状态(用于测试继续游戏场景) |
RoomTransition |
Validate Target Scene |
检查目标场景是否存在于 BuildSettings |
7. 编辑器菜单结构
Unity 菜单栏 BaseGames/ 下的所有工具入口:
BaseGames/
├── Core/
│ └── Event Channel Monitor → EventChannelMonitorWindow
│
├── World/
│ ├── Room Connection Validator → RoomConnectionValidatorWindow
│ ├── SaveData Viewer → SaveDataViewerWindow
│ └── Rebuild All Spawn Points → 扫描并重新生成 SpawnPoint ID 索引
│
├── Navigation/
│ ├── Quick Bake All Rooms → NavSurfaceBakeTool
│ └── Validate Path Connectivity → 检查所有房间 NavLink 连通性
│
├── Combat/
│ └── DPS Calculator → 输入 DamageSourceSO + AttackCooldown,输出 DPS 表格
│
└── Settings/
├── Open Project Layer Matrix → 快速跳转到 ProjectSettings > Physics2D Layer Matrix
└── Validate Assembly Definitions → 检查 .asmdef 依赖关系是否符合零耦合原则
8. 自动化检查工具
场景验证检查(保存场景时自动运行)
SceneValidationProcessor(继承 AssetModificationProcessor),在保存场景时自动检查:
| 检查项 | 错误级别 | 说明 |
|---|---|---|
场景是否有 RoomCameraBounds |
Warning | 遗漏镜头约束 |
场景是否有 NavSurface |
Warning | 有敌人的场景必须有 NavSurface |
所有 RoomTransition 目标场景是否在 BuildSettings |
Error | 目标场景不存在 |
所有 HitBox 是否有对应 DamageSourceSO |
Error | 攻击参数未配置 |
所有 EnemyBase 是否有 EnemyStatsSO |
Error | 敌人属性未配置 |
检查结果在 Console 窗口输出,并在 Scene Validation 浮窗中汇总。
Assembly Definition 依赖校验
BaseGames > Settings > Validate Assembly Definitions 检查 .asmdef 是否遵循零耦合原则(如 BaseGames.Player 不应直接依赖 BaseGames.Enemies),输出依赖图 Mermaid 格式并在 Console 报警。
9. 高级工具集(补充)
9.1 Behavior Tree 验证器
Tools > Zeling > BT Validator(BaseGames.Editor.BehaviorTreeValidator):
扫描 Assets/ 下所有 Behavior Designer .asset 文件,检测:
| 检查项 | 级别 | 说明 |
|---|---|---|
| 孤立节点(无父节点且非根) | Warning | 表示悬空的设计草稿节点 |
| 缺失 TaskName 的 Action/Condition | Error | 会导致 BD 无法编译 |
| SharedVariable 引用为空 | Warning | 运行时会 NullRef |
| Action 节点最大深度 > 12 | Warning | 过深 BT 建议拆分子树 |
| 同一 Agent 上同时存在多个 BehaviorTree 组件 | Error | 会互相覆盖 |
输出到 Console,双击跳转到对应 BD 资产。
9.2 进程流程图(Progression Flow Graph)
Tools > Zeling > Progression Flow Graph(EditorWindow):
┌─ Progression Flow Graph ─────────────────────────────────────┐
│ [刷新] [导出为 PNG] [高亮未实现节点] │
│ │
│ ┌Forest──────┐ ─击败SpiderGuard→ ┌Cave───────────────┐ │
│ │SP_Forest_01│ │SP_Cave_01 │ │
│ │HP+2 Heart │ │WallJump Unlock │ │
│ └────────────┘ └───────────────────┘ │
│ │ │ │
│ └──────── 需要 Dash ─────────────────┘ │
└──────────────────────────────────────────────────────────────┘
- 自动读取所有
ProgressLock/AbilityGateSO 及BossProgressTracker配置 - 用 Bezier 曲线绘制依赖关系(红色=未解锁,绿色=已解锁)
- 右键节点 → "模拟解锁" → 在 Editor 中测试后续节点是否变绿
9.3 GameState 转换分析器
Tools > Zeling > GameState Analyzer(EditorWindow):
- 列出
GameManager中所有GameState枚举值 - 显示每个状态下:允许的输入 Action Map、哪些 SO 频道被监听
- 矩阵视图:行 = 事件频道,列 = 当前状态;标注"会触发"/"被忽略"
- 辅助排查"暂停状态下攻击事件仍被响应"等逻辑漏洞
9.4 伤害模拟器(Damage Simulator)
DamageSourceSO 右键菜单 → Simulate Damage,弹出快速面板:
┌─ Damage Simulator: DamageSource_PlayerAttack1 ──┐
│ 目标防御: 0 [ ] 格 受伤类型: Normal │
│ CharmBonus: × 1.5 + 12(剑尖魅力) │
│ 弱点: × 1.0 [✓] 骑士弱点(十字架) │
│ ───────────────────────────────────────────── │
│ 最终伤害: 14(基础 9 × 1.5 + 1 向上取整) │
│ [运行 1000 次随机伤害分布图] │
└─────────────────────────────────────────────────┘
不需要进入 Play Mode 即可快速验证伤害数值设计。
9.5 地图贴图验证器(Map Texture Validator)
Tools > Zeling > Map Texture Validator:
- 读取
MapRoomDataSO.roomOutlineTexture与对应场景的实际 Tilemap 边界 - 对比边界框是否对齐(允许 ± 1 tile 误差)
- 检测 Texture 是否以
Read/Write导入(SetPixels 需要) - 批量输出不匹配的房间列表 + 截图预览
9.6 音频导入预处理器(Audio Import Preprocessor)
BaseGames.Editor.AudioImportPreprocessor(继承 AssetPostprocessor):
规则表(AudioImportRulesSO,可在 Inspector 配置):
| 文件名前缀 | 平台 | 采样率 | 压缩格式 | Load Type |
|---|---|---|---|---|
BGM_ |
All | 44100 | Vorbis(q=0.4) | Streaming |
SFX_ |
All | 22050 | ADPCM | CompressedInMemory |
AMB_ |
All | 22050 | Vorbis(q=0.3) | Streaming |
Voice_ |
All | 22050 | Vorbis(q=0.6) | CompressedInMemory |
导入音频时自动按文件名前缀应用对应设置,Console 输出 [AudioPreprocessor] Applied: SFX rule → SFX_Player_Hurt.wav。
9.7 装备预览工具(Equip Preview)
Tools > Zeling > Equip Preview(EditorWindow):
┌─ Equip Preview ──────────────────────────────────────────────┐
│ 选择魅力组合(最多 4 个槽位): │
│ 槽1: [剑之力量魅力 ▼] 槽2: [灵魂强化魅力 ▼] │
│ 槽3: [无 ] 槽4: [无 ] │
│ ───────────────────────────────────────────────────────── │
│ 最终属性: │
│ 攻击力: 9 × 1.5 = 13 法术消耗: 33 × 0.67 = 22 │
│ 弹反 Soul: 10 → 10 法术弹数: 3 → 3 │
│ 路径成本: 4 个通知(EquipmentManager.Apply × 4) │
│ [复制配置 JSON] [应用到 Player(Play Mode)] │
└──────────────────────────────────────────────────────────────┘
9.8 构建验证器(Build Validator)
Tools > Zeling > Validate Build,在正式打包前执行完整检测:
| 检测项 | 级别 |
|---|---|
| 所有场景已加入 Build Settings | Error |
所有 AudioImportRulesSO 规则已应用 |
Warning |
所有 AnimationEventConfigSO 无超出范围的事件时间 |
Error |
所有 AbilityGate 引用的能力 ID 存在于 AbilityType 枚举 |
Error |
所有 LocalizationKeys 常量在 zh-CN StringTable 中有对应条目 |
Warning |
Player Prefab 已注册为 Addressable(address = "Player",不使用 Resources/) |
Error |
| 所有 Addressable Group 无缺失引用(Missing Reference) | Error |
SaveData JSON Schema 与当前字段一致(版本检查) |
Warning |
| 构建目标平台 Build Target 与发布目标匹配 | Warning |
输出结果为 Build Validation Report(Text + 每项跳转链接),只有零 Error 才允许继续打包。