- Home /
Is it possible to have multiple tags (or the like) on one object?
Here's my situation. I'm coding scripts for a turn-based game that has an initiative system. Sometimes I need all of the planes to go first, sometimes the ground units, sometimes all the enemies, etc. The FindObjectsWithTag has such good functionality, but tagging an object based on its vehicle type means I can't tag it "player" or "enemy" (which makes things harder in other areas). Is there any way to have more than one tag so that I can iterate through my objects easily? Or is there another strategy in Unity that will get me what I want (simply iterating through planes[].Move() after defining "planes" with FindObjectsWithTag is sooo convenient...).
Thanks!
i have a strange solution for you, check here:-
http://blockmonkey.com/my-work/unity-3d-work/
it's a script that allows you to put in $$anonymous$$ultiple tags on an object...
Angad do you still have that script, the website is tits up. Can you post it here for records?
dead link. Please remove the answer or reupload.
I was looking for a way to do this multi-tag thing as well and happened across the correct URL.
Scroll down to where it says "Unity script that allows multiple tags".
http://blockmonkeydotcom.wordpress.com/my-work/unity-3d-work/
I have yet to try it. Looks pretty basic though.
Answer by andrew · Jul 06, 2010 at 11:45 PM
It is not currently possible, but i use a work-around.
On gameObjects that i need more than one tag on, i add an empty game objects as a child for each tag i need, and give each of these separate tags.. Then you can still search for tags using FindGameObjectsWithTag then just reference the parent object.. as an example in C#
sensedObjects = GameObject.FindGameObjectsWithTag(theTag);
foreach (GameObject foundOne in sensedObjects) { GameObject objectMain = foundOne.transform.parent.gameObject; //use it... }
That's a really good idea! I'll give it a shot. Thanks!
If I implemented this I'd make sure I never add a tag to a top level parent otherwise stuff will hit the fan (I'm assu$$anonymous$$g didn't test). I do like this ability though. For instance for me I have levels I want to reset stuff, but not everything, so I can basically tag everything that I want a reset on with a child object that has the tag 'resettable'. Thanks
@Timwillhack Using an interface sound like a better way to implement that than tags.
I'm glad you mentioned interfaces, as it is a great way to implement a generic always there function or the like across different types of objects, so thank you I'm sure this will help someone with that need. $$anonymous$$y comment was specific to the added complexity that you need to keep in $$anonymous$$d if you implemented this method. I don't like to add 'rules' to my development logic if I don't have to. The end of my comment was just a quick way to add any object I have to a search from anywhere (in this case resetting a scene without reloading the scene from scratch), as there is no built in interface searching that I know of without custom classes (nothing wrong with that). I am doing exactly what you are talking about though for my resets, each object that should be 'resetting' implements an interface and does in fact have a function that is called if it comes back in the tags search to do resets or the like. I am also new to unity (for like the 4th time) - I keep co$$anonymous$$g back. So every time I just 'wing it' and search when I need a hand.
Great simple idea...but GameObjects seem to have a lot of unnecessary overhead for just this. You could also just add a script, I'd call it "Tag.cs", and put a public variable or multiple variables with the "tags" you needed. Not quite as simple, but much more efficient.
edit: looks like someone beat me to the punch: https://answers.unity.com/questions/1470694/multiple-tags-for-one-gameobject.html
I agree with the last comment. Adding extra gameobjects just for tags is a SERIOUSLY bad idea and should NEVER be done under any circumstances. Anyone who has worked on even an average sized project will be able to tell you that this would negatively affect the performance of your game (and in-editor operating performance), and the weight of the object hierarchy unnecessarily.
Answer by CodeElemental · Feb 06, 2014 at 08:12 PM
When i want to multi-tag something i create Acronyms for the tags Ex:
Ally = All
Minion = Min
Champion = Chm
So when i want for some object to have multiple tags i tag it with a string containing several of them. ex : "EnChm" (for Enemy Champion) contains "Ch" , and i get by with doing the regular checks :
tag.Contains(string name)
I like this better. Seems like it will have way better performance... although there should be a best practice on this kind of object tagging and search.
I would even put a tag separator character between tags just for clearance. Also I would avoid using acronyms for better readability.
If you had a lot of tags, this would begin to get really difficult to manage since you have to input new tags manually in the editor.
If i did it this way I'd name them alphabetically so you can't screw up and put 'EnChm' ins$$anonymous$$d of 'ChmEn' (using your example backwards). I just tested a really long string as a tag and it let me, so I wouldn't bother making acronyms. Also what I don't like about this method is you can't ask for all enemies including champions and $$anonymous$$ions.
If tagging allowed more than one on each object without significantly extending the default functionality, you could query your scene/children like a simple database. I don't see anything wrong with enabling that functionality.
EDIT: Also, my original comment was discussing the answer, not that I created this situation myself.
Very nice. I never even considered something like this. By the way, if you came up with this on your own, you are truly brilliant and should have a promising future.
Using Tags like: |Enemy|Champion|GoldBoost|
is likely a better way... Then you can just use: if (tag.Contains("|Champion|")) { $$anonymous$$akeBadAss(); }
, and you know you'll never accidentally get back a substring of another Tag (if you end up with hundreds [or thousands] of them)...
Answer by rasmus_unity677 · Oct 12, 2017 at 04:23 PM
As alternative to re-implementing tags (as suggested by @CarterG81) just use a (possibly empty) component instead of using tags at all - this is far more flexible, and you can search using FindObjectsOfType just the same - without any additional framework/code.
If you need to classify objects in the first place, such as by adding tags, it's likely you'll discover at a later time that those objects have more in common than just a name - and you'll need a behavior for that anyhow; this way, you have a placeholder for that already.
In my space shooter tutorial project, I use a Shootable
behavior, which I apply to anything that can be shot - for example:
public class Shootable : MonoBehaviour {
public GameObject explosion;
public void Explode()
{
Destroy(gameObject);
Instantiate(explosion, transform.position, transform.rotation);
}
}
The controller for my shot is responsible for checking collisions - it checks if objects it collides with are Shootable
, and if so, destroys itself, and tells the Shootable
to explode:
private void OnTriggerEnter(Collider other)
{
var shootable = other.gameObject.GetComponent<Shootable>();
if (shootable) {
Destroy(gameObject);
shootable.Explode();
}
}
This way, shootables are responsible for generating their own explosions - you can elaborate on this concept and also make them responsible for counting damage, deciding whether to destroy themselves, and any other effects that may be specific to each kind of shootable object.
This is the best answer, I$$anonymous$$O. Others just encourage you to make messy code and project structure.
I agree, this is probably the best method available at the moment. You could extend your objects too so that they still show up if you ask for the original base class. I've been doing something similar with my trigger communications with various objects.
FindObjectsOfType
is one of the slowest commands there is... Tags get cached, so that they can be retrieved quickly. They don't need to be searched as Unity will know exactly what objects have or haven't got a specific tag.
Answer by NeilMeredith · Dec 09, 2013 at 10:25 AM
I created a simple asset called Tag Frenzy that allows you use multiple tags in Unity. It is (in my opinion) as easy to use as the built in tag system. You can see it in action here. I'd encourage you to check it out if you don't want to manually add child gameobjects like in the solution above.
Interesting! But can you use your tags in a case like this: void OnTriggerEnter(Collider col) { if(col.gameObject.tag == "Unit") {
If so, how would the code look?
Answer by CarterG81 · Feb 13, 2017 at 02:34 AM
It's pretty simple to just replace Unity's tag system with your own.
Here's an example of how you could write a tag replacement system (to show how easy it is).
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
}
//Tags.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.
}
}
}
}
//Tags.cs
void Awake()
{
TagSystem.AddGameobjectTags(this);
}
Finally, to actually get any of the tag information, you'd need a reference to the Tags.cs component.
myGameObject.GetComponent<Tags>().hasTag(theTag);
Something like that, anyway. Pretty easy stuff to simulate Unity's tag API.
You could even extend this system to include Layers, or a third similar type. Since it's your own custom system, it's fully extendable for easier readability, better performance, and more overall power as a feature.
Having Enums rather than strings can save you some problems with user error (typos), among other benefits. It's up to you though. It'll all perform extremely fast, so readability is most important.
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.
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
GameObject.findGameObjectsWithTag returning empty? 1 Answer
Array Question Length (C#) 8 Answers
Replace variable with new game object after it is made null - not working 0 Answers
Shooting Specific GameObject via Tag 0 Answers