LGUI Prefab和Unity Prefab系统很相似,在虚幻中预制件是可以存储在资产中并实例化到关卡中的 actor 集合,它不受 UI 元素的限制,您可以在 LGUIPrefab 中使用几乎所有 actor 类型;Actor指的就是虚幻的Actor,如下图所示。

image-VAWh.png

在构造关卡时,通常情况下,你希望创建一些 Actor 的排列,然后在相同关卡或其他关卡中重用该集合。例如,火把可能由一些静态网

,只有仍处于原始预制件默认值的属性才会更新。例如,假设您有一个包含黄色光源的预制件,然后您将预制件的一个实例更改为具有蓝光。然后,您将预制件本身更改为绿灯。只有光线仍为黄色的实例才会将颜色更改为绿色。这非常有用,因为它允许您修改甚至删除预制件实例的某些部分以使其适合特定用途,同时还可以接收对预制件的更新。

创建预制体

创建预制件,和unity操作一样,所有Actor都需要附加到一个关卡中的单个根Actor,然后选择根 Actor,右键点击 LGUI 列,然后从上下文菜单中选择 创建预制件(Create Prefab),点击后将显示一个保存窗口,选择保存路径(要在content目录下);单击“保存”,然后一个预制件资源将出现在内容文件夹中,该预制件的 actor 将在 LGUI 列上显示“预制件”图标:

删除预制体

在大纲中删除这个预制体组,不能直接删除根Actor,这个和UE特性有关

在 UE 中“附着”只是变换层级关系,不是所有权。销毁父 Actor 不会自动销毁附着在它上的其他 Actor;删除根组件也不会影响其他独立 Actor。

会被跟着一起销毁的只有该 Actor 自己的组件(UActorComponent),因为组件的所有者是 Actor;但“子 Actor”是独立对象,生命周期不受附件关系控制。

所以要删除本预制体(以及子组件),则需要借助LGUI Editor Tools这个LGUI编辑器右键菜单工具,右键点击根 Actor 的 LGUI 列,然后选择“Destroy Actors”,以删除整个预制体。

本功能是直接删除本物体以及附着在本物体上的Actor,所以可以操作非LGUI系统的actor。

image-efiL.png

在 LGUI-Prefab-Editor 中编辑预制件

只需双击预制件资源,就会弹出一个 LGUI-Prefab-Editor 窗口,LGUI 将自动创建一个名为“[temporary_RootAgent]”的根 Actor,因为该名称表示该 Actor 是临时创建的,仅作为根持有者。

在 LGUI-Prefab-Editor 窗口中,您可以执行任何您想要编辑/修改预制件的作,操作完后,重要的是单击编辑器窗口左上角的Apply(应用)按钮,Apply(应用)按钮会将您更改的属性保存到预制件资源中,因此请务必记住点击它。

这个PrefabEditor窗口是一个编辑Prefab的好地方;[temporary_RootAgent](或旧版本中的 [RootAgent])是自动创建的 actor,它只是一个临时的Actor,充当Prefab的父级容器,加载时Prefab的根会附加到这个RootAgent上。

RootAgent

RootAgent 的创建逻辑会根据 Prefab 的根 Actor 类型而不同:

  • UI Actor: 如果 Prefab 的根 Actor 是 UI 类型,会创建一个 AUIContainerActor 作为 RootAgent,并可选地添加 Canvas 组件。

  • 普通 Actor: 如果不是 UI 类型,会创建一个普通的 AActor 并添加 SceneComponent 作为根组件;此时这个根组件锚点可编辑;如果要使用自己的 LGUICanvas,则应删除 [temporary_RootAgent] 上的 LGUICanvas 组件。

RootAgent 具有一些特殊的编辑器属性:

  • 位置锁定 (SetLockLocation(true))

  • 名称不可编辑 (bActorLabelEditable = false)

  • 固定在原点位置

RootAgent 在编辑器中有特殊的限制:

  • 不能作为子 Prefab 的父节点

  • 不能将其他 Actor 附加到

  • 所有 Actor 必须附加到 Prefab 的根 Actor,而不是 RootAgent

有一点需要注意一下,在PrefabEditor 中给prefab上分配一个 actor 变量,我们实际上无法使用这些快速方法来选择所需的 actor(三个小图标按钮),因为它只能选择当前关卡中的 actor:

image-StvK.png

但我们该怎么做呢?好吧,有一个解决方法。检查 细节(Details) 面板中的小锁按钮,然后将你的 Actor 拖到变量区域:

在关卡编辑器中编辑预制体组件

将你的预制件资源拖放到关卡编辑器的视口中,这将创建一个预制件资源的实例;请注意,如果你在关卡编辑器中选择一个 Actor,然后拖放预制件,则创建的预制件实例将附加到所选 Actor。

在关卡编辑器中编辑预制件实例时,LGUI 实际上将其视为子预制件,因此功能和限制是相同的,请参阅下面的嵌套预制件和属性覆盖部分。

在运行时加卸预制体

LGUIPrefab 提供了一个函数来在运行时加载它,你可以在蓝图和 c++ 中轻松调用它,可以看到,一个是使用LGUIPrefab实例的加载方式;另一种是蓝图函数库方式加载,蓝图函数库在确定Prefab的引用有效性后,调用Prefab的对应加载方法。

  • LoadPrefab:Prefab 资产对象的核心加载方法,根据 Prefab 版本选择对应的序列化器。

  • LoadPrefabWithTransform:Prefab 资产对象的带变换加载方法,支持指定相对变换。

  • LoadPrefabWithReplacement:Prefab 资产对象的带资源替换加载方法,临时替换引用列表中的资源和类。

