UGC1.0 编辑器与元件:模式、契约和复杂对象
这篇覆盖 UGC1.0 编辑器侧的高频追问。主线不是罗列功能,而是说明:编辑状态由谁拥有,元件怎样形成完整契约,复杂对象如何进入统一编辑框架,以及旧架构为什么越来越难维护。
面试官:你在 UGC1.0 编辑器里具体做了什么?
30 秒回答
我直接做过基础编辑交互、简易/专家模式、元件管理与属性刷新、AI 参考图、四足生物自定义,以及多类元件的线上维护。工作不只是接 UI,我需要处理输入、选择、Gizmo、碰撞、相机、对象数据、撤销刷新和试玩切换之间的一致性。
我对这段经历最大的总结是:编辑器不能由多个页面各自维护状态,元件也不是一个 Actor 或一张蓝图。前者需要统一操作状态机,后者需要从注册、Schema、编辑、保存到运行时形成一条完整契约。
90 秒回答
我做过两类编辑器问题。第一类是通用编辑状态,例如简易和专家模式切换、元件栏与管理器互斥、跟随式操作栏、飞行/行走、对象碰撞和 Gizmo。难点是这些功能会同时改 UI、输入和世界状态,如果各自存布尔值,切模式、进试玩或异常退出后就会泄漏。我最后形成的设计认识是:业务模型只保留一份,模式只做能力裁剪;当前操作由统一状态机管理,每个状态对输入订阅、临时碰撞和 UI 资源负责,并保证退出幂等。
第二类是复杂元件。比如四足生物不是普通静态模型,它包含骨骼挂点、部件外观、局部变换、碰撞、动画和运行时实例;AI 参考图则是一个异步资产任务,包含提示词、审核、生成历史、候选图、断线恢复和引用。它们都必须接入稳定对象身份、属性 Schema、保存、撤销和发布链路,不能做成页面里的特例。
面试官:基础编辑器架构怎么设计?
一句话结论
基础编辑器应把输入、操作状态、对象选择、事务和 UI 投影拆开;UI 发意图,领域层改状态,世界与页面订阅结果。
flowchart LR
A["输入路由<br/>触摸 / 键鼠 / 手柄"]
B["操作状态机<br/>选择 / 移动 / 旋转 / 缩放"]
C["选择集与稳定对象身份"]
D["编辑命令 / 事务"]
E["内容模型"]
F["Gizmo / 碰撞 / 相机"]
G["属性面板 / 元件栏"]
A --> B
B --> C
C --> D
D --> E
E --> F
E --> G各层职责
| 模块 | 负责什么 | 不应该负责什么 |
|---|---|---|
| 输入路由 | 设备事件、焦点、手势优先级 | 直接修改对象数据 |
| 操作状态机 | 当前操作、进入/退出、临时资源 | 保存多个互相冲突的模式布尔值 |
| 选择集 | 稳定对象身份、多选、失效剔除 | 持有易悬空的临时 UI 引用 |
| 编辑命令 | Before/After、合并、撤销重做 | 直接驱动页面布局 |
| 内容模型 | 对象、属性、引用和版本 | 保存 Gizmo 高亮等瞬时表现 |
| UI 投影 | 展示当前状态并发送用户意图 | 成为业务状态权威 |
面试官:简易模式和专家模式怎么共存?
直接回答
不是做两套编辑器,而是在同一内容模型和命令系统上提供两套能力视图。
统一内容模型
├─ 专家模式:完整 Gizmo、批量操作、高级属性
└─ 简易模式:跟随式操作栏、有限属性、受控相机与移动模式切换至少要原子处理四类状态:
- 结束当前拖拽或属性编辑,不能留下半个事务。
- 退出当前操作状态,归还输入、碰撞和相机控制权。
- 按新模式重新计算可见面板与可用命令。
- 用模型状态重建 UI,不能沿用旧页面的临时勾选值。
真实线上问题包括元件栏和元件管理器同时显示、切模式后网格配置串状态、简单操作时碰撞没有临时关闭、飞行或 NPC 动作导致移动能力没有恢复。这些表面上是不同 Bug,根因相同:多个模块分别持有同一状态,而且退出清理不完整。
面试官:操作状态机为什么有必要?
移动、选择、绑定、预设修改和拍照都会订阅输入并创建临时状态。如果只靠页面开关,它们可能同时响应一次触摸。
Idle
├─ Select
├─ Transform.Move
├─ Transform.Rotate
├─ Transform.Scale
├─ Attach
├─ PresetEdit
└─ Capture每个状态必须有三项约束:
Enter只申请自己需要的输入、UI、碰撞和相机资源。Exit可重复调用,并清理委托、临时对象和预览值。- 异常事件如对象删除、切层、切后台、进入试玩,统一强制退回安全态。
拖拽过程中每帧可以更新预览,但只在结束时提交一个命令。否则撤销栈会被每帧 Transform 淹没。
面试官:选择、Gizmo、相机和碰撞怎样协同?
选择先得到稳定对象身份,再由选择集决定 Gizmo 目标;Gizmo 只产生变换意图,内容模型负责父子空间换算和合法性校验。拖拽期间可以临时改变碰撞,结束、取消或异常退出时必须恢复。
四个容易忽略的点是:
- 射线要区分可选中表面、装饰碰撞和 Gizmo 自身碰撞。
- 父子对象变换要明确使用世界空间还是局部空间。
- 负缩放、极端尺度和嵌套编组会影响朝向、包围盒和点击区域。
- 移动端相机手势和对象拖拽需要明确竞争规则,不能两者同时消费。
面试官:元件管理器怎么设计?
直接回答
元件管理器不是 Actor 列表,而是内容对象的索引和操作入口。它依赖稳定实例 ID,通过注册表获得类型、分类、图标、能力和限制,再把搜索、筛选、显隐、锁定、删除、占用值等操作转换成领域命令。
Component Registry
typeId -> metadata / schema / factory / limits
|
Scene Object Index ----+----> search / category / filter
|
Editor Commands -------+----> visibility / collision / lock / delete管理器的刷新不能靠“重新打开页面”。对象创建、删除、复制、撤销、编组、属性变化都应发布领域事件,由管理器增量更新。批量操作还要处理混合值:多选对象属性不一致时显示 Mixed,不能偷偷取第一个对象的值。
面试官:什么才算一个完整元件?
一句话结论
元件是一条贯穿创作和运行的版本化契约,而不是一段封装逻辑。
| 契约部分 | 要回答的问题 |
|---|---|
| 注册信息 | 类型 ID 是否稳定,属于什么分类,谁能创建 |
| 属性 Schema | 类型、默认值、范围、枚举和旧版本缺省值是什么 |
| 编辑能力 | 如何选中、变换、配置、复制、删除和撤销 |
| 保存格式 | 哪些是作者数据,引用如何编码,如何迁移 |
| 运行时实现 | 何时实例化,属性变化是否即时生效 |
| 网络策略 | 哪些状态复制,谁是权威,事件如何校验 |
| 资源依赖 | 模型、图片、动画如何收集、审核和加载 |
| 成本模型 | 数量、Tick、渲染、物理和网络预算是多少 |
新增一个属性时,我会追问四件事:旧地图没有字段怎么办;编辑修改通知谁;试玩是否热更新;它是否需要保存或复制。缺一项就可能出现“面板值正确但表现没刷新”“复制后值一样但效果不同”或“旧图加载异常”。
面试官:玩法基础元件怎样控制扩展成本?
预封装元件的价值是门槛低、可审核、性能和网络边界可控;代价是每增加一种玩法能力,都可能新增类型、属性和连接规则。
控制扩展成本要避免“一需求一个巨型元件”,而是拆成三层:
对象能力:Transform / Render / Collision / Interaction
领域能力:Spawner / Trigger / Counter / Dialogue / NPC
逻辑组合:Signal / Event / Condition / Action / Coding简单用户使用完整预设,高级用户组合能力或 Coding。高频稳定能力下沉为原生实现;变化快但风险可控的逻辑留给脚本。这样既不把所有逻辑写死在元件里,也不把所有风险直接暴露给脚本。
面试官:AI 参考图的完整链路是什么?
30 秒回答
AI 参考图不是“输入一句话返回图片”。客户端负责提示词规范化、任务提交、候选结果、历史上限、选择悬浮图、设为参考、断线和失败反馈,并接入敏感内容、信用限制、水印与埋点。生成模型和服务端审核不属于我的职责。
flowchart LR
A["输入 / 预置提示词"] --> B["本地格式校验"]
B --> C["安全与资格校验"]
C --> D["创建任务 requestId"]
D --> E["生成多张候选"]
E --> F["历史记录与水印"]
F --> G["设为参考图"]
G --> H["编辑器悬浮窗 / 开始搭建"]我实际处理过多张候选、历史记录淘汰、提示词字符规范、服务协议更新、断线后一直 Loading、极差网络下点击无反馈和合规水印。设计上应把 Idle/Submitting/Generating/Succeeded/Failed/Cancelled 做成显式状态,requestId 使用足够宽的稳定类型,页面重建后可以恢复任务,而不是靠一个 Loading 布尔值。
面试官:四足生物为什么比普通元件难?
30 秒回答
四足生物同时跨了内容对象、骨骼装配、动画、物理和编辑交互。用户编辑的是头部、身体等外观与局部 Transform,最终要转换成稳定的骨骼挂接数据;编辑态还要解决射线选取、Gizmo 遮挡、碰撞和相机尺度,运行态则负责按保存数据重建模型并遵守动画约束。
Animal Definition
├─ skeleton / animation profile
├─ part slots -> asset reference
├─ local transform overrides
├─ collision profile
└─ editor metadata不能把编辑时的临时 Actor 引用直接保存。保存的是槽位、资源身份、骨骼挂点和局部变换;加载时再创建运行实例。部件替换要保持稳定槽位身份,Transform 修改必须区分根对象和部件局部空间。
面试官:剧情 NPC 你怎么讲?
这部分不能说成我独立负责完整剧情系统。可靠口径是:我做过 NPC、外观编辑及相关编辑器适配,也处理过剧情对话上传图片等上下游问题;完整剧情数据、分支推进、Sequence、跳过和存档恢复,是我基于项目源码补齐的系统认识。
完整设计应把剧情权威状态与客户端表现分开:
Dialogue Graph / Conditions / Progress
|
authoritative state
|
Client presentation: UI / camera / animation / sequence / skip客户端可以预加载和播放表现,但会影响任务、奖励和公共进度的分支必须由权威侧确认。跳过也不是直接关 UI,而是推进到明确的同步点。
面试官:可视化 Coding 和元件是什么关系?
元件提供受控对象与能力,Coding 负责编排。积木至少要携带类型、输入输出、对象引用、版本和生成规则;生成结果不能直接依赖页面内部结构,而应调用稳定的创作 API。
Blockly workspace
-> block schema + typed connections
-> serialized graph
-> generated Lua / intermediate form
-> sandboxed runtime APIs
-> server validation for authoritative effects我的直接工作包括 Coding Web 工程、模板/IDE/积木工厂兼容和客户端接入;我不会把整个 Lua 运行时和全部积木体系说成个人实现。继续追问时,应分别讲编辑态生成、API 版本、沙箱、异常日志和网络权威,而不是只说“Blockly 生成 Lua”。
面试官:创作大厅到端内循环怎么拆?
它是一条跨系统会话链,不是几个页面跳转:
地图列表 / 创作者页
-> 选择地图与版本
-> 创建或加入会话
-> 下载内容与依赖
-> 进入编辑 / 游玩
-> 发布、保存或退出
-> 返回原列表位置并刷新状态关键状态包括地图 ID、版本、用户身份、编辑/游玩模式、会话 ID、下载进度和返回上下文。客户端要保证重复点击幂等,失败后能退出 Loading,返回后恢复列表和页签,不让 Web 页面、原生大厅和游戏 World 各自猜测当前状态。
面试官:旧架构最难维护的问题是什么?
STAR 背诵版
S: 简易编辑是在已有专家编辑器上逐步增加的,页面、输入、碰撞和角色移动各自保存了一部分状态。线上陆续出现元件栏与管理器同时显示、切模式后配置串状态、拖动时碰撞不对、退出 NPC 编辑后飞行能力没有恢复等问题。
T: 我的目标不是逐个补 UI 判断,而是识别共同根因,保证任意模式切换、试玩和异常退出后都能回到一致状态。
A: 我沿状态变化梳理 UI、操作模式、角色能力、碰撞和对象选择的拥有者;修复具体问题时,把刷新接到模型事件,把临时碰撞和移动能力的修改成对恢复,并减少页面之间直接控制。进一步的正确方向是统一操作状态机、资源令牌和模式切换事务。
R: 相关模式、碰撞、元件管理和四足编辑问题得到持续收敛。由于没有完整线上缺陷率统计,我不声称具体下降比例。更重要的反思是:后加的“简易模式”不应成为第二套编辑器,应从一开始就是同一模型上的能力裁剪。
面试官:如果重做这一块,你会怎么改?
- 用稳定对象 ID 和统一 Schema 连接页面、编辑对象、保存数据与运行时。
- 用状态机和资源令牌管理输入、相机、碰撞、角色能力与弹窗焦点。
- 所有修改进入统一命令/事务层,连续预览只提交一个最终命令。
- 元件由注册表声明能力、成本和版本迁移,页面根据 Schema 投影。
- AI 任务、下载和发布都使用可恢复状态机,并记录输入 revision。
- 用契约测试覆盖 Schema 与迁移,用真实引擎自动化覆盖模式切换、试玩返回和复杂对象编辑。
追问边界
| 可以直接说 | 应限定后再说 | 当前不能说 |
|---|---|---|
| 负责简易/专家模式、元件管理、AI 参考图和四足编辑相关工作 | 参与 Coding 接入,沿源码补齐完整运行时认识 | 独立设计全部 UGC1.0 编辑器 |
| 处理过输入、碰撞、Gizmo、刷新与试玩泄漏问题 | 做过 NPC/剧情上下游适配 | 独立负责完整剧情系统 |
| 3D UI 元件做过 Tick/可见性方向的性能治理 | 元件模式的整体利弊是项目复盘结论 | 在没有基准数据时给出性能收益百分比 |
一分钟收口
我在 UGC1.0 编辑器侧真正积累的不是某几个页面,而是编辑状态一致性和内容契约意识。简易/专家模式让我看到输入、UI、碰撞和角色能力必须由统一状态机管理;元件和四足生物让我看到一个创作对象必须贯穿注册、Schema、编辑、保存、运行时和版本迁移;AI 参考图让我补齐异步任务、安全与失败恢复。旧系统的问题不是功能不够多,而是状态所有权和扩展契约不够统一,这也是我后来理解 UGC2.0 对象模型与服务边界的基础。