Why does Unity only support one tag per gameobject?

Is it a technical issue? Multiple tags would make life so much easier when scripting. This is so basic I’m astonished that unity is at version 5+ and something like this still needs a workaround.

There are often better solutions than tags. What is exactly your use case where you would like to have more than one tag per game object?

1 Like

It would be nice to have multiple tags. Or subtags, like “dog” being a subtag of “animal”.

For now you can have child objects with tags, you can search the tag and get the parent.

You can also search by script, using GameObject.FindObjectsOfType , which often can be more practical.

3 Likes

Lets say I make an RPG with enemies: subcategory: orcs, goblins, trolls … Then there are classes: shaman, warrior, defender …

Lets say I want to give all enemies +10 health per lvl of the Player I use the tag enemy, but what if I only want it to affect all orcs, or just the shamans like the troll shaman, the goblin shaman etc. I’ll have to use my own tagging system even though unity already has one.

Or when placing units randomly / world generation, item placement … The are so many possibilities to use the tags.

This is pretty much basic object oriented coding, stuff every beginner learns.

1 Like

You may have an Enemy class which e.g. has an enum for the subcategory and another one for the classes (shaman, …). Like that, you can always have the required information available, without the need to use tags at all.

Not sure how this is related to object oriented coding.

1 Like

What is the tag feature for then? Aren’t the tags for sorting, applying changes, etc.? There is that tag feature in the gui, why would I want to create classes in script files if I could just tag eveything comfortably from the gui?

Rephrased: The tags could be used to create classes.

There’s asset on asset store.

You can also write your own string-based object with multi-tag support. It is fairly simple.

1 Like

I just add empty children with a simple script to refer finders to their parents.

Because tags have limited practical usefulness. Interfaces/inheritance/polymorphism is proper way to go. Tagging an enemy as an orc means absolutely nothing. Class Orc that inherits from Enemy (or whatever) is actually usable and practical.

7 Likes

This all the way. A lot of people abuse the tag system and to a greater degree, the layer system.

I always try to minimize my use of tags. I only use them when there is absolutely no way to distinguish certain objects without it. Multiple inheritance is just kind of a basic rule with OOP.

Start with your most basic class type and then derive each base class from there. Tags are good for filtering objects when you want to collect information from a scene at the start of a level. I wouldn’t use them for anything other than that.

3 Likes

Using tags is string based programming. String based programming is bad. The fact that Unity implements tags at all is simply to make the engine more accessible to newer users that are not familiar with programming.

If you still want multiple tags, then implementing it yourself is trivial. Simply create a MultiTag component with a HashSet to store tags. Then use a static helper method that will call GetComponent and check for the appropriate tag. Throw in appropriate responses for null checks and check the actual GameObject.tag and you are good to go.

1 Like

It doesn’t support it because it’s not needed. The case you described could literally be a textbook example on polymorphism. :wink:

2 Likes

It is probably a better idea to make custom component instead of searching through children every time.

HashSet doesn’t serialize, as far as I know.
You’ll need to override ISerialCallbackReceiver, and dump contents of the hash into List or something similar.

WIth small number of tags and infrequent updates you could even go with flat array and binary search if you wanted.

1 Like

I usually do but my code-fu is weak so sometimes I just take the easy route.

Unity’s tag implementation is not good, that doesn’t mean that a tag based approach is bad. Almost any type of application or game has cross cutting concerns which are separate to the object hierarchy (often called aspects).

The component model promoted by Unity can address this but it is not an elegant solution. Having to create a class with no functionality just because I want to be able to identify several disparate objects as having a shared aspect is far from ideal. Pushing every potentially shared aspect up to some top level class inherited by every component is not great either (long complex code, violates separation of concerns, etc).

More to the point its easy for level and game designers to add and change tags, not so easy for them to create new classes and refactor the object hierarchy.

The ability to quickly find objects by tags, to filter tag results and to support multiple tags with inheritance would enable some elegant code whilst simultaneously enhancing the usability for designers.

2 Likes

Searching by components is better in a game, but in an editor multiple tags per object are useful. That’s what tagging originally was for anyway - a method that doesn’t limit organisation to folders.

I never use tags. Marker classes are the way to go. Out of the box you get:

  • To have as many as you want.
  • To add extra information to them.
  • Support for Inheritance/polymorphism.
  • More robust find/search.

