Unity中通过代码添加Layer层和Tag层

本文介绍了一种在Unity中自动添加Tag和Layer的方法,解决了导入Package后需手动设置的问题。通过代码实现物体Layer的精确匹配,避免了层级名称不一致导致的错误。适用于不同Unity版本。

在导入别人的package包的时候,tag信息和layer信息导不进来。还得手动一个个添加,一个个设置。很是麻烦。

在网上看了一下别人写的添加layer层的文章,但是里面的代码已经不适合现在版本的unity了。像雨松MOMO

Unity3D研究院之脚本自动添加tag和Layer。这给unity版本很早了。整合了一下各种版本,测试可以使用,代码如下:

场景中的物体的layer 需要用代码去设置。不然即使layer添加进去了,但是有可能出现匹配不正确。而Tag值则不会出现这个问题。

思考了一下,unity 在匹配Tag值得时候,是遍历TagList,找到对应的Tag设置。而unity在设置Layer层的时候,则是通过层级来设置的,即使你层级里面对应的名字不正确。 所以最好是通过代码设置物体的layer层级。

 private static string[] _testLayerArr = { "LayerOne", "LayerTwo", "LayerThree" };
    private static string[] _testTagArr = { "TagOne", "TagTwo", "TagThree" };

    private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        foreach (string s in importedAssets)
        {
            if (s.Equals("Assets/Test/LayerTest/ExportLayer.cs"))
            {
                foreach (string tag in _testTagArr)
                {
                    AddTag(tag);
                }
                foreach (string layer in _testLayerArr)
                {
                    AddLayer(layer);
                    
                }
                return;
            }
        }
    }  

    static bool IsHasLayer(string layer)
    {
        SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/Tagmanager.asset"));
        SerializedProperty it = tagManager.GetIterator();
        while (it.NextVisible(true))
        {
            if (it.name == "layers") 
            {
                for (int i = 0; i < it.arraySize; i++)
                {
                    SerializedProperty sp = it.GetArrayElementAtIndex(i);
                    if (!string.IsNullOrEmpty(sp.stringValue))
                    {
                        if (sp.stringValue.Equals(layer))
                        {
                            sp.stringValue = string.Empty;
                            tagManager.ApplyModifiedProperties();
                        }
                    }
                }
            }
        }
        for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.layers.Length; i++)
        {
            if (UnityEditorInternal.InternalEditorUtility.layers[i].Contains(layer))
                return true;
        }
        return false;
    }

    static bool IsHasTag(string tag)
    {
        for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.tags.Length; i++)
        {
            if (UnityEditorInternal.InternalEditorUtility.tags[i].Contains(tag))
                return true;
        }
        return false;
    }

    /// <summary>
    /// 添加layer
    /// </summary>
    /// <param name="layer"></param>
    private static void AddLayer(string layer)
    {
        if (!IsHasLayer(layer))
        {
            SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
            SerializedProperty it = tagManager.GetIterator();
            while (it.NextVisible(true))
            {
                if (it.name == "layers")
                {
                    for (int i = 0; i < it.arraySize; i++)
                    {
                        if (i == 3||i==6||i==7)
                        {
                            continue;
                        }
                        SerializedProperty dataPoint = it.GetArrayElementAtIndex(i);
                        if (string.IsNullOrEmpty(dataPoint.stringValue)) 
                        {
                            dataPoint.stringValue = layer;
                            tagManager.ApplyModifiedProperties();
                            return;
                        }
                    }
                }              
            }
        }
    }

    /// <summary>
    /// 添加tag
    /// </summary>
    /// <param name="tag"></param>
    private static void AddTag(string tag)
    {
        if (!IsHasTag(tag))
        {
            SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
            SerializedProperty it = tagManager.GetIterator();
            while (it.NextVisible(true))
            {
                if (it.name == "tags")
                {
                    for (int i = 0; i < it.arraySize; i++)
                    {
                        SerializedProperty dataPoint = it.GetArrayElementAtIndex(i);
                        if (string.IsNullOrEmpty(dataPoint.stringValue))
                        {
                            dataPoint.stringValue = tag;
                            tagManager.ApplyModifiedProperties();
                            return;
                        }
                    }
                }
            }
        }
    }

 

<think>我们正在讨论Unity中的TagLayer。根据引用内容,我们可以总结如下:1.**Tag**:-每个游戏对象只能设置一个Tag。-在Inspector视图中通过下拉菜单设置。-通常用于在脚本中通过字符串标识对象,例如:`gameObject.tag=="Player"`。-内建的Unity组件没有暴露Tag的设置字段,主要在自定义脚本中使用。-运行时创建Tag需要编辑TagManager.asset(通常不推荐运行时动态创建,但可以通过特殊方法实现,如引用[4]所示)。2.**Layer**:-每个游戏对象只能设置一个Layer。-在Inspector视图中设置,但Layer在CameraLight的CullingMask中可以选择多个(通过LayerMask)。-用于渲染(如Camera的CullingMask决定哪些被渲染)物理碰撞(Physics设置哪些之间可以碰撞)。-创建Layer在Edit>ProjectSettings>TagsandLayers中完成,在UserLayers下添加(如引用[1]所示)。-在代码中,Layer使用整数索引(0~31)或通过LayerMask类来处理。**区别**:-Tag是字符串标识,用于逻辑判断(如识别玩家、敌人等)。-Layer是整数位掩码,主要用于渲染、光照物理碰撞的过滤。**使用方式**:**Tag的使用**:在脚本中,我们可以通过检查Tag来执行逻辑:```csharpif(gameObject.tag=="Player"){//玩家相关逻辑}```或者使用`CompareTag`方法(更高效):```csharpif(gameObject.CompareTag("Player")){//...}```**Layer的使用**:1.**设置对象的Layer**:```csharpgameObject.layer=LayerMask.NameToLayer("Enemy");```2.**在Camera中设置CullingMask**(只渲染指定):```csharpcamera.cullingMask=(1<<LayerMask.NameToLayer("Player"))|(1<<LayerMask.NameToLayer("Enemy"));```3.**物理碰撞过滤**:在Edit>ProjectSettings>Physics中设置之间的碰撞矩阵。在代码中,可以使用LayerMask来忽略某些的碰撞:```csharpvoidOnCollisionEnter(Collisioncollision){//只处理特定的碰撞if(((1<<collision.gameObject.layer)&enemyLayerMask)!=0){//处理与敌人的碰撞}}```或者使用射线时指定:```csharpintlayerMask=1<<LayerMask.NameToLayer("Enemy");RaycastHithit;if(Physics.Raycast(transform.position,transform.forward,outhit,Mathf.Infinity,layerMask)){//只检测Enemy}```**运行时创建TagLayer**:引用[4]提到可以在运行时创建TagLayer,但这通常不推荐,因为需要修改项目设置(TagManager.asset),而且可能会引起序列化问题。如果确实需要,可以通过序列化系统来修改,但要注意保存。总结:Tag用于对象标识,Layer用于对象分类(渲染、物理等)。两者都是对游戏对象的分类方式,但使用场景机制不同。§§相关问题§§1.Unity中如何设置两个游戏对象之间的碰撞忽略?2.如何在运行时动态改变一个游戏对象的Layer?3.TagLayer在性能上有什么需要注意的地方?4.如何通过脚本获取所有使用了某个Tag的游戏对象?</think>### UnityTagLayer的作用与使用方式 #### **1. Tag的作用与使用** - **作用**: Tag是**字符串标识符**,用于在脚本中快速识别特定类型的游戏对象(如玩家、敌人、道具)。每个游戏对象只能设置一个Tag[^2]。 - **使用方式**: - **设置Tag**: 在Inspector窗口中选择对象 → Tag下拉菜单 → 选择预设Tag或创建新Tag[^1]。 ```csharp // 代码设置Tag gameObject.tag = "Player"; ``` - **检测Tag**: 在脚本中通过`CompareTag`方法高效检测: ```csharp if (other.gameObject.CompareTag("Enemy")) { Destroy(gameObject); // 碰撞到敌人时销毁 } ``` - **运行时创建Tag**: 需修改`TagManager.asset`文件(需特殊处理,非直接API)[^4]。 #### **2. Layer的作用与使用** - **作用**: Layer是**位掩码分类系统**(0~31),用于控制渲染、物理碰撞射线检测的过滤。例如: - 摄像机仅渲染指定(`Camera.cullingMask`)[^2] - 物理引擎忽略特定间的碰撞(`Physics.IgnoreLayerCollision`) - **使用方式**: - **创建Layer**: `Edit > Project Settings > Tags and Layers` → 在`Layers`列表添加自定义(如"Player", "Enemy")[^1]。 ![Layer设置界面](https://docs.unity3d.com/uploads/Main/TagsLayersSetup.png) *(Unity官方文档示意图)* - **设置对象Layer**: ```csharp // 代码设置Layer gameObject.layer = LayerMask.NameToLayer("Enemy"); ``` - **过滤应用**: ```csharp // 摄像机只渲染Player camera.cullingMask = 1 << LayerMask.NameToLayer("Player"); // 射线检测忽略UI int ignoreUIMask = ~(1 << LayerMask.NameToLayer("UI")); Physics.Raycast(ray, out hit, Mathf.Infinity, ignoreUIMask); ``` #### **3. TagLayer的关键区别** | **特性** | **Tag** | **Layer** | |----------------|----------------------------------|-------------------------------| | **标识类型** | 字符串 | 整数位掩码(32上限) | | **对象绑定** | 1个对象1个Tag | 1个对象1个Layer | | **主要用途** | 逻辑识别(如敌我判断) | 系统级过滤(渲染/物理) | | **多选支持** | ❌ 仅单选 | ✅ 可多选(如摄像机渲染多) | | **性能影响** | 字符串比较较低效 | 位运算高效 | | **动态创建** | 需编辑TagManager.asset[^4] | 运行时无法动态创建新 | #### **4. 最佳实践** - **Tag适用场景**: 需要精确识别对象类型时(如`if (obj.CompareTag("Bullet"))`)。 - **Layer适用场景**: 需要批量处理对象集合时(如禁用所有"UI"的物理碰撞)。 - **混合使用示例**: ```csharp // 只对"Enemy"Tag且位于"Damageable"的对象造成伤害 void DealDamage(GameObject target) { if (target.CompareTag("Enemy") && target.layer == LayerMask.NameToLayer("Damageable")) { target.GetComponent<Health>().TakeDamage(10); } } ``` > **注意**:Layer的位掩码特性使其在性能敏感场景(如大量射线检测)中优于Tag[^3]。避免在运行时频繁修改TagLayer,可能触发物理引擎重建。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值