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、批量操作、高级属性
    └─ 简易模式:跟随式操作栏、有限属性、受控相机与移动

模式切换至少要原子处理四类状态:

  1. 结束当前拖拽或属性编辑,不能留下半个事务。
  2. 退出当前操作状态,归还输入、碰撞和相机控制权。
  3. 按新模式重新计算可见面板与可用命令。
  4. 用模型状态重建 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: 相关模式、碰撞、元件管理和四足编辑问题得到持续收敛。由于没有完整线上缺陷率统计,我不声称具体下降比例。更重要的反思是:后加的“简易模式”不应成为第二套编辑器,应从一开始就是同一模型上的能力裁剪。

面试官:如果重做这一块,你会怎么改?

  1. 用稳定对象 ID 和统一 Schema 连接页面、编辑对象、保存数据与运行时。
  2. 用状态机和资源令牌管理输入、相机、碰撞、角色能力与弹窗焦点。
  3. 所有修改进入统一命令/事务层,连续预览只提交一个最终命令。
  4. 元件由注册表声明能力、成本和版本迁移,页面根据 Schema 投影。
  5. AI 任务、下载和发布都使用可恢复状态机,并记录输入 revision。
  6. 用契约测试覆盖 Schema 与迁移,用真实引擎自动化覆盖模式切换、试玩返回和复杂对象编辑。

追问边界

可以直接说应限定后再说当前不能说
负责简易/专家模式、元件管理、AI 参考图和四足编辑相关工作参与 Coding 接入,沿源码补齐完整运行时认识独立设计全部 UGC1.0 编辑器
处理过输入、碰撞、Gizmo、刷新与试玩泄漏问题做过 NPC/剧情上下游适配独立负责完整剧情系统
3D UI 元件做过 Tick/可见性方向的性能治理元件模式的整体利弊是项目复盘结论在没有基准数据时给出性能收益百分比

一分钟收口

我在 UGC1.0 编辑器侧真正积累的不是某几个页面,而是编辑状态一致性和内容契约意识。简易/专家模式让我看到输入、UI、碰撞和角色能力必须由统一状态机管理;元件和四足生物让我看到一个创作对象必须贯穿注册、Schema、编辑、保存、运行时和版本迁移;AI 参考图让我补齐异步任务、安全与失败恢复。旧系统的问题不是功能不够多,而是状态所有权和扩展契约不够统一,这也是我后来理解 UGC2.0 对象模型与服务边界的基础。