Having no methods is not the same as having no functionality. The functionality it provides is that of describing your “aspect”.

2 Likes

Quite commonly (at least for me) No Functionality is used informally to describe a class that has no methods, but better yet lets substitute ‘a class with no methods, properties or fields’.

If you use Components purely for assigning an aspect to a GameObject then you are using Components as a tag implementation. Tagging is not orthogonal to inheritance, multiplicity, etc.

If you start to put methods/properties on these things they become conceptually different as you start to get a much tighter coupling between declaring membership and behaviour. This can be a good trade-off, but not always.


EDIT: Just to be clear I’m not saying OO is bad, or component-based design is bad. I’m just saying that there are many different approaches to a problem, and often more than one is suitable. There are some nice things that come out of a tag based approach which I hope I demonstrate below.

Its really hard to explain this succinctly but let me try and illustrate with an example the problem that I think tagging helps to solve. If you wanted to name the problem you might call it “Fast-moving domain model causes frustration for designers and work for developers” :slight_smile:

Imagine fantasy game where characters have a race and we want to use this race to determine to whom we apply a spell effect to character:

Character {
  public Race Race  {get};
}

Now we realise that NPC’s have a race too:

Mob {
  public Race Race  {get};
}

Character: Mob;

NPC Mob;

As our game grows we realise that mobs also have an alignment (GOOD/EVIL) which can affect spells too:

Mob {
  public Race Race  {get };
  public Alignment Alignment {get };
}

Then we realise objects can also have an alignment (evil sword for example):

FantasyObject {
  public Alignment Alignment {get };
}

Mob : FantasyObject {
  public Race Race  {get };
}

But then we realise some object don’t have an alignment, spells that affect good/evil don’t apply. We could add NONE or NEUTRAL but in our game character MUST be good or evil so having a third value doesn’t match our game. So instead we adopt an interface (we keep FantasyObject because it has grown to have a lot of other shared properties):

IAligned {
  Alignment Alignment {get};
}

Mob : FantasyObject, IAligned {
  public Race Race  {get };
  public Alignment Alignment {get };
}

AlignedObject : FantasyObject, IAligned {
  public Alignment Alignment {get };
}

FantasyObject {
  public string name;
  public string uniqueId;
  // Etc
}

And our Spell method (after multiple rewrites to match the changing model) ends up looking something like:

DoSpell (SpellData spell) {
  var targetObjects = objectsInSpellRadius;
  if (spell.Race) targetObjects = targetObjects.Where(o=> o is Mob && ((Mob)o).Race == race);
  if (spell.Alignment) targetObjects = targetObjects.Where(((IAligned)o).alignment == alignment)
  targetObjects.ForEach(target => Damage(target));
}

These classes and methods have been refactored multiple times through our journey, and this work requires developers (i.e. not designers).


Now image the tag version, there’s no code changes or refactoring. Designers can create tags assign them to objects and add them to spell data without developer involvement just based on the one simple initial implementation:

DoSpell (SpellData spell) {
  var targetObjects = objectsInSpellRadius;
  objectsInSpellRadius.FilterByTags(spell.targetTags);
  targetObjects.ForEach(target => Damage(target));
}

EDIT: And yes you can solve the above with components and a little reflection code. With a bit of editor code to automate it becomes quite a nice solution (I’ve got one floating about that does exactly this). But as mentioned in my view thats just using component as a tag implementation.

1 Like

Absolutely. I perhaps should have said that I never use the built-in GameObject tag implementation.

I definitely see what you’re getting at and agree that there’s more than one way to approach things and that things can be open to preference. I was simply sharing how I approach things. Still, considering marker classes/interfaces/components, I’m not sure how tags are necessarily an improvement in some of the examples.

For instance, while I see the problem with the Alignment marker in this case, I don’t see how it’s solved or improved with tags - you could still add a NEUTRAL tag, or no tag, or multiple tags (some of which the marker class approach could solve for you).

1 Like

If alignment is a string then its half way to being an aribitrary tag anyway :slight_smile:

The main difference I see is that the designer is considered the owner of tags.


I guess this is pretty similar to a discussion of static vs dynamic typing ( or any other of these type of issues :slight_smile: ).

As with most of these things my view is that although I may have a preference for a certain type of solution to a certain type of problem (based on what has previously worked for me), I try to be very open to picking what works for the team/project/situation.