新版Prefab的一些梳理

欢迎 来到 王国聪的博客!

原文链接:https://zhuanlan.zhihu.com/p/53824013

前言

Unity的Prefab相信大家一定很熟悉了,但是用起来那叫个又爱又恨,爱是因为它方便,恨是因为它不支持嵌套,经过大家的各种报怨,终于在Unity2018.3.0f2中迎来了功能支持~

先说下Prefab都有哪些好处吧:

  • 类似模版的概念,修改基本Prefab,所以实例都会相应的更新改变。(这也是原本Prefab就有的功能,也是最基本的功能)
  • 嵌套,可多级嵌套,在角色、UI、特效等上都有很大的发挥空间。
  • 变体,在做同一类型资源(有不同外观或属性)但是又希望每一个都是个Prefab时比较有用。

好处了解完后,接下来就详细的从头到尾来捋一捋。


Prefab

首先要说下如何生成Prefab,以一个机器人Robot(利用一些基本Cube拼出一个机器人)为例:

prefab1

利用一些Cube拼出的机器人

如何生成Prefab?

  1. 首先在Hierarchy面板中创建出我们的机器人,并且把所有的部件都放在一个叫Robot的空物体下面。(因为我们是要把整个机器人做为Prefab来保存,所以需要把它们组合到一个对象下面来管理)

  2. 在Hierarchy面板中,将Robot拖到Project面板内(具体拖到哪个文件夹可自由决定),即可在相应的文件夹内生成Robot的Prefab。

在Hierarchy面板中,对象名称左边有个小图标,在普通情况下它是一个灰白色的小方块,而当它是个Prefab实例时,则是一个蓝色的小方块,这是在Hierarchy面板区分物体是否为Prefab的一个直观的方式。
在Project面板中,Prefab是以.prefab为后缀命名的。

如何编缉Prefab?

有多种方式可以对Prefab进行编缉,这里编缉的意思是指对Prefab本身做修改,以使修改自动更新到所有的实例中。

  • 第一种方式是在Prefab Mode中进行编缉。

Prefab Mode是新版中的新术语,意思就是进入一个独立的空间中,在其中对Prefab进行修改编缉。

  • 第二种方式是在外面进行,也就是普通界面下进行修改编缉。

Prefab

Prefab Mode

要在Prefab Mode中编缉,首先就要进入到此模式下,有以下几种进入方式:

  • 在Hierarchy面板中,Prefab对象的最右侧有个向右的小箭头,通过点击此箭头即可进入Prefab Mode中。

prefab2

从Hierarchy进入Prefab Mode
  • 同样是在Hierarchy面板选中Prefab后,在Inspector面板最上方会显示”Open”字样的按钮,点击Open即可进入。

prefab3

从Hierarchy选中对象并从Inspector面板中进入Prefab Mode
  • 在Project面板中,选中Prefab后,在Inspector面板中会显示”Open Prefab”字样的按钮,点击即可进入。

prefab4

从Project进入Prefab Mode

进入后呈现如下所示:

prefab5

Prefab Mode
  1. 一级一级的退出Prefab Mode,每点一次回退一级。
  2. 点击标签可以回退到指定的上一级,多级嵌套时可以方便的回到某个层级中。
  3. Auto Save,自动保存,默认勾选,在Prefab Mode中所做的任何修改都会自动进行保存。如果电脑性能不佳,有出现卡顿感时,可以选择去掉勾选,在需要时主动点击Save按钮(当去掉勾选时,在其左边会出现Save按钮)。另外,当去掉勾选,同时也做了一些修改,但是在没有点Save后,直接选择退出Prefab Mode,此时会弹出一个提示对话框,需要选择是否对修改进行保存。还是相当贴心的。。。

Editing Environment

编缉环境,什么意思呢,就是说当我们进入Prefab Mode时,默认使用的都是一个只有天空盒的空场景,那如果我们想要换个场景怎么办呢?

通过Edit>Project Settings>Editor打开工程设置界面:

prefab6

设置Editing Environments

在此设置界面中有两个Environment可供设置:

Regular Environment:常规Prefab的编缉环境,常规是什么意思呢,其实就是非UI类的都属于常规类,也就是说凡是Prefab父级是Transform的都会用这个环境。

prefab8

常规类用Regular Environment

UI Environment:UI类的Prefab编缉环境,凡是Prefab父级是RectTransform的都会用这个环境。

prefab8

UI类用UI Environment

实例

现在把Robot Prefab从Project中拖入Hierarchy中,也就表示在场景中生成了一个Robot的实例,然后再拖进来一个,移动一下它的位置,至此,我们在场景中有了两个Robot的实例。

大部分情况下,我们都希望生成出来的实例是有些稍稍不同的,比如某个Robot大一点,某个Robot又高一些,甚至某些Robot有些额外的部件等等。

总体而言呢,会有以下几种类型的不同:

  • 属性值的不同
  • 组件的新增与删除
  • 子物体的添加

注意,除此以外的操作会要求进入到PrefabMode模式下更改,说明在实例上不支持,必须修改Prefab本体才行。比如子级排序变更、子对象的删除等操作。

删除子对象的操作可以采用在Inspector面板中禁用显示来变相达到需求。

当实例上有修改时,在Inspector界面中会以一个蓝色条状进行标示,以示区别。

prefab9

Prefab实例修改后的标记

覆盖与恢复

概念

覆盖与恢复操作是Prefab实例中很重要的两个概念:

  • Overrides(覆盖)

将实例中所做的修改覆盖应用到原始Prefab中去,此操作会更新所有的实例。

比如场景中有1000个机器人实例,当把其中一个改成2倍大,然后将其覆盖,此时场景中所有的实例都会变成2倍大。(前提是另外那999个机器人的缩放值没有修改过)

  • Revert(恢复)

将某个实例上的修改移除,并恢复到原始Prefab上的状态。

覆盖与恢复(方法一)

实现覆盖与恢复的方法很多,先说第一种,当我们选中实例时会在Inspector面板顶部显示三个按钮:

  • Open:进入Prefab Mode
  • Select:在Project面板中选中此Prefab
  • Overrides:覆盖或者恢复实例上的修改

其中覆盖与恢复操作就在Overrides中,默认情况下点击Overrides时,由于实例上没有任何修改,所以不会有覆盖与恢复相关的按钮,如下所示:

prefab10

实例上的基本操作

对象的Position与Rotation属性有修改时,不会算作Overrides,也就是说我们在实例上不管怎么修改位置与旋转都不会产生覆盖操作,同理,当我们修改了Prefab自身的位置与旋转值时也不会影响到任何实例。
注意Scale值会被收集到Overrides中。

当实例上产生可覆盖的修改时,面板将显示如下:

prefab11

  1. Revert All:恢复实例的所有修改到Prefab原始状态,也就是移除所有修改,回复到默认状态。
  2. Apply All:将此实例上的所有修改都覆盖到Prefab本身,此操作会影响到所有的实例。
  3. 当一个实例有修改时,会在此处列出每个修改块,通过点击可查看具体的修改信息。
  4. 查看每个修改块的具体修改内容,如果是新增的就会单独以Added的形式展示,如果是原先Prefab就有的,则会显示出两者的对比,便于参照,可以说是非常良心了。同时在此小面板的右上角有Revert和Apply两个按钮,与1、2大同小异,只不过是单独针对选中的对象进行操作的。

覆盖与恢复(方法二 )

第二种方法,还是在Inspector面板中,在修改属性的上面点击右键,从而会弹出相关的命令,如下图所示:

prefab12

在Component上覆盖与恢复Prefab

Apply to Prefab “XXX”,表示将此条修改覆盖到原始Prefab中。

Revert表示恢复此条修改。

添加与删除组件也可以用此方法来弹出操作命令,这里不再详细说明。
此种方式在修改了单独的属性并想快速覆盖与恢复时比较常用。

覆盖与恢复(方法三 )

第三种方法,这回是在Hierarchy面板中,在对象上点击右键,如下图所示:

prefab13

注意,此种方法只能对新增的子物体进行覆盖与恢复,无法针对组件以及对象上的属性修改做覆盖与恢复操作。

这三种方法,各有各的针对情况,第一种方法最全面,但是相对要小心处理,第二方法针对组件上的属性与添加和删除组件很好用,第三种方法主要针对添加子物体时的操作。所以三种方法相互配合才是提高操作效率的最佳手段。


嵌套Prefab

新版中最重要的功能就是支持嵌套了,实际操作起来也是非常简单,重要的一些概念在上面都已经讨论过了。

如下图中,我们将Robot的各个部件都单独生成一个Prefab并且放置于Robot内,这就形成了嵌套Prefab。

prefab14

Prefab中的嵌套Prefab

嵌套的Prefab的本身就是Prefab,把它当作常规Prefab就行了,只不过在新版本中,可以将它放在其它Prefab内,并同时保留自身的引用关系,当本体更新时它也会自动更新,这在以前的版本中是做不到的。

同时也支持多级嵌套,即Prefab中有子Prefab,子Prefab中又可有自己的子Prefab。。。以此类推,具体不清楚有没有嵌套层级数量限制,理论上来讲应该是无限的。


Prefab变体

此概念也是新版本中的功能,具体是什么意思呢?

试想一下,假如我们的Robot是一个怪物,那么我们现在想要多个怪物,但是它们外观又不大一样,并且各自的属性也不太相同,同时呢,它们又都是属于Robot类,也就是说,我们要生产一批类型差不多但稍有细微差别的一组Robot。

按照以前的做法,我们肯定是生成多个Prefab,各个Prefab不相关,不同的外观不同的属性,一旦想改变所有的属性时就必须要去一个个的修改,这是及其不方便的。

那么Prefab的变体就是为了解决此类问题而生的。

利用Prefab变体我们就可以快速生成多个Prefab,同时我们可以给予它们不同的外观与属性,但是它们又共同继承自原始的Prefab,当我需要整体都改变时只需调整最原始的Prefab即可。

如何创建Prefab变体

在Project面板中,在原始Prefab上点击右键,从中依次选择Creat>Prefab Variant即可。

prefab15

创建Prefab变体菜单

然后在原始Prefab边上就会出现一个变体资源,注意图标样式与普通Prefab是不同的。

prefab16

生成Prefab变体

这个时候就可以像修改普通Prefab一样的去修改变体Prefab了,但是有一点千万要注意:

在变体的Prefab Mode中,选中Prefab最上层时的Overides下覆盖按钮变成了Apply All to Base,此命令会使用变体的修改去覆盖原始Prefab,请千万明确此操作确实是你想要的再去点。

通常情景下,变体是不会去覆盖本体的,否则就失去了变体的意义了。

prefab17

变体上的覆盖到基类

下图简单展示了一个变体与本体的效果差别:

变体比本体中多了脚的部件,同时头部的属性值也发生了变化。

此时当我们去修改本体属性时,变体也会自动更新。这就是变体的核心方便之处。

prefab18

变体与本体

Prefab解散

同样,新功能,其实Prefab确实很像一个组,组内包含各式各样的部件与组件,那既然是一个组,那就有解散组的可能性。

所以官方也是考虑到了这一点,也提供了相应的功能支持。

如何解散

  1. 首先解散操作只能在实例上进行操作,也就是只能在Hierarchy中进行。所以先在Hierarchy中选中Prefab实例。

  2. 然后右键,从中选择Unpack Prefab或者Unpack Prefab Completely。

    prefab19

Prefab解散
  • Unpack Prefab:解散Prefab与本体的关联,此时在Hierarchy面板中父级会变成灰色图标,表示不再是一个实例。在Inspector面板中Prefab相关的操作也会消失。但是子级的Prefab属性还是存在的。(如果子级有Prefab的话)

  • UnPack Prefab Completely:完全解散Prefab,此时不管是父级还是多深的子级全部失去与各自Prefab的关联,也就是纯纯粹变成了场景中的一组对象而已。

在对Prefab变体实例Unpack Prefab后,它会首先解散成普通Prefab(此时与原始Prefab会进行关联)。当再次执行Unpack Prefab后才会失去与本体Prefab的关联。


运行时覆盖

新版本同时也带来了一些新的问题,除了API需要更新以外,运行时修改并覆盖的功能也没了,在之前运行时选中Prefab实例,在Inspector面板是有Apply按钮来覆盖修改的,但是新版本中就完全消失了,这个功能对于美术特效人员来说非常重要,可以在运行时边调效果边保存,虽说也可以手动拖到Project面板中来覆盖保存,但未免总是有些不方便,于是抛砖引玉,给出下面这段运行时保存的代码:

prefab20

运行时保存代码

工具界面最终如下:

prefab21

工具界面

大概思路:

设想利用EditorWindow做成一个小工具窗,其中有一个按钮,在运行时修改完特效后选中此特效的父级直接点击按钮即可。

由于新版本中运行时Prefab实例会丢失与原始Prefab的关联(目测是这样),所以只能通过名称在相应的目录内来查找,查找到后进行替换,否则提示找不到。

此工具只是抛砖引玉,通用性太差,如果大家有更好更方便的方法请留言回复。

坚持原创技术分享,您的支持将鼓励我继续创作