在unity中,tag是一个好东西,我们可以用tag来区分物体,也可以通过tag来快速地查找物体。但是美中不足的是,tag是一个字符串string。为什么说美中不足呢?
因为假如我们在一个脚本里面想要有一个Tag字段,都只能定义一个string字段。
using UnityEngine; public class TagObjFinder : MonoBehaviour { public string Tag; public GameObject[] FindGos { get; private set; } public void Start() { FindGos = GameObject.FindGameObjectsWithTag(Tag); } }
而这样的话,在编辑器中,就非常不方便填写,也非常容易出错。
有一些人会采用CustomEditor的方法,利用TagField可以非常好地使用Tag下拉框。这种通过自定义属性面板的方法其实并不赞成,因为总不可能给每一个需要用到tag的脚本都专门给它写一个CustomEditor。
而第二个原因是在代码中使用了大量表示tag的string,非常不优雅,查找和维护都相当不方便。比如:经常看到GameObject.FindGameObjectsWithTag(“Player”)或者是if(gameObject.tag=="GameController”);这样的代码。
那么有人也想到办法,就是手动定义,const所有的tag。比如
public const string TagPlayer=”Player”;
public const string TagMainCamera=”MainCamera”;
确实这是一个方法。通过查找const变量可以找到所有的引用,非常方便。可惜的是,在属性面板中,依然需要手动填写。
既然const不行的话,是不是可以使用枚举呢?当然可以,而且非常优雅。属性面板中还能选择,非常适合。
public enum EmTag { Untagged, Respawn, Finish, EditorOnly, MainCamera, Player, GameController, }
我们改写一下TagObjFinder
using UnityEngine; public class TagObjFinder : MonoBehaviour { public EmTag Tag; public GameObject[] FindGos { get; private set; } public void Start() { FindGos = GameObject.FindGameObjectsWithTag(Tag.ToString()); } }
不过有一个麻烦的就是,如果我在unity中增加了一个tag,就需要增加在代码中一个枚举值。这时候,unity的易扩展性就发挥出来了,我们完全可以自动生成这个EmTag枚举的代码。
using System.IO; using System.Text; using UnityEditor; using UnityEditorInternal; using UnityEngine; public class TagEnumGenarator : MonoBehaviour { [MenuItem("Tools/GenTagEnum")] public static void GenTagEnum() { var tags = InternalEditorUtility.tags; var arg = ""; foreach (var tag in tags) { arg += " " + tag + ", "; } var res = "public enum EmTag { " + arg + "} "; var path = Application.dataPath + "/Tool/EmTag.cs"; File.WriteAllText(path, res, Encoding.UTF8); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } }
通过InternalEditorUtility.tags获取到unity中已有的所有tag,然后通过File.WriteAllText方法写入到一个cs文件中,这里把这个文件EmTag.cs放在了”Assets/Tool/”下。
编译完成,ok。这样只要增加tag的时候,点击一下菜单上的Tools->GenTagEnum就可以同步代码了。然后愉快地抛弃string tag,快乐地使用enum tag。