Finding all Game Objects with multiple Tags

Ok, so heres my problem:

Say I have 2 Arrays setup, one array of strings and the other for gameobjects.

Just like this:

var townsPeople : int;
var bandits : int;

var allTags : String[];
var allTownsPleopleTags : String[];
var allMaffiaTags : String[];

var allPlayers : GameObject[];
var allTownsPleople : GameObject[];
var allMaffia : GameObject[];


function Start(){

}

function Update () {
	
	for(apt = 0; apt < allTags.Length; apt++){
		allPlayers = GameObject.FindGameObjectsWithTag(allTags[apt]);
	}
	
	for(atp = 0; atp < allTownsPleopleTags.Length; atp++){
		allTownsPleople = GameObject.FindGameObjectsWithTag(allTownsPleopleTags[atp]);
	}
	
	for(am = 0; am < allMaffiaTags.Length; am++){
		allMaffia = GameObject.FindGameObjectsWithTag(allMaffiaTags[am]);
	}
	
}

You can probably tell what i’m trying to do. I’m trying to enter all of my tags into the string array and get all the game objects with the correct tags. The problem is that I’m only getting one random object with a random tag. I think that its because I have my code in the Update function, but it has to be there because my tags are going to change will in game. Any ideas?

You can use a List of GameObjects, and loop though the array of tags, adding each result to the List using AddRange. You really don’t want to do that in Update though, regardless of whether the tags change in the game. Just do it when the tags actually change, not every frame. It would probably be best to make a FindGameObjectsWithTags function, so you can use it easily for different Lists of GameObjects.

import System.Collections.Generic;

var allPlayers : List.<GameObject>;
var allTags : String[];

function Start () {
	allPlayers = FindGameObjectsWithTags (allTags);
}

function FindGameObjectsWithTags (tags : String[]) : List.<GameObject> {
	var combinedList = new List.<GameObject>();
	for (i = 0; i < tags.Length; i++) {
		var taggedObjects = GameObject.FindGameObjectsWithTag(tags*);*
  •  combinedList.AddRange(taggedObjects);*
    
  • }*
  • return combinedList;*
    }
    You could convert the List to a GameObject[] array, but you might as well save the conversion and leave it as a List, since it’s more flexible than GameObject[] and is barely any slower.

In your first for loop you use allTownsPleopleTags to define the length but eventually call FindGameObjectsWithTag() with your allTags array

Also, you will only get the results from the last tag in each tag-array since you always overwrite the content of the gameObject arrays.

A quick google search for “site:unity3d.com javascript array merge” gave me this

You could define roles and jobs by different components.
For example, you have a Warrior and a Cook component assigned to a character game object, by checking

if( characterObject.GetComponent<WarriorClass>() != null )
{
    //this is a warrior
}

if( characterObject.GetComponent<CookJob>() != null )
{
   //this is also a cook
}

so for your example, you have a townspeople and a mafia component. (These components really don’t have to do anything, but I suggest you rethink your component structure so each action is done by its respective component)

to seperate them you then use sth like this

var mafiaList = new List.<GameObject>();
var townspeopleList = new List.<GameObject>();

for( i = 0; i < allCharacters.Length; ++i )
{
    if( allCharacters[ i ].GetComponent<Mafia>() != null )
    {
        mafiaList.Add( allCharacters[ i ] );
    }

    if( allCharacters[ i ].GetComponent<TownsPeople>() != null )
    {
        townspeopleList .Add( allCharacters[ i ] );
    }
}

(I tried to do the example in JavaScript, but no guarantees since I am using C#)

OK Guys, I figured it out!!!

Here is my final script, I used a for loop inside another for loop:

import System.Collections.Generic;

var townsPeople : int;
var mafia : int;

var allTags : String[];
var allTownsPleopleTags : String[];
var allMaffiaTags : String[];

var allPlayersList = new List.<GameObject>();
var townspeopleList = new List.<GameObject>();
var mafiaList = new List.<GameObject>();

function Update(){
	UpdateTags();
}

function UpdateTags() {
	allPlayersList.Clear();
	townspeopleList.Clear();
	mafiaList.Clear();
	
	for(apt = 0; apt < allTags.Length; apt++){
		var APT1Test : GameObject[] = GameObject.FindGameObjectsWithTag(allTags[apt]);
		for(i = 0; i < APT1Test.length; i++){
			allPlayersList.Add(APT1Test*);*
  •  }*
    
  • }*

  • for(atp = 0; atp < allTownsPleopleTags.Length; atp++){*

  •  var ATP2Test : GameObject[] = GameObject.FindGameObjectsWithTag(allTownsPleopleTags[atp]);*
    
  •  for(o = 0; o < ATP2Test.length; o++){*
    
  •  	townspeopleList.Add(ATP2Test[o]);*
    
  •  }*
    
  • }*

  • for(am = 0; am < allMaffiaTags.Length; am++){*

  •  var AM3Test : GameObject[] = GameObject.FindGameObjectsWithTag(allMaffiaTags[am]);*
    
  •  for(p = 0; p < AM3Test.length; p++){*
    
  •  	mafiaList.Add(AM3Test[p]);*
    
  •  }*
    
  • }*

}
It might be a very roundabout way to do it, but it works very well for my needs. I can not tell you how helpful you have all been.
PS: I don’t really need to worry about it updating every frame because this is for a chat based game, no powerful graphics are going to be used. I did add a new function in the script so that if I really need to, I can get rid of the update function and just call the UpdateTags function from another script when I’m ready. Everyone was so worried about the performance hit by running Update, but I guess it would have helped if I mentioned there are no other heavy graphics or any other intensive scripts to bog down the performance. In my case, this works flawlessly.
Again, thank you to everyone for being so helpful, I think this is a great addition to the unity tagging system and will help in find Game Objects faster and easier. Feel free to use this in your own projects :slight_smile: