zoukankan      html  css  js  c++  java
  • 【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)中以“蓝色”文字显示。

    image

    在这个截图中,有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#脚本:

    image

    双击Demo1脚本,Unity就会自动启动VS2015并自动在VS2015中打开Demo1.cs文件,而且解决方案资源管理器中Assets下的文件夹结构和Unity中的文件夹结构相同:

    image

    将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视图,单击【播放】按钮观察执行效果。此时将看到完全用代码创建的立方体墙(由于默认使用了重力,墙会自动倒塌):

    image

    当然,由于没有添加纹理,所以此时看到的仅仅是一堵白色的墙(倒塌后还是一个一个的立方体)。若想执行附加操作,例如更改砖块纹理、摩擦力或刚体的质量,还需要再添加其他的代码,可见用这种方式实现起来有多么麻烦。

    删除层次视图中刚创建的空游戏对象。

    (2)实现方式2

    第2种中实现方式是先创建一个“墙”预制体,然后再用“创建预制体实例”的办法来创建多堵墙。

    步骤如下:

    选择主菜单的【GameObject】->【3D Object】->【Cube】创建一个立方体:

    image

    此时,刚创建的Cube在层次视图中处于选中状态。

    将Texture文件夹下的brick_D拖放到层次视图中的这个立方体上。

    在Project视图的Assets文件夹下,添加一个Prefabs子文件夹:

    image

    鼠标右击Prefabs子文件夹,选择【Create】->【Prefab】:

    image

    将新添加的Prefab的名称更改为“Brick”。

    将在层级视图中创建的立方体拖放到Project视图中刚创建的“Brick”上。

    image

    这样就创建好了一个名为“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组件:

    image

    另外,此时检视器 (Inspector) 中将出现一个名为“Brick”的新变量,这个Transform类型的变量可以接受任何游戏对象 (GameObject) 或预制体。

    从工程视图 (Project View) 中,将预制体“Brick”拖放到检视器 (Inspector)视图中的Brick变量的值上(作用是:创建预制体的实例作为Brick变量的值):

    image

    按下“播放 (Play)”,就会看到同时使用预制体和C#脚本创建的墙:

    image

    可见,这种方式实现的脚本代码不仅非常干净,而且可重复使用这个Brick预制体。

    刚开始学习时,你可能想知道为什么要这样做,用第1种方式创建立方体不是更灵活和方便吗?为什么还要再搞一个Prefab呢?

    这是因为使用Prefab,您可以在数秒之内就能完成对它的调整:

    • 想要添加或更改所有实例的质量?只需在预制体中添加一个刚体,并一次性调整刚体 (Rigidbody)的重力即可。
    • 想为所有实例使用不同的材质 (Material)?只需将材质 (Material) 拖放到预制体上一次。
    • 想要更改摩擦力?在预制体碰撞器中使用不同的物理材质 (Physic Material)就行了。
    • 想为所有立方体添加一个粒子系统 (Particle System)?向预制体中添加一次子对象即可。

    当然,如果仅仅是为了学习操作步骤,找不到brick_D.jpg文件时,随便找一副其他的.jpg图片代替也行,反正目标就是给这堵用立方体构造的墙贴满图,理解其含义就行了。

  • 相关阅读:
    MacOS install Maven
    MacOS install Nginx
    网站速度优化
    MacOS命令行计算文件hash值
    网站接入GoogleAnalytics步骤
    更换GitHub Pages博客主题
    那些让我相见恨晚的东西(持续更新)
    python 中的getattr(),setattr(),hasattr()的方法
    父往子传,子往父传,以及平行传值
    watch和computed
  • 原文地址:https://www.cnblogs.com/rainmj/p/5347130.html
Copyright © 2011-2022 走看看