预制体
预制体是一棵存好的实体树——你在编辑器里编辑一次、生成很多次的模板(敌人、拾取物、子弹)。
在运行时通过 Prefabs 资源实例化。预制体资源始终是单一权威来源;实例可以在其之上叠加
自己的值。
在编辑器里创作
Section titled “在编辑器里创作”你先在编辑器里可视化地搭出预制体,再从代码生成它。本节都发生在编辑器中;运行时 API 在下文。
在 World Outliner 里右键一个实体 → Create Prefab。编辑器会把该实体及其整棵子树抽取成
assets/prefabs/<Name>.esprefab(以实体名命名),并且不改动你的场景——原实体原样留在场景里,
不会被替换成实例。要放置实例,把 .esprefab 从内容浏览器拖进场景,或从 Create → Prefabs 分类生成。
编辑预制体——Prefab Mode
Section titled “编辑预制体——Prefab Mode”双击一个 .esprefab(或从实例上点 Edit Prefab)进入 Prefab Mode:预制体会作为它自己的可编辑
实体树,在同一个视口 / Outliner / Details 里打开,外框带暖色高亮,顶部是 Editing Prefab 横幅。
像编辑场景一样增删、改名、重设父级、调组件,然后 Save Prefab——每个场景里的每个实例都会拿到这次
改动。Back to Scene 把你带回原处。
Prefab Mode 暂不支持:就地编辑嵌套预制体,或基不是扁平的变体。编辑预制体时 Play 与 Save As 被禁用。

Prefab Mode:Editing Prefab 横幅带 Save Prefab / Back to scene,预制体作为它自己的实体树打开——保存后每个实例都会更新。
把实例放进场景,它会与源保持联动。改动实例上的某个字段,它就成为一条覆盖(override)——叠在预制体 之上的逐实例值。编辑器会标出覆盖,让你随时知道哪些是本地的:
- 实例的根名字在 Outliner 里被染成暖色;
- 被覆盖的字段会显示一个重置箭头(↺ Reset to default),其组件带一个琥珀色圆点;
- 检视器有一个筛选,可把 Details 面板收窄到只看被覆盖的字段。
用字段的 ↺ 按钮重置单个字段,值会回落到预制体的值。
Apply · Revert · Unpack · Variant
Section titled “Apply · Revert · Unpack · Variant”在 Outliner 里右键一个实例(或用检视器的 prefab 条)可执行这些身份操作:
| 操作 | 作用 |
|---|---|
| Edit Prefab | 在 Prefab Mode 里打开源。 |
| Select Prefab Source | 在内容浏览器里定位到该 .esprefab。 |
| Apply to Prefab | 把这个实例的覆盖推回源——更新每个实例的基。 |
| Revert to Prefab | 丢弃这个实例的覆盖,并重新同步到源。 |
| Create Variant | 存出一个新的 .esprefab,继承基并把这个实例的覆盖烘进去(预制体的预制体)。 |
| Unpack Prefab | 拆开子树——其实体变成普通场景实体,失去一切预制体关联。可撤销。 |
Apply 是唯一会改写共享资源的操作,所以它总会先预览一份逐条 diff(“Apply changes to prefab?”)—— 改动为琥珀、新增为绿、删除为红,结构性改动会被标为破坏性。
生成一个预制体
Section titled “生成一个预制体”instantiate 加载预制体并生成它。它是异步的,并返回生成的树——root 是新的根实体:
import { defineSystem, Res, Prefabs } from 'esengine';
const spawnEnemy = defineSystem([Res(Prefabs)], async (prefabs) => { const { root } = await prefabs.instantiate('prefabs/enemy.esprefab'); // `root` is the new entity — move it, tag it, give it a Transform position…});设置父级并访问子项
Section titled “设置父级并访问子项”把实例嵌套到另一个实体下,并用返回的 entities map 按预制体局部 id 访问子项:
const { root, entities } = await prefabs.instantiate('prefabs/turret.esprefab', { parent: mountPointEntity,});// root → the instance root// entities → Map<prefab-local id, spawned Entity>, for reaching children传 overrides 来仅为这个实例改值,而不编辑预制体资源——用不同血量或着色生成同一个敌人。
每条覆盖用字符串 prefabEntityId(编辑器创作的预制体里是 UUID)定位一个预制体实体,并指明
组件 + 属性:
const { root } = await prefabs.instantiate('prefabs/enemy.esprefab', { overrides: [ { prefabEntityId: '0', type: 'property', componentType: 'Health', propertyName: 'value', value: 250 }, ],});除了 'property',type 还可以是 'name'、'visibility'、'component_added'、
'component_replaced'、'component_removed'、'metadata_set' 或 'metadata_removed'
(metadata 两种用 metadataKey 代替 componentType/propertyName)。
instantiate 参考
Section titled “instantiate 参考”| 选项 | 类型 | 说明 |
|---|---|---|
parent |
Entity | 把实例嵌套到该实体下。 |
overrides |
override[] | 逐实例的组件值改动。 |
baseUrl |
string | 解析预制体资源的基 URL。 |
| 结果字段 | 说明 |
|---|---|
root |
实例的根 Entity。 |
entities |
Map<prefab-local id, Entity>,用于访问子项。 |
- 一个预制体,多个实例——共享数据放在预制体里,用
overrides区分实例,这样一次设计 改动就更新所有实例。 - 通过
entitiesmap 访问子项,而不是按索引遍历层级。 - 在生成时设父级(
parent),而非事后重设父级,让变换在第一帧就正确解析。 - 当某个改动应当全局时,在编辑器里用 apply-to-prefab 把实例的调整推回源。