Is there a way to assign multiple tags to a single GameObject?

I need multiple tags on a GameObject. I am grouping GameObjects by functionality. In this case I have tags for Room1MonsterCollider, Room1MonsterRigid, and NPCRoom1Monster. I need a single tag that I can use to identify all NPCs, regardless of room, and without fore-knowledge of all tags. So, having the ability to tag an NPC as both “NPC” and “NPCRoom1Monster” is highly desirable when I want to get a list of all NPCs in the game.

You have other ways around this. You can either use verbose tags and parse out the tags you want or use child objects.

Child Objects

Use child objects under your object and apply unique tags to the children then search for the tag you want. Then do something with the parent.

Verbose Tags

Or with your current tags you could use:
tag.Contains()
Then search for the individual tags. You could even go as far as making them more readable using a separator like ‘-’ or ‘_’.

For example lets use one of your tags “NPCRoom1Monster”.

We could get NPC’s with:

tag.Contains("NPC")

You can get Room1 with:

tag.Contains("Room1")

Just have to find what works for your game.

Just a note, this appears to be a duplicate of: Is it possible to have multiple tags (or the like) on one object? - Questions & Answers - Unity Discussions

oh wow! all this time i thought you could (but never tried) i thought thats what tags were for. Why would Unity not do this?

@plbyrd

Yes you can, by simply replacing Unity’s tag system with your own. Very simple.

Best practice is to always avoid using GameObject.Find(). Here’s an example of how you could write a tag replacement system (to show how easy it is).

An easy replacement is to just use a FREE system like Tag Frenzy.

Another option is to make your own system. Still pretty easy, and also extendable.


public class Tags : Monobehaviour
{
    public string[] myTags;

    bool hasTag(string tagToCheck)
    {
        foreach(string tag in myTags) //Can replace foreach with 'for loop'
        {
            if(tag == tagToCheck)
            {
                return true;
            }
        }
        return false;
    }
}

Alternatively you could replace the string with enum TagType

public enum TagType
{
    Item,
    NPC,
    Player,
    Object
}
//Tag.cs
public TagType[] myTags;
bool hasTag(TagType tagToCheck)
//etc.

If you want to be like Unity, you could also still use this system by simply introducing more code to do other functions, like FindGameObjectWithTag, which is much faster than GameObject.Find() because Unity stores all gameobjects with tags.


public static class TagSystem
{
    public static Dictionary<string, List<Gameobject>> allTaggedGameObjects;

    List<GameObject> FindObjectsWithTag(string tagToFind)
    {
        if(allTaggedGameObjects.ContainsKey(tagToFind)
        {
            return allTaggedGameObjects[tagToFind];
        }
        else { Debug.LogError("No Objects with Tag " + tagToFind + " found."); return null; }
    }

    GameObject FindObjectWithTag(string tagToFind) //Return the first tag found
    {
        if(allTaggedGameObjects.ContainsKey(tagToFind)
        {
            return allTaggedGameObjects[tagToFind][0];
        }
    }

    static void AddGameobjectTags(Tag tagScript)
    {
        foreach(TagType tag in tagScript.myTags)
        {
            if(allTaggedGameObjects.ContainsKey(tag)
            {
                allTaggedGameObjects[tag].Add(tagScript.gameObject);
            }
           else
           {
                //Add new tag & new gameobject list to dictionary, etc.
           }
        }
    }
}

//Tag.cs
void Awake()
{
    TagSystem.AddGameobjectTags(this);
}

Something like that, anyway. Pretty easy stuff to simulate Unity’s tag API.


Note: I’m not an expert, so I’m always open to improvement. I’d love for anyone who believes this is inefficient, to comment as to why (I’m trying to build a collection of solid ‘best practices’ or ‘systems’ which users could find & use.) so I can explain any caveats.

No you can’t.

The way I’d approach this is to make all my NPCs have a component that derived from an abstract “NPC” class. Then use FindObjectsOfType<NPC>() to grab all the NPCs in the scene.

I would go for either a branched system so the NPCRoom1 tag implicates that it is a NPC or if that is not enough the only way is to build something custom. From the top of my head I would be using a Dictionary> in a kind of observer pattern, where all the GameObjects register themselves.