参数:

  • InParent:提供 SceneComponent 作为父级,以便加载的预制件的根 Actor 将附加到父级。

  • SetRelativeTransformToIdentity: true- 重置加载的预制件的根 actor 的变换值;false- 保留原点值。

  • In Callback Before Awake:在执行预制体的Awake(LGUI生命周期函数)之前的回调

LoadPrefabWithReplacement

  • InReplaceAssetMap:从资产映射到另一个资产,可能是静态网格体。

  • InReplaceClassMap:从类映射到另一个类,在上面的示例中,我们可以将 CompA 映射到 CompB。

此函数让我们有机会在加载预制件之前替换预制件的引用资产或类。在以下情况下很有用,我们在根 actor 上创建一个 PrefabA 和一个组件 CompA 来管理 PrefabA,然后我们创建一个与 CompA 具有相同属性但具有不同函数实现的 CompB,然后我们可以使用此函数加载 PrefabA 并将类从 CompA 替换为 CompB;但请记住,预制件序列化依赖于 UProperty,因此 CompA 和 CompB 必须具有相同的 UProperty。

想象一下,您有一个 UI 按钮的 Prefab,它引用了一个蓝色的材质。现在您想在运行时加载这个按钮,但希望它显示为红色,而不想修改原始的 Prefab 资产。LoadPrefabWithReplacement 就是用来做这件事的。

LoadPrefabWithReplacement 的核心逻辑可以分为三个主要阶段:临时替换、加载执行、恢复原状。整个替换过程不会永久修改 Prefab 资产,所有修改都是临时的。这通过"替换-使用-恢复"的三阶段模式实现。

遍历并替换资源

如果提供了资源替换映射 (InReplaceAssetMap.Num() > 0),系统会遍历资源列表: LGUIPrefab.cpp:529-536

对于列表中的每个资源,使用 TMap::Find() 查找是否需要替换。如果找到匹配项,则:

  • 将原始索引和原始资源保存到 ReplacedAssets 集合中

  • 用新资源替换列表中的对应位置

类似地,如果提供了类替换映射 (InReplaceClassMap.Num() > 0),执行相同的替换逻辑

关键点

  1. 不修改原始资产: Prefab 文件本身不会被改变

  2. 临时性: 替换只在这一次加载中生效,下次加载需要重新指定

  3. 灵活性: 可以同时替换多个资源和类

这个功能的核心就是"借花献佛"——用您提供的新资源,临时替换 Prefab 里的旧资源,加载完成后再把 Prefab 恢复原样。这样您就可以用同一个 Prefab 创建出不同外观的实例,而不需要创建多个 Prefab 资产。

使用场景:

这个功能适用于以下场景:

  1. 动态换肤: 加载同一个 UI Prefab 但使用不同的材质或纹理

  2. 多语言支持: 替换文本资源以支持不同语言

  3. A/B 测试: 使用不同的资源变体测试效果

  4. 运行时定制: 根据玩家设置或游戏状态动态替换资源

在运行时加载预制件时初始化

LGUIPrefab 使用自己的序列化策略,并且它比“BeginPlay”执行晚,因此“BeginPlay”时属性尚未就绪,因此必须使用“BeginPlay”的替换来执行初始化作业。

LGUIPrefab 提供了两种方法来实现这一点:

  • LGUILifeCycleBehaviour :是 LGUI 的生命周期行为基类,类似于 Unity 的 MonoBehaviour,为组件提供了一套完整的生命周期回调;这是一个ActorCompoment扩展,是抽象的,您需要自己继承实现本组件,然后附加到需要的地方。

  • LGUIPrefabInterface:Actor 和 ActorComponent 都可以实现此接口,这是一个轻量的接口,只有Awake和一个Awake_Editor(编辑器下初始化,如拖入到世界中,仅编辑器下调用,运行时本函数不会调用)

在运行时删除预制件实例

Prefab 实例只是 actor 的集合,因此我们需要做的就是删除这些 actor。LGUI 提供了一个简单的函数来做到这一点 “Destroy Actor with Hierarchy”,只需将其与加载的预制件的根 actor 一起使用即可:

嵌套预制件和属性覆盖

嵌套预制件意味着您可以在其他预制件中包含预制件实例。嵌套预制件保留其与自己的预制件资产的链接,同时也构成另一个预制件资产的一部分。

如何创建嵌套预制件?这很简单,双击 Prefab 资源打开一个 LGUI-Prefab-Editor,单击一个 actor 将其选择为父级,然后将另一个预制件拖到 LGUI-Prefab-Editor 的视口中,然后你会发现在 LGUI-Prefab-Editor 中创建了一个 Prefab 实例:

预制件可以维护其默认属性,并跟踪更改的属性值以供以后的应用恢复 。例如,如果我将灯光颜色更改为红色,转到 Sub-Prefab 的根 Actor 并右键单击 outliner 中的 LGUI 列,您将找到“Prefab Override Properties”,单击它并可以看到修改后的属性;您可以将修改后的属性恢复为子预制件的默认值,或应用该值以更改子预制件的默认值。

编辑子预制件时有一些限制:

  • 无法删除或移除 Actor。

  • 无法删除或移除 ActorComponent。

  • 无法更改 Actor 的附件。

如果我们尝试将一个 actor 附加到另一个 actor,将显示一条消息来阻止它: