Unity - LayerMask简析

本文简述了LayerMask的定义,后通过项目实战充分解析 LayerMask中的GetMask、LayerToName、NameToLayer 等函数的使用方法及其注意事项。
项目地址:3D坦克大战 - SouthBegonia

LayerMask 定义

用来表示32个Layer层级的位掩码,类型为Int32,。前面8个是引擎使用的,后面24个供开发人员使用的。通过LayerMask我们可以实现诸多类似 层判定、层限制、层检测 的方法。的我们可以在Edit->Project Setting->Tags and Layers->Layers 中看到这32层(见下图)

LayerMask 方法

GetMask

函数原型:public static int GetMask(params string[] layerNames)

功能:传入一个图层名称列表,返回这个图层列表的等效图层蒙版。此处大家再回看上面的函数原型可能会产生疑问:何为等效图层蒙版,为何它的类型为int?它的用处是什么?

解析:我们先Debug看看上图中第1层和第5层看看:

//Way1:GetMask方法
Debug.Log(LayerMask.GetMask("Default");	       -->1
Debug.Log(LayerMask.GetMask("Default", "UI"));	-->33

一个非常奇怪的数据,但是我们转换成二进制呢?

1 --> ‭0001‬
33 --> ‭0010 0001‬

不难发现,这是Int32的位掩码,即LayerMask,第1、5位数为1表示开启了这两个层。因此可以说:等效图层蒙版 == 启用/关闭某几层的LayerMask位掩码, 1表示开启,0表示关闭。此外我们还可以使用位运算实现等效图层蒙版:

//Way2:位操作方法
LayerMask layer1 = (1 << 0);
LayerMask layer2 = (1 << 0) | (1 << 5);
Debug.Log(layer1.value);	  -->1
Debug.Log(layer2.value);	  -->33

//等效于:
LayerMask layer3 = LayerMask.GetMask("Default","UI");
Debug.Log(layer3.value);	  -->33

//其他位操作方法:
LayerMask layer4 = (0 << 5);  	 //关闭索引为5的层
LayerMask layer5 =  ~(1 << 5);     //打开除了索引为5的层之外的层

那么怎么落实到项目中呢?在此提供一个项目示例(地址在文章首):我们在开发坦克大战游戏,有红蓝绿三方阵营,我们想让各自阵营的炮弹不伤害到友军,这时我们就需要用到LayerMask:

//设置LayerMask的类:
public class LayerManager : MonoBehaviour
{
    public static int blueLayer = 10;
    public static int greenLayer = 11;
    public static int redLayer = 12;

	//传入玩家所在Team的结构体变量,返回敌人所在的图层蒙版
    static public LayerMask GetEnemyLayer(Team team)
    {
        LayerMask mask = 0;
        switch (team)
        {
            case Team.Blue:
                mask = (1 << redLayer) | (1 << greenLayer);     //开启redLayer层和greenLayer层
                break;
            case Team.Green:
                mask = (1 << redLayer) | (1 << blueLayer);
                break;
            case Team.Red:
                mask = (1 << blueLayer) | (1 << greenLayer);
                break;
        }
        return mask;
    }
}

//炮弹脚本的碰撞检测片段:
public void OnCollisionEnter(Collision collision)
{
	//射线检测球形范围内enemyLayers层敌人的collider
	Collider[] cols = Physics.OverlapSphere(transform.position, explotionRadius, enemyLayers);

	//炮弹仅对敌人阵营(敌人所在图层)造成伤害
}

//机理概述:
//1. 通过传入坦克自身所在阵营信息如蓝方阵营到GetEnemyLayer(),得到敌人红绿阵营的 layermask 并设置为 enemyLayers
//2. 我们在发射出的炮弹的脚本中就通过该 enemyLayers 限制了仅能检测到敌方layer层的碰撞体
//3. 实现炮弹对敌伤害而友军安全

LayerToName / NameToLayer

函数原型:public static string LayerToName(int layer)public static int NameToLayer(string layerName)

功能:将索引值k转换为第k层的名称、将第k层的名称转换为k索引值

示例:

Debug.Log(LayerMask.NameToLayer("Blue"));	-->10
Debug.Log(LayerMask.LayerToName(10));	    -->Blue

//检测物体是否在某Layer
if (gameObject.layer == LayerMask.NameToLayer("Default"))
	Debug.Log("Yes!");

总述

LayerMask是Unity中 操控Layer层的类,我们在使用时需要注意数据类型转换,其用法常体现在物理检测、射线检测

关于射线检测可移步博主拙作:Unity射线检测 - SouthBegonia

参考

posted @ 2019-11-14 19:54  SouthBegonia  阅读(4472)  评论(0编辑  收藏  举报