Find objects by one tag or another.

Hi, I need to find all objects in a scene that have either the tag “1”, “2” or “3”. The query should return an array of all the objects. I can only find references to finding all objects by ONE tag.

The reason for this is I am trying to code a food chain, and animals that are tagged with “3” can find and eat all animals tagged “2” or “1”.

If there is a better way to do this than using tags please let me know, I have been googling for a full day.

Thanks

You could just use GameObject.FindGameObjectsWithTag 3 times at Start, and check the appropriate arrays - animals 3 look for food in arrays 1 and 2, for instance. If you really want the animals in a single array, however, add some specific script to all animals, and get them all at once with GameObject.FindObjectsOfType(ScriptName), again at Start. Both alternatives have two drawbacks: newly created animals aren’t included in the arrays, and destroyed ones aren’t removed. The last problem is easy to work around: any references to a destroyed game object magically become null in Unity, thus you should skip null array elements - they were already eaten. But the first issue is more complicated: Find functions are too slow to be used in Update. If new animals may be added during the level, it would be better to use another approach: create an empty object - say, “Animals” - reset its position and rotation and child all animals to it when they are created. You could thus iterate through all animals with a simple for…in like this:

for (var animal: Transform in animals.transform){
  switch (animal.tag){
    case "1":
    case "2":
      // this is food!
      break;
    case "3":
      // it's a colleague, don't eat it!
      break;
  }
}

Since all animals are childed to “Animals” when created, its children list is always up to date - and destroyed animals are automatically removed from the list, thus you don’t have to worry about null references.

EDITED:

In order to use the “animals group” approach, you should create and empty game object named “Animals” and reset its position and rotation. All animals should have code to child themselves to Animals when they are created. The same script could be used in all animals, if it had fields indicating which itens the animal can eat - like this:

var food1 = "2"; // this animal can eat types 2 or 3
var food2 = "3"; // the eatable types can be defined in the Inspector

private var animals: GameObject; 

function Start(){
  animals = GameObject.Find("Animals"); // find the animals group
  transform.parent = animals.transform; // child itself to it
}

function FindClosestTarget () : GameObject {
  var closest: GameObject;
  var distance = Mathf.Infinity; 
  var position = transform.position;  
  for (var trFood: Transform in animals.transform){ // for each animal...
    if (trFood == transform) continue; // avoid eating yourself!
    var food = trFood.gameObject; // get its GameObject reference
    // check if it's comestible:
    if (food.CompareTag(food1) || food.CompareTag(food2)){
      // if so, check if it's the nearest one:
      var curDistance = (trFood.position - position).sqrMagnitude;
      if (curDistance < distance){ // it's the nearest up to now:
        closest = food; // save its game object reference...
        distance = curDistance; // and its squared distance
      }
    }
  }
  return closest; // return the nearest one, or null if there's nothing to eat
}

If the animal can only eat one type, set food1 and food2 to the same type (CompareTag only accepts existing tags - invalid values throw a runtime exception). You can of course have more eatable types: just declare food3, food4 etc. and include them in the if clause.

why not just call GameObject.FindGameObjectsWithTag 3 times?
and have 3 arrays or gameobjects.

to add them all to the same array

GameObject[] threeTags = new GameObject[arr1.length + arr2.length + arr3.length];

arr1.CopyTo (threeTags, 0);
arr2.CopyTo (threeTags, arr1.length);
arr2.CopyTo (threeTags, arr2.length);

Aldo has a great point and that is the method you should use. Although for people who enter this domain searching for treasure regarding the title, here’s another take which will sum all objects with tag(s) into one single array.

private var gameObjectsWithMyTags : GameObject[]; //Cached objects

function Start () {
	// Define the tags
	var tags : String[] = ["Tag 1", "Tag 2", "Tag 3"];
	
	// Collect the objects with tags
	gameObjectsWithMyTags = FindGameObjectsWithTags(tags);
	
	// Do something with gameObjectsWithMyTags
	for (var go : GameObject in gameObjectsWithMyTags)
		Debug.Log("GameObject: "+go.name+" has tag: "+go.tag);
}

function FindGameObjectsWithTags (tags : String[]) : GameObject[] {
	var allFoundObjects = new Array();
	for (var tag : String in tags) {
		allFoundObjects = allFoundObjects.Concat(GameObject.FindGameObjectsWithTag(tag));
	}
	return allFoundObjects.ToBuiltin(GameObject) as GameObject[];
}