2
\$\begingroup\$

I'm trying to mimic FindGameObjectsWithTag with FindGameObjectsWithName. I know using tags is faster, but I'm trying create a way to search for objects I spawn with a child object I name on instantiation through the inspector.

My goal is create multiple enemy spawners. My current spawner has a drag and drop variable for enemy prefabs. It looks for enemies tagged "ReSpawn", then checks if that length is below a value, to start spawning more. I would like to upgrade my current single spawner to still check for enemies named "ReSpawn", but then check if those respawns have a child object a name specified in the editor. This way, I can set the enemy spawners anywhere (e.g. near water, tall grass, forests, etc), and when I defeat one, the specific spawner will instantiate one of its opponents for that area.


Here is my code, so far:

var ThisSpot:String;
var Oppos : GameObject[];
var OppoCount : GameObject[];

var HowMany = 3;
var spawnSizeArea = 25;

function Start() {
    StartCoroutine ("Spawn");
}

function Update () {
    OppoCount = GameObject.FindGameObjectsWithTag("Respawn");
    // OppoCount = GameObject.FindWithName(ThisSpot);  This is what I am trying to achieve

    if(OppoCount.length < HowMany) {
        StartCoroutine ("Spawn");
    }
}

function Spawn() {
    var length = Oppos.length-1;
    var index = Mathf.Round(length*UnityEngine.Random.value);
    curSpawn = Oppos[index];

    var xz = Random.insideUnitCircle * spawnSizeArea;
    var newPosition = Vector3(xz.x,0,xz.x)+transform.position;

    yield WaitForSeconds(Random.Range(70,120));

    Instantiate(curSpawn, newPosition, transform.rotation);

    // Then I could use these 2 lines of code below to use multiple spawners      
    //var newOp : GameObject = Instantiate(curSpawn, newPosition, transform.rotation);
    //newOp.transform.Find("fighter").gameObject.name=ThisSpot;

    StopCoroutine("Spawn");
}
\$\endgroup\$
3
  • 1
    \$\begingroup\$ Unity has their own StackExchangeish answer boards... sorry for the spam, but answers.unity3d.com will give you faster/more exact solutions. At least I think so. \$\endgroup\$ Commented Aug 5, 2011 at 17:02
  • 1
    \$\begingroup\$ @Tom That's not spam, it's a useful comment :p \$\endgroup\$ Commented Aug 6, 2011 at 10:13
  • 1
    \$\begingroup\$ You should post your solution as an answer to the question, not an edit to the question \$\endgroup\$
    – yoozer8
    Commented Apr 19, 2012 at 14:03

3 Answers 3

3
\$\begingroup\$

Unity best practices are to never use Find in any of its incarnations at run time. It's slow and unnecessarily ties the name of the object with its functionality.

Any time you call Instantiate you can save off the return value and store it somewhere (i.e. a List in some component your write). Then you can just iterate over the elements of that list to get what you want.

So for your spawner example, your spawner could have a list of game objects that it has spawned. In Update you can iterate over that list and count the number of non-null gameobjects (to check for destroyed objects). Alternatively the enemy can have a reference to its spawner and remove itself from that list in OnDestroy. Then if that number is less than a certain value spawn a new one.

\$\endgroup\$
3
  • \$\begingroup\$ Now why didn't I think of that?? Thanks! I will post my attempt in a few moments in my original post \$\endgroup\$
    – Epic447
    Commented Aug 5, 2011 at 22:29
  • \$\begingroup\$ That was the solution I needed! Thanks to you both for your kind help! \$\endgroup\$
    – Epic447
    Commented Aug 5, 2011 at 22:38
  • \$\begingroup\$ Now I'm wondering... What is Find good for? \$\endgroup\$
    – cregox
    Commented Feb 24, 2015 at 23:24
3
\$\begingroup\$

From Unity Reference :

// This will return the game object named Hand in the scene.
hand = GameObject.Find("Hand");

