【Unity学习笔记】第十三 · tag与layer(运行时创建tag和layer)

发布于:2024-04-23 ⋅ 阅读:(20) ⋅ 点赞:(0)

参考:

注:本文使用Unity版本是2022.3.23f1

转载引用请注明出处:🔗https://blog.csdn.net/weixin_44013533/article/details/137978498
作者:CSDN@|Ringleader|

Tag

创建tag

手动创建可以在对象tag上或者project settings上创建,
在这里插入图片描述
可以用gameobject的tag属性赋值和修改。注意使用标签前,需要在标签和层管理器中声明它们。否则会报错:“Tag: xxxx is not defined.

gameObject.tag = "Player";

也可以用代码在运行时添加tag:

public void AddTag(string tagname)
{
    UnityEngine.Object[] asset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset");
    if ((asset != null) && (asset.Length > 0))
    {
        SerializedObject so = new SerializedObject(asset[0]);
        SerializedProperty tags = so.FindProperty("tags");

        for (int i = 0; i < tags.arraySize; ++i)
        {
            if (tags.GetArrayElementAtIndex(i).stringValue == tagname)
            {
                return;     // Tag already present, nothing to do.
            }
        }
        tags.InsertArrayElementAtIndex(0);//可能会打印提示信息”Default GameObject Tag: xxx already registered“
        tags.GetArrayElementAtIndex(0).stringValue = tagname;
        so.ApplyModifiedProperties();
        so.Update();
    }

注意Unity 包含一些未出现在标签管理器中的内置标签:
在这里插入图片描述

还有一种运行时插入tag的方式:

UnityEditorInternal.InternalEditorUtility.AddTag("xxx");

注意运行时添加的tag在编辑态并不会保留。

手册上提示的“注意:您不应通过 Awake() 或 OnValidate() 方法设置标签。这是因为组件唤醒的顺序是不确定的,因此可能导致意外行为,例如标签在唤醒时被覆盖。如果尝试执行此操作,Unity 将生成一条警告:“SendMessage cannot be called during Awake, CheckConsistency, or OnValidate”。”测试下来并不会提示。

参考:

通过tag查找对象
  • FindWithTag 返回一个属于此tag的激活对象,找不到则返回null,tag不存在则报异常
  • FindGameObjectsWithTag 返回全部属于此tag的激活对象,没找到则返回空数组,tag不存在报异常
private void Awake()
    {
        GameObject o = GameObject.FindWithTag("MyTag");
        GameObject[] os = GameObject.FindGameObjectsWithTag("MyTag");
        Debug.Log("FindWithTag: " + o?.gameObject.name);
        Debug.Log("FindGameObjectsWithTag: " + string.Join(", ", os?.Select(obj => obj.name)));
    }

注意: 这两个方法都无法确定找到的是哪个对象,数组中对象顺序不定,也无法找到非激活的对象

Layer

层 (Layer)提供一种类似tag但不同的方式在某些内置操作(例如渲染或物理碰撞)中包括或排除GameObject 组。
在这里插入图片描述
在这里插入图片描述
创建同样需要用tag&layer编辑器(TagManager)。也可以运行时创建:

private void Awake()
    {
        AddLayer("myLayer", 0);
        AddLayer("myLayer", 1);
        AddLayer("myLayer", 2);
        AddLayer("myLayer", 4);
        AddLayer("myLayer", 5);
        AddLayer("yeah30", 30);
        AddLayer("yeah31", 31);

        gameObject.layer = 30;
        int LayerIgnoreRaycast = LayerMask.NameToLayer("yeah30");
        gameObject.layer = LayerIgnoreRaycast;
        Debug.Log("Current layer: " + gameObject.layer);
    }
    
void AddLayer(string layerName, int index)
  {
      int[] builtInIndex = { 0, 1, 2, 4, 5};
      if (builtInIndex.Contains(index))
      {
          Debug.Log("can't use built-in layer index:" + index);
          return;
      }
      UnityEngine.Object[] asset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset");
      if ((asset != null) && (asset.Length > 0))
      {
          SerializedObject so = new SerializedObject(asset[0]);
          SerializedProperty tags = so.FindProperty("layers");//注意这个TagManager.asset里属性名称可能不一样,注意Unity版本

          for (int i = 0; i < tags.arraySize; ++i)
          {
              if (tags.GetArrayElementAtIndex(i).stringValue == layerName)
              {
                  return; // Tag already present, nothing to do.
              }
          }

          tags.InsertArrayElementAtIndex(index); 
          tags.GetArrayElementAtIndex(index).stringValue = layerName;
          so.ApplyModifiedProperties();
          so.Update();
      }
  }

在这里插入图片描述
注意:这个TagManager.asset里属性名称可能不一样,注意Unity版本

tag、layer的区别

在这里插入图片描述

  • 在设计用途上,layer更面向cameral render physic这种系统级别处理差异的地方,比如相机遮挡剔除、光照剔除、射线或碰撞检测等,tag的话更针对代码逻辑上,比如区分敌人伙伴,小怪和精英等等。
  • tag使用的是字符串,注意常量的使用,避免拼写错字符。

参考:

总结

本文主要搜集并验证运行时添加tag和layer的方法。
(本来不准备写博客的,但又寻思都搜集了些,胡乱贴上就是了,也算一篇文章了,也正好许久没了。但一写上就需要负责,很多地方都需要仔细验证,不过也算值得,本来tag我试过可以后就以为layer也一样,没想到这么点小改动我都会忙碌许久,就像这小小的tag和layer,手册上一带而过,不动手试试还真不知道这么多问题。)