Unity一个物体多个标签

共 4071字,需浏览 9分钟

 ·

2021-06-19 09:36

在unity中,我们经常通过给物体添加标签来判断这个物体是不是我们想要的

7ce3c163da9334e77f312d578b1db00d.webp

但是unity默认只能添加一个标签,那如果我们要给一个物体添加多个标签应该怎么办

首先,我们定义一个Tag.cs类,这个类用来存储物体的tag信息

 public class Tags : MonoBehaviour{
     public List<string> tags=new List<string>();
 }

然后创建一个单例类TagManager.cs用来管理tag

 public class TagManager : MonoBehaviour {
    public static TagManager Instance { get; private set; }
    private void Awake() {
       if (Instance == null) {
          Instance = (TagManager) this;
          DontDestroyOnLoad(gameObject);
      }
       else {
          Destroy(gameObject);
      }
    }
 }

TagManager中增加存储tag的list和对应物体的dictionary

 public List<string> tagsList = new List<string>();
 [ShowInInspector]
 public Dictionary<string, List<GameObject>> tagsDictionary = new Dictionary<string, List<GameObject>>();

但是inspector窗口中修改dictionary中的值后,播放时会自动清除数据,所以还要给dictionary赋值

 private void InitTags() {
    int length = tagsList.Count;
    tagsDictionary = new Dictionary<string, List<GameObject>>(length);
    for (int i = 0; i < length; i++) {
       tagsDictionary.Add(tagsList[i], new List<GameObject>());
    }
 }

然后我们通过在inspector窗口修改list来修改物体的taf

cce52b6b917c1c247d46138c53612769.webp


新建一个Extensions.cs,我们在这个类里面写一些扩展方法

 public static class Extensions {
    //包含所有的 tag 返回true
    public static bool HasTag(this GameObject gameObject, params string[] tag) {
       if (gameObject.TryGetComponent<Tags>(out Tags t)) {
          for (int i = 0; i < tag.Length; i++) {
             if (!t.tags.Contains(tag[i])) {
                Debug.Log(gameObject.name+"不存在"+tag+"标签");
                return false;
            }
          }
      }
       return true;
    }
    //给物体增加 tag
    public static void AddTag(this GameObject gameObject, params string[] tags) {
       if (gameObject.TryGetComponent<Tags>(out Tags t)) {
          foreach (var tag in tags) {
             if (!TagManager.Instance.tagsList.Contains(tag)) {
                Debug.Log("增加一个tag:" + tag);
                TagManager.Instance.tagsDictionary.Add(tag, new List<GameObject>());
                Debug.Log(tag + "增加一个物体" + gameObject.name);
                TagManager.Instance.tagsDictionary[tag].Add(gameObject);
            }
             else {
                Debug.Log(tag + "增加一个物体" + gameObject.name);
                TagManager.Instance.tagsDictionary[tag].Add(gameObject);
            }
          }
      }
    }
    //给物体删除tag
 public static void RemoveTag(this GameObject gameObject,params string[] tags) {
 for (int i = 0; i < tags.Length; i++) {
 if (gameObject.HasTag(tags[i])) {
 gameObject.GetComponent<Tags>().tags.Remove(tags[i]);
 Debug.Log(gameObject.name+"移除"+tags+"标签");
 TagManager.Instance.tagsDictionary[tags[i]].Remove(gameObject);
 }
 else {
 Debug.LogWarning(gameObject.name+"不存在"+tags[i]+"标签");
 }
 }
 }
 }

这样像下面这样直接调用即可

 gameObject.AddTag("Player","Tag1");
 gameObject.HasTag("Player","Tag1");
 gameObject.RemoveTag("Player");

最后TagManager.cs中通过标签获取所有物体

 public List<GameObject> FindObjsWithTag(string tag) {
     if (tagsDictionary.ContainsKey(tag)) {
         return tagsDictionary[tag];
    }
     Debug.Log("不存在标签为" + tag + "的物体");
     return null;
 }

测试一下

创建两个挂有Tags.cs脚本的物体

 public class Tags : MonoBehaviour{
     public List<string> tags=new List<string>();
     void Start() {
         gameObject.AddTag(tags.ToArray());
         gameObject.HasTag("Player");
    }
     void Update(){
         if (Input.GetKeyDown(KeyCode.A)) {
             gameObject.RemoveTag("Player","tag1");
        }
    }
 }

两个物体具有的tag分别为tag1tag2tag1

TagManager只有tag1

39d06f96167dc552046fde7396195a21.webp

运行

9623cd4f109a1cf9cb87f71bbad79d04.webp

但是这样当退出Play模式后,List中的数据会被清空,所以可以使用ScriptableObject进行持久化存储也可以使用Odin等插件直接对字典进行序列化

使用ScriptableObject

新建一个TagsAsset.cs

 [CreateAssetMenu]
 public class TagsAsset : ScriptableObject{
     public List<string> tags=new List<string>();
 }

将原先代码中tagsList相关的代码修改为tagsAsset.tags并修缮一下即可

使用Odin

导入Odin插件,使TagManager继承自SerializedMonoBehaviour

 [NonSerialized, OdinSerialize]
 public Dictionary<string, List<GameObject>> tagsDictionary = new Dictionary<string, List<GameObject>>();

关于Odin的进阶可以看https://zhuanlan.zhihu.com/p/268324619


浏览 99
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报