前言
Prefab,也就是大家熟知的预制件(本文中,我们依然使用它的英文名字——Prefab),它是Unity中一个极其重要的概念。Prefab用来保存GameObjects(以及其所有的子GameObejct)、组件以及属性。在实例化Prefab的时候,Prefab扮演着资源模版的角色。
Unity2018.3的Beta版本中支持了可嵌套的Prefab系统,这个新特性使得能够把一个大型的建筑剥离成粒度更小的Prefab来。例如大型建筑,可以嵌套房间的Prefab,以此类推,房间的Prefab也可以嵌套更小的家具的Prefab。Prefab嵌套的灵活性极大的增强了Pefab在多人协同开发的效率,同时新版的Prefab系统在Prefab的编辑上也有很大的改变,使用起来非常方便。
接下来,我们就来一览新版的Prefab系统吧。开始正文之前,show一张我们工作室的游戏截图
一、创建Prefab
创建Prefab资源
创建Prefab同之前版本的Unity引擎一样,我们只需要把Hierarchy视图中GameObject拖到Project视图里,穿着蓝色衣服的Prefab资源就出现在Project的视图中了。
二、Prefab实例化
创建Prefab实例的方法也没有改变,还是下面两个途径:
- 从Project视图中直接把Prefab拖动到Scene或者Hierarchy视图里面。
- 在运行时通过Instantiate这个API来创建Prefab的实例。
在Prefab模式下编辑Prefab
Prefab模式,是一种专门用来支持单独编辑Prefab的一种模式。Prefab模式允许在一个独立的场景里面查看和编辑Prefab里面的内容。
进入Prefab模式
这里有两种方法可以进入Prefab模式:
- 在Project视图中双击Prefab
- 在Hierarchy视图中点击Prefab实例的箭头按钮
注意:在Prefab模式下,Prefab的根节点是普通类型的GameObject(并是不显示成Prefab实例特有的蓝色图标)
在Prefab模式下,Scene视图的上方会显示一个导航栏。使用导航按钮可以在主场景或其他Prefab之间切换。此外,在Hierarchy视图顶部,也会显示一个标题栏,上面显示当前打开的Prefab的名字。点击标题栏中的左箭头按钮,也可以用于回到主场景。
自动保存
在Prefab下,如果点选了自动保存的话,任何对Prefab的改动,都将会自动的保存到Prefab资源中去(自动保存默认是开启的)。
我们也可以关闭自动保存。在关闭之后,当我们退出当前Prefab的Prefab模式的时候,编辑器会提醒我们是否保存修改。在某些情况下,关闭自动保存是非常有用的。
设置Prefab模式的编辑环境
Prefab模式下,默认会显示一个空场景。我们可以指定一个特定的场景来作为Prefab模式的背景场景。(背景场景中的对象,都会显示在Prefab模式中,但是这些对象是无法被选中的,也不会显示在Hierarcy视图中。)
我们可以通过Editor Settings来设置这个背景场景。在打开主菜单“Edit->Project Settings -> Editor”,找到“Prefab Editing Environments”。其中“Regular Environment”适用于大多数的Prefab,“UI Environment”适用于大多数的UI相关的Prefab。
三、实例的覆盖值
所谓覆盖值,简单地说,修改了实例的值就会产生覆盖效果,Prefab实例中值覆盖了Prefab资源中的值,这就是覆盖值的定义。
这个特性是非常有用的,例如,当你需要创建多个相似的NPC,但是又需要有一些少许的差异(也就是说实例和Prefab不会完全一致的时候)。
我们对Prefab实例中的值进行修改,就相当于创建了一个覆盖值。 修改的动作,我们可以理解为覆盖。
新版的Prefab支持下面几种类型的覆盖
- 修改组件中属性的值
- 添加/删除组件
- 添加一个子的GameObject
同时这里也有一些限制:不能修改该Prefab中的Gameobject的根节点,也不能删除属于Prefab的GameObject(可以通过active为false的方法来绕过)
为了直观地看到被覆盖的属性,Unity把Inspector中被覆盖的属性的名字用粗体字显示,同时在左边的边缘显示了一条蓝色的线。如果是添加的一个全新的Componet的话,蓝色的线会跨过整个Componet。
添加或者移除组件,会在Inspector界面的名字旁边生成+或者-的标记。如果是增加一个GameObject话,则会在Hierarchy视图中的图标旁边增加+的标记。
实例覆盖值的优先级更高
Prefab实例的覆盖值,会取代来自Prefab资源中的值。换而言之,如果你修改了Prefab资源中的一个值,这个值对于被覆盖了值的实例来说,是不会生效的。<u>因此,发现修改了Prefab中的值,但不是所有的Prefab实例都有效果,那么建议检查一下这个值是否是在没生效的Prefab实例中被覆盖了。</u>
最后,为了尽量去避免潜在的问题和困惑,建议只在必要的情况下使用实例覆盖值取代Prefab的值。
四、通过实例来编辑Prefab
当选中Prefab实例的根节点时候,Inspector界面中会出现3个按钮,分别是Open、Select和Overrides。
点击Open按钮,将直接进入Prefab模式,点击Select,将会在Proejct视图中选中Prefab资源。点击Overrides,则会弹出一个下拉窗口。重点说下Overrides.
Overrides下拉窗口
Overrides下拉窗口中可以查看所有修改过的数据项(例如属性,组件,添加的GameObjects等)。在这个窗口中,我们可以放弃和应用所有的修改。(需要注意的是,如果这个Prefab是嵌套在其他Prefab中的话,那么Inspector中没有Overrides按钮,因此不能打开Overrides窗口)
通过点击下拉界面中列表的数据项,会弹出一个悬浮界面。如果是修改的属性,这个悬浮界面分为两个部分,左边是来自Prefab资源中的值,右边是Prefab实例的值,其中修改过的字段的名字被加粗显示,同时在左边缘有一个蓝色的竖线。
上下文菜单
另外,所有类型的覆盖值,都可以通过相关上下文菜单来进行应用/撤销。
在Inspector界面中,加粗显示覆盖了Prefab的值的属性名。右键点击,在弹出的上下文菜单里面,选择Apply to Prefab或Revert。
对于修改过的组件(新增加的组件,组件图标旁边有一个+标记),可以通过点击该组件右上角的齿轮按钮,或者右键点击组件顶部弹出上下文菜单来进行操作。
已经移除的组件上,会有一个-标记重叠在组件的图标上。删除操作也可以通过是上下文菜单来进行回滚或应用到Prefab资源上。撤销删除的组件,这个组件会从新回到GameObjct中。应用修改的话,会把这个组件也从Prefab中也删除。
在Prefab实例中新增加的GameObject的图标上会叠加一个+的标记。在Hierarchy视图中,右键点击新增的GameObejct,在弹出的上下文菜单中可以进行应用和撤销的操作。
五、Prefab的嵌套
当当(念一声和二声),到了本文最核心的部分了,Prefab的嵌套。Prefab嵌套是指在一个Prefab中,可以包含其他的Prefab,也就是说,一个Prefab可以包含在另外一个Prefab中。做关卡设计的同学,对以前的Prefab有多难用,有深刻的感受,现在终于可以长长地舒口气了。
在Prefab模式中添加嵌套的Prefab
添加一个嵌套的Prefab和在场景中添加实例化Prefab的操作是一样的,通过把Prefab资源拖动到Hierarchy视图或者Scene视图中就可以把一个Prefab实例添加到已经打开的Prefab中去。
这里可以看到,在Prefab模式下打开的Prefab的GameObejct的图标,显示成的是普通的图标,而嵌套的Prefab的实例则显示着象征了Prefab实例的蓝色图标。同时。我们可以像在普通场景中一样地覆盖这些Prefab实例的值。
在Prefab的实例中进行嵌套的操作
我们也可在非Prefab模式下来创建Prefab的嵌套。我们只需要把Prefab资源拖动到一个Prefab实例下面,编辑器会在Hierarchy为我们创建一个叠加了+标记的Prefab实例(+标记意味着这个被添加的Prefab实例可以撤销或者应用到外部的Prefab中去)。
这里我们和前面介绍的通过实例来编辑Prefab的操作一样,可以把这个修改覆盖值应用到外部的Prefab资源中去。在进行覆盖操作后,+号标记会消失,它将成为外部Prefab的一部分。
六、Prefab变体
Prefab变体类似于面向对象编程中的继承的概念。Prefab变体继承了基础Prefab的所有属性,覆盖Prefab变体中的属性,会把属性覆盖到基础Prefab中去。Prefab变体也是一个会带来极大效率提升的新功能。
Prefab变体可以这样的应用场景下使用: 我们有一个武器的Prefab,为这个武器创建一个变体,通过赋予不同的材质,可以让武器呈现出不同于基础Prefab的外观,例如金属质感,破旧感。对于基础武器Prefab的修改,会影响变体(在变体中覆盖的属性不受影响)。比如我们可以通过调整基础Prefab的碰撞参数来修改各个变体的物理碰撞范围。
创建Prefab变体
Unity提供了多种方法来创建Prefab变体:
- 在Project视图中,右键点击Prefab资源,然后选择“Create Prefab Variant”。
- 把一个Prefab实例从Hierarchy视图中拖到Project视图中,会弹出一个对话框,让我们选择是创建一个新的Prefab还是创建一个Prefab变体。如果我们选择Prefab变体的话,就会基于拖出的Prefab实例的Prefab资源来创建一个变体,所有在这个实例中的修改,都会存储在Prefab变体内部
Prefab变体显示和Prefab一样的图标,不同的是,图标上有叠加箭头样的装饰图形。
编辑Prefab变体
在Prefab模式下的Prefab变体的的根节点显示着标志着是Prefab实例的蓝色图标,本质上Prefab变体的内核就是一个Prefab实例,任何对这个变体的修改,都可以覆盖到基础Prefab中去。
变体可以覆盖的类型和相关限制,与Prefab实例中修改Prefab是一样的,具体可参考第三节实例覆盖部分的描述。
例如,选择“Table with Vase”的根节点,然后点击Inspector界面中的Select按钮,编辑器会帮助选中基础Prefab资源,正如我们前面所说,这是因为在变体中,“Table with Vase“是一个Prefab实例。
对Prefab变体的相关操作,和实例覆盖完全一致。再次强调一下,所有的Override操作,都是覆盖到基础Prefab资源中的,而不是Prefab变体中。
七、多层级应用覆盖值
当我们修改一个嵌套在内部的Prefab实例时候,在执行Override操作的时候,Unity提供了在应用覆盖的时候可以选择覆盖到不同的Prefab的选项,这就是所谓的多层级应用覆盖。
如果Vase中的根节点的Scale被修改了,在应用覆盖的时候,可以选择是应用到Table还是Vase上。
- 如果选择了应用到Vase上,则修改后Scale会保存到Vase的Prefab资源中去,进而影响到所有的Vase实例。
- 如果选择了应用到Table上,修改后的Scale变成Table这个Prefab内部的Vase实例的值覆盖,修改后的Scale在Hierarchy或Inspector界面中不会被标记为蓝色的值覆盖。但是在Table的Prefab模式下,Vase实例的Scale值,依然标记为值覆盖。这就意味着所有的Table实例中的Vase实例都使用了这个Scale来覆盖Prefab资源中的值。*而在工程中的其他不属于Table中的Vase实例,则不受这个值的影响。
八、Unpacking Prefab Instance(解除和Prefab的关联)
在新版本中的Prefab中,可以通过Unpack Prefab来解除Prefab实例和Prefab资源之间的连接关系。Prefab实例解除连接后,在Hierarchy视图中的图标显示为普通GameObject的图标。
新版Prefab系统支持两种解除连接Prefab资源的方法,点击Prefab实例的根节点,在右键弹出的窗口中,找到下面的两个选项:
- Unpack Prefab
解除当前Prefab实例和Prefab资源的连接关系。这个操作对内部嵌套的Prefab是没有影响的。
- Unpack Prefab Completely
完全解除关联和旧版本引擎的“Break Prefab Instance”功能类似,一旦执行了完全解除关联,当前Prefab实例下的所有嵌套Prefab实例也会失去和对应的Prefab资源的关联。
九、结尾
新版的Prefab系统为大家介绍到这里。本文的核心内容主要参考自官方的一篇关于Prefab的文章Prefab手册。
写作本文的过程中,笔者使用的Unity引擎版本是2018.3.b7。操作过程中,仍然出现了一些难以描述的bug。例如嵌套的Prefab在场景里面有显示,但是Hierarchy视图中,却看不到(此时编辑器控制台会一直报一个序列化相关的错误)。因此,不建议在正式的商业项目中使用Unity2018.3的beta版本。
受限于笔者的能力有限,因此难免有偏颇之处,希望朋友们雅正、谅解。