Unity中的标签 层级 静态物体 预制体

1. 标签

1.1 简介

标签(Tag)是一个可以标记在游戏物体上的记号,它一般是一个简单的单词。
比如:你可以为游戏人物添加一个Player标签,并为敌人角色添加一个Encemy 标签,还可以为地图上的道具添加一个Collectable标签。

在脚本中查找和指定物体时,使用标签是一种非常好的方法。
这种方法可以避免总是采用某个公开变量的方式来指定游戏物体,那样还需要通过拖曳的操作才能给变量赋初值。通过标签来查找物体可以简化编辑工作。

标签还特别适合用在处理碰撞的时候,当游戏人物与其他物体发生碰撞时,你可以通过判断碰到的物体是敌人、道具还是其他东西,来进行下一步处理。

1.2. Unity预制标签

Uniy预置了一些常用的标签, 在标签管理器中你不能修改下面这些预置的标签:

标签名 含义
Untagged 没有标签
Respawn 出生
Finish 完成
EditorOnly 编辑器专用
MainCamera 主摄像机
Player 玩家
GameController 游戏控制器

1.3. 创建新标签

要创建一个新的标签,需要在标签下拉菜单中选择Add Tag,之后检视窗口会切换到标签与层级管理器(Tag and Layer Manager)。

注意:标签一旦创建就不可以再被修改,只能删除并重新创建。

1.4. 为物体设置标签

检视窗口的上方显示了标签(Tg)和层级(Layer) 的下拉菜单。

在标装的下技菜单中单击任意.个标签名称,就可以为物体指定该标签了

1.5. 使用标签查找游戏物体

略,详见在脚本中访问其他物体2.3

1.6. 小提示

  • 一个游戏物体只能被指定一个标签
  • 可以用任意一个单词作为标签的名称
    甚至可以用一个很长的词组作为名称
    但是那样非会不太方便,比如在界面中看不到完整的名字

2. 层级

2.1 简介

层级最有用、最常用的地方有:

  • 用来让摄像机仅渲染场景中的一部分物体
  • 还可以让灯光只照亮一部分物体。
  • 用来在进行碰撞检测、射线检测时,从而只让某些物体发生碰撞,让另一些物体不发生碰撞。

2.2 新建层级

单击主菜单的Edit > Project Settings > Tagsand Layers选项,会在检视窗口中打开层级和标签窗口。
这步操作和之前介绍标签时的操作完全一样, 不同的是,在学习标签时我们展开了标签菜单,这里我们要展开层级菜单。
将新的层级User Layer8命名为Player,就建立了一个新的Player层级,序号为8.

2.3 只渲染场景的一部分

层级配合摄像机的剔除遮眾Culling Mas)使用,就可以有选择性地显示某些层级的物体,而不渲染另一些层级的物体。

要做到这一点, 只需要在摄像机中选中需要渲染的层级即可。
单击摄像机的剔除遮罩下拉菜单,打钩的层就是要显示的层。

注意: Unity 中有很多类似这样的下拉菜单,菜单的最上面两项是特殊的:
单击Noting时,所有选项都会被取消勾选,表示全部不选
单击Everyhing 时,则所有选项都会被勾选。
使用这两个快捷选项有助于快速选中必要的层。
比如说,要仅选中Ul层和Player层,就可以先选择Nothing,然后再单独勾选UI层和Player层即可.

UI系统如果采用屏幕空间画布,则不会受摄像机别除遮罩的影响。

2.5 选择性的射线检测

使用层级可以让射线检测忽略某些碰撞体,这种效果也是用“层级”和“遮罩”这两个概念来设置的。

例如,有时需要发射条射线, 仅和Player 层的物体发生碰撞, 而忽略其他层的物体。
Physics.Racast方法用来发射一条射线, 它可以带有一个叫作layerMask 的参数,layerMask是一个利用位标记作为遮罩的参数。

用位(bit)作为标记是二进制相关的一种方法
原理是int型的变量由32个位组成,每个位的值只能是0或1
因此可以根据某个位是0还是1来选中或者忽略某一层

  • 如果layerMask所有的位都是1,那么就会和所有的层发生碰撞。
  • 如果layerMask等于0,那么它就不会和任何层、任何物体发生碰撞。
1
2
3
4
5
6
7
//将1左移8位
int layerMask =1 << 8;
//将layerMask设置为只有从右数第8位是1,其他位是0,则只会和Layer 8 Player层发生碰撞
if (Physics .Raycast (transform.position, Vector3. forward, Mathf. Infinity, layerMask))
{
Debug.Log("The ray hit the player") ;
}

如果是玩家的游戏人物射击发出的检测射线,就恰恰相反,需要和除玩家的游戏人物以外的所有物体发生碰撞,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Update ()
{
//将1左移8位
int layerMask = 1 << 8;
//按位取反,所有值为0的位变为1,值为1的位变为0
layerMask = ~ layerMask;
RaycastHit hit;
//发射射线,Debug. DrawRay用于画出辅助框线
if (Physics.Raycast(transform.position,traform.TransformDirection(Vector3.forward),
out hit, Mathf.Infinity,layerMask))
{
Debug.DrawRay(transform.position,
transform.TransformDirection(Vector3.forward)*
hit.distance,Color.yellow);
Debug. Log("Did Hit");
}
else
{
Debug.DrawRay(transform.position,
transform.TransformDirection(Vector3.forward)*1000
Color.white) ;
Debug.Log("Did not Hit");
}
}

如果在调用Raycast方法时省略layerMask参数,则默认除了Ignore Raycast这层不会被碰撞,其他层都可能发生碰撞。

使用lgnore Raycast层可以专门指定某些物体不受射线检测碰撞。

序号为31的最后一层是特别的,编辑器把它作为预览使用,开发者不要使用这一层,会造成冲突

3. 静态物体

3.1 简介

如果引擎事先知道了某一个物体在游戏进行中是否会移动,那么就可以针对性地应用一系列优化策略。

如果一个物体是静态的,即不会移动的,那么引擎就可以假定它不会受到任何其他物体或者事件的影响,从而预先计算好物体的信息。
比如说,渲染器可以将场景中许多静态物体台并为一个整体,这样就可以通过一次渲染就将它们全部处理完毕,这种做法也被称为批量渲染。

在检视窗口中,每个游戏物体名称的右侧都有一一个静态(Static) 复选框以及一个菜单,它用来指定物体是否是静态的,且可以进一步指定物体 在某些子系统中是否是静态的,还可以独立地设置游戏物体在每个子系统中是否是静态的,这样就可以对物体进行非常细致的优化。

下图是静态标记菜单,可以有针对性地设置物体在每个子系统中是否是静态的。

3.2 子系统的静态特性内容

静态菜单中的Everyhing和Nothing选项分别用于同时启用或禁用物体在所有子系统中的静态特性以便优化。

这些子系统包含如下内容:

名称 作用
Lightmap Static 场景中的高级光照特性
Occluder Static 根据物体在特定摄像机下的可见性,进行渲染优化
Batching Static 将多个物体合并为一个整体进行渲染
Navigation Static 在寻路系统中,将此物体作为静态的障碍物
Off Mesh Link Generation 寻路系统中的网格链接
Reflection Probe Static 反射探针优化

某些子系统与内部渲染方式有较大关联,可以在相关文档中阅读它们的细节。

4.预制体

4.1 简介

在场景中创建物体、添加组件并设置合适参数的操作一开始会令人觉得方便, 但是当场影的用到大量同样的NPC、障碍物或机关时,创建以及设置属性的操作就会带来巨大的麻烦。
复制这些物体看似可以解决问题,但是由于这些物体都是独立的,所以还是需要一个一个单独体改它们。

所以,Unity 提供了预制体这个概念。
它允许事先保存一个游戏物体,包括该物体上挂载的组件与设置的参数。
这样预制体就可以成为模板,可以用这个模板在场景中创建物体。

预制体具有以下两个优点

  • 对预制体文件的任何修改可以立即影响所有相关联的物体

  • 每个物体还可以重载(override)一些些组件和参数, 以实现与模板有所区别的设置

注意:
当你拖曳一个资源文件(比如一个模型)到场景中时,Unity 会自动创建一个新的游戏物体,原始资源的修改也会影响到这些相关的游戏物体。
这种物体看起来像是预制体,但是和预制体是完全不同的,所以不适用下面介绍的预制体的特性。
这种“引用关系”仅仅是与预制体有相似之处。

4.2 使用预制体

创建预制体有两种常用方法:

  • 方法一:
    在工程窗口中的某个文件夹内单击右键,选择Create> Prefab创建一个空白预制体,然后将场景中制作好的某个游戏物体拖曳到空白预制体上。
  • 方法二:
    直接将某个游戏物体从场景拖曳到文件夹中。
    在创建好预制体以后,将另一个游戏物体拖曳到预制体文件上,系统会提示是否替换预制体。

预制体是一个后缀为 .prefab的资源文件。
在层级视图中,所有与预制体关联的游戏物体的名称,都会以蓝色显示(普通物体的名称是以黑色显示的)

编辑器会用粗体字来显示游戏物体中与预制体不一样的独特属性

4.3 通过游戏物体实例修改预制体

与预制体关联的游戏物体,会在检视窗口的上方多出三个按钮:

  • 选择( Select)
    选中与物体相关联的那个预制体,单击后,在工程窗口中会高亮显示该预制体。
    这有助于迅速找到相关的预制体。

  • 回滚(Revert)
    将游戏物体修改过的组件和属性恢复到和预制体一致。
    这个功能用于试验性地修改某些参数以后,将物体恢复到原始状态。

  • 应用(Apply)
    将本物体上修改的那些组件和参数写回到原始的预制体中(但是变换组件的位置信息不会写回预制体)。
    这有助于通过任何一个物体修改预制体,有时会非常方便,特别是在某些预制体只有一个实例的时候。

4.4 预制体实例化

使用Instantiate函数

Instantiate函数实例化是将传入对象的所有子物体和子组件完全复制,成为一个新的对象。
这个新的对象拥有与源对象完全一样的东西,包括坐标值等。

4.4.1 参数

参数名 作用
original 用来做复制操作的对像物体,源对象
position 实例化的对象的位置坐标
rotation 实例化的对象的旋转坐标(旋转四元数)
parent 实例化对象的父对象,在完成实例化函数处理后,实例化对象将是父对象的子对象
instantiateWorldSpace 为TRUE,表示实例化对象相对于世界坐标系的位置(是位置,不是坐标值,比如实例化前在Canvas左上角,实例化后还在左上角)不变,相对于父对象的坐标值变了
为false,表示实例化对象相对于父对象的坐标值不变,但在世界坐标系中的位置变了。

https://blog.csdn.net/qq_29413829/article/details/78934579

4.4.2 重载

![Instantiate函数](./images/Unity中的标签 层级 静态物体/20171229171822891)