【Unity】3.2 利用预设(Prefab)制作可复用的组件
分类:Unity、C#、VS2015
创建日期:2016-04-02
一、简介
预制体(Prefab,也叫预设)是“存储在工程视图(Project View)中”的一种特殊的资源,是一种可重复使用的游戏对象(GameObject)的容器。
如果在Project中有多个预制体(Prefab),为了容易查找,可将这些预制体全部保存到Project视图中Assets文件夹的Prefabs子文件夹下。
Prefabs子文件夹下的的所有预制体都可以放入到多个场景中,而且即使在同一个场景中仍然可以多次使用。
向场景中添加一个预制体就是创建该预制体的一个实例。另外,由于场景(Scene)中所有预制体的实例都会自动链接到Project中的原始预制体(Prefab),因此这些实例本质上就是原始预制体的克隆。或者说,不论场景中有多少个预制体实例,只要仅仅对Project中某个Prefab作出任何更改,你就会看到这些更改马上就能应用于场景中该Prefab的所有实例。
1、在工程视图(Project)中创建预制体(Prefab)
要在Project中创建一个预制体(Prefab),只需将你在场景(Scene)中创建的一个游戏对象 (GameObject)拖放到工程视图(Project View)中的某个Prefab中。
如果层级视图(Hierarchy)中的游戏对象(GameObject)的名称变成蓝色,表示Hierarchy中的该对象是一个已经制作好的预制体的实例。此时,你可以根据需要,决定是保留层级视图 (Hierarchy)中的这个实例还是删除这个实例,不论你是否保留,都不会影响Project中制作好的原始预制体。
2、在层次视图(Hierarchy)中创建预制体的实例
要在“当前场景中”创建一个“预制体的实例”,直接从工程视图(Project View)中将某个预制体拖放到场景(Scene)或层级视图(Hierarchy)中。
Hierarchy视图中的“蓝色”字体表示该对象是某个预制体的实例。
一旦你创建了预制体的实例,该实例就会自动链接到Project中的源预制体,并在层级视图(Hierarchy)中以“蓝色”文字显示。
在这个截图中,有3个游戏对象是蓝色,表示这都是预制体的实例。
3、在检视器(Inspector)中操作预制体
(1)粗体的含义
有时候你可能希望仅更改单个预制体实例的属性,同时还能保持与源预制体的链接完整,此时可看到该实例对应的变量名称变成了粗体,表示这个变量已被重写。注意,所有重写的属性都不会受到源预制体更改的影响。
(2)Select
如果你选择了某个预制体实例,并希望将所做的更改影响到所有实例,此时可直接在检视器(Inspector)中单击【Select】按钮来选择更改的原始预制体。
(3)Apply
如果希望用重写的值更新源预制体及其所有实例,可单击检视器(Inspector)中的【Apply】 按钮。注意,这种“应用”不会对“根位置”和“旋转”起作用,因为这会影响实例的绝对位置并导致所有实例放在同一个位置。但是,Apply会对根的任何子元素或祖先元素的位置和旋转起作用,因为它们是相对于根的变换来计算的。
(4)Revert
如果想放弃对特定实例的所有重写,可单击【(Revert)】按钮。
4、导入预制体
将网格资源放入Assets文件夹下时,Unity会自动导入文件,并生成一些类似于网格之外的看起来像预制体的东西。但是,这实际上不是预制体(Prefab),它只是资源文件本身使用的东西。
注意,资源(asset)图标与预设 (Prefab) 图标略有不同。
资源是作为一个游戏对象(GameObject)存在于场景中的实例,它链接到源资源而不是链接到预制体(Prefab)。你可以向该游戏对象(GameObject) 正常添加、删除组件,。但是你无法对资源本身作任何更改,因为这样会向资源文件本身添加数据!如果你希望创建一些可重复使用的东西,那你就应当把它制作成一个预制体。
选择一个资源实例时,检视器 (Inspector) 中的【Apply】按钮将被替换成【Edit】按钮。单击此按钮将为资源启动编辑应用程序(如 Maya 或 Max)。
二、Prefabs基本用法示例
经过上面的介绍,你应当已经从基本层面上了解了Prefabs的概念:Prefabs本质上是GameObjects(预定义的游戏对象)和Components(组件)组成的集合体,是可在游戏中重复使用的容器对象。
使用Prefabs可以方便地在运行时实例化复杂的GameObjects(游戏对象)。
1、创建游戏对象的方式
在Unity中,有两种创建对象(Game Object)的方式:
(1)方式1:全部用C#代码实现。这种方式使用C#代码从头开始创建并初始化游戏对象(GameObjects)。
(2)方式2:利用Prefabs实现。即:先制作预制体,运行时再通过代码实例化预制体。
与方式1相比,方式2(用Prefabs实现)有多个优势:
l 可以使用一行代码实例化Prefab,并具有完整功能。而使用代码创建等效游戏对象 (GameObjects),平均需要五行代码,还有可能需要更多。
l 可在场景 (Scene) 和检视器 (Inspector) 中快速设置、测试和修改预制体。
l 可以更改已实例化的预制体,而无需更改实例化预制体的代码。例如,可将一个简单的火箭更改成超级火箭,但无需更改代码。
2、示例—创建一堵墙
为了说明Prefabs的强大,让我们来看看可用得上Prefabs的一些基本情况:
(1)在不同位置,多次使用单块“砖”预制体来创建一堵墙。
(2)发射时,火箭发射器实例化一个飞行的火箭预制体。该预制体是一个包含一个网格(Mesh)、刚体 (Rigidbody)、碰撞器 (Collider) 和带有自己的拖尾粒子系统 (Particle System) 的子游戏对象 (GameObject)。
(3)机器人爆炸成许多碎片。此时完整的操作机器人已毁坏,替换成一个残破的机器人预制体。该预制体包含分成多个部分的机器人,所有部分均设有自己的刚体 (Rigidbodies) 和粒子系统 (Particle Systems)。有了预制体,你仅用一行代码就可以将一个对象替换成指定的预制体,从而让机器人炸成许多碎片。
该示例仅仅是为了说明“使用Prefab创建对象”与“使用代码创建对象”相比,前者(使用Prefab创建对象)的优势。
(1)实现方式1
首先演示“使用代码创建对象”的实现方式,因为只有比较,你才能理解这种方式有什么缺点。
先在ch03Demos工程的Project视图的Assets下创建一个名为Scripts的子文件夹,然后在该子文件夹添加一个名为Demo1的C#脚本:
双击Demo1脚本,Unity就会自动启动VS2015并自动在VS2015中打开Demo1.cs文件,而且解决方案资源管理器中Assets下的文件夹结构和Unity中的文件夹结构相同:
将Demo1.cs文件改为下面的内容:
using UnityEngine; using System.Collections; public class Demo1 : MonoBehaviour { void Start () { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.AddComponent<Rigidbody>(); cube.transform.position = new Vector3(x, y, 0); } } } }
保存该文件。
切换到Unity,选择主菜单的【GameObject】->【Create Empty】创建一个空游戏对象,再将Scripts文件夹下的Demo1脚本拖放到刚添加的空游戏对象中。
切换到Game视图,单击【播放】按钮观察执行效果。此时将看到完全用代码创建的立方体墙(由于默认使用了重力,墙会自动倒塌):
当然,由于没有添加纹理,所以此时看到的仅仅是一堵白色的墙(倒塌后还是一个一个的立方体)。若想执行附加操作,例如更改砖块纹理、摩擦力或刚体的质量,还需要再添加其他的代码,可见用这种方式实现起来有多么麻烦。
删除层次视图中刚创建的空游戏对象。
(2)实现方式2
第2种中实现方式是先创建一个“墙”预制体,然后再用“创建预制体实例”的办法来创建多堵墙。
步骤如下:
选择主菜单的【GameObject】->【3D Object】->【Cube】创建一个立方体:
此时,刚创建的Cube在层次视图中处于选中状态。
将Texture文件夹下的brick_D拖放到层次视图中的这个立方体上。
在Project视图的Assets文件夹下,添加一个Prefabs子文件夹:
鼠标右击Prefabs子文件夹,选择【Create】->【Prefab】:
将新添加的Prefab的名称更改为“Brick”。
将在层级视图中创建的立方体拖放到Project视图中刚创建的“Brick”上。
这样就创建好了一个名为“Brick”的预制体(或预设)。
创建预设 (Prefab) 后,在层次视图中添加的立方体(Cube)已经用不到了,可以从层级视图 (Hierarchy) 选中它,然后按Delete键删除。
重新添加一个空游戏对象 (GameObject)。
在VS2015解决方案资源管理器项目中的Scripts子文件夹下,添加一个文件名为Demo2.cs的C#脚本(Demo2.cs),然后将其改为下面的内容:
using UnityEngine; using System.Collections; public class Demo2 : MonoBehaviour { public Transform Brick; void Start () { for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { Instantiate(Brick, new Vector3(x, y, 0), Quaternion.identity); } } } }
按<F5>键将其附加到Unity,然后按<Shift>+<F5>键结束。
切换到Unity,将工程视图下的该脚本拖放到刚才添加的Cube上,这就为该对象添加了一个Demo2组件:
另外,此时检视器 (Inspector) 中将出现一个名为“Brick”的新变量,这个Transform类型的变量可以接受任何游戏对象 (GameObject) 或预制体。
从工程视图 (Project View) 中,将预制体“Brick”拖放到检视器 (Inspector)视图中的Brick变量的值上(作用是:创建预制体的实例作为Brick变量的值):
按下“播放 (Play)”,就会看到同时使用预制体和C#脚本创建的墙:
可见,这种方式实现的脚本代码不仅非常干净,而且可重复使用这个Brick预制体。
刚开始学习时,你可能想知道为什么要这样做,用第1种方式创建立方体不是更灵活和方便吗?为什么还要再搞一个Prefab呢?
这是因为使用Prefab,您可以在数秒之内就能完成对它的调整:
- 想要添加或更改所有实例的质量?只需在预制体中添加一个刚体,并一次性调整刚体 (Rigidbody)的重力即可。
- 想为所有实例使用不同的材质 (Material)?只需将材质 (Material) 拖放到预制体上一次。
- 想要更改摩擦力?在预制体碰撞器中使用不同的物理材质 (Physic Material)就行了。
- 想为所有立方体添加一个粒子系统 (Particle System)?向预制体中添加一次子对象即可。
当然,如果仅仅是为了学习操作步骤,找不到brick_D.jpg文件时,随便找一副其他的.jpg图片代替也行,反正目标就是给这堵用立方体构造的墙贴满图,理解其含义就行了。