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

但是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

新建一个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分别为tag1,tag2和tag1
TagManager只有tag1

运行

但是这样当退出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
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

评论(0)