You must remember that when trying to access objects via script, any inactive GameObjects are not included in the search. And that this will only return one object.

If you want to create the same behaviour as 'FindGameObjectsWithTag', you'll have to implement the function yourself.

In one of my games, for each level I used a GameObject to parent all the other objects, this way it was easier to access the objects. You could do something like :

int count = 0;
GameObject[] children = GetComponentsInChildren<GameObject>();
foreach (GameObjectchild in children )
{
    if(children.name == "WantedName")
        ++count;
}

Edit:

If you're using the UI to add instances to the spawner, that means that the spawner, and the objects it is supposed to spawn, are already instanced at startup. I don't think this is the best way to go about it. I would personally add a script to the spawner with an Enum for each monster type. This scripts behaviour would be to check if it holds an instance to an object, if not create one of the Enum type and keep the reference.

If you haven't tried overloading UI yet, it can be quite easy and help enormously in creating a more suitable editor for your game.

\$\endgroup\$
5
  • \$\begingroup\$ Unless If I can somehow tally 'foreach' to get a count of how many names it finds, I can't use it. I basically need amounts to check if their lengths are below a certain amount, so the spawner can know to instantiate more. I also prefer not to parent the enemies in gameobjects because they have other scripts constantly looking for the root transform, which must be the enemy itself (amongst other reasons). Someone a while ago suggested using 'Get Types' to find String names, but I had no idea how to use it properly with Java script. Any ideas? \$\endgroup\$
    – Epic447
    Commented Aug 5, 2011 at 11:44
  • \$\begingroup\$ @Epic447 I edited the answer to tally the number of objects, but I'm still not sure I understand :). \$\endgroup\$ Commented Aug 5, 2011 at 11:53
  • \$\begingroup\$ I appreciate your help so far, and thank you! this will work, but what about when I defeat one the spawners enemies? This code is in the update function- won't the count keep adding 1 each second after it finds someone with the right name? This is really a bigger head scratcher than I thought it would be. Anyway, the gist is to be able to place multiple spawn points in a level, drag and drop people/creatures to spawn at each one, then if the player defeats one of those characters, to spawn another. So all thats needed is a wider method for tallying each thing. I'm just trying not to use tags \$\endgroup\$
    – Epic447
    Commented Aug 5, 2011 at 12:14
  • \$\begingroup\$ @Epic447 Ok now I get it :). Indeed you could use a list of string along with a UI overload to make this possible, but it's all rather messy. I'll edit my answer to try and help more. \$\endgroup\$ Commented Aug 5, 2011 at 12:39
  • \$\begingroup\$ Wha?? Okay, now I am lost :) I have never heard of overloading UI? So I should drop trying to find objects by name (I'm lost!)? I think I recognize 'Enum'. That means I have to type a list of every name of every enemy right? there's around 50! How would I go from there? Please, may I ask you for an example? \$\endgroup\$
    – Epic447
    Commented Aug 5, 2011 at 13:09
0
\$\begingroup\$

The original asker edited their question with the solution they used. However, as questions should not be edited to include the answers, I have removed the code to post as a community wiki.


The original asker reports that they used this code to meet their requirements:

function Update (){
    for (var i =0; i < OppoCount.length ; i ++){
        if(OppoCount.length > 0) {
            if (OppoCount[i].gameObject == null){
                OppoCount.RemoveAt(i);
            }

        if(OppoCount.length < HowMany){
            StartCoroutine ("Spawn");
        }
    }
}

function Spawn(){
    var length = Oppos.length - 1;
    var index = Mathf.Round(length*UnityEngine.Random.value);
    curSpawn = Oppos[index];

    var xz = Random.insideUnitCircle * spawnSizeArea;
    var newPosition = Vector3(xz.x,0,xz.x) + transform.position;

    yield WaitForSeconds(Random.Range(2,4));

    var newOp : GameObject = Instantiate(curSpawn, newPosition, transform.rotation);

    OppoCount.Push(newOp);
    StopCoroutine("Spawn");
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .