Issue with arrays etc

This is a problem that has been seriously vexing me for months now.

I need a way to find all the gameobjects that are both children of a specific object AND carry a specific tag.

Finding all the children in easy. Finding all the objects in scene with that tag is easy. However, it seems I have to do both - and create hundreds of individual tags - to accomplish this. Here’s a code sample so far (using JS):

var wilhelm: GameObject;
var wilhelmsKids : GameObject [];
var partyGoers: GameObject [];
function Start () {
    partyGoers = GameObject.FindGameObjectsWithTag("juniors");
}

function Update () {
    for (var : kid in partyGoers) {
        if (kid.transform.parent == wilhelm) {
            kid.tag == wilhelmJuniors;
        }
    }
    wilhelmsKids = GameObject.FindGameObjectsWithTag("wilhelmJuniors")
}

What I’m looking for is a way to find “wilhelmsKids” without having to change the tag or check the parent. In this scenario, I would have over 200 parents - that seems like an awful lot of work to create individual tags for each.

If there was a “FindChildrenWithTag” command that would be ideal, but since there isn’t I think I’m stuck making all those tags or hundreds of object-specific scripts.

Can I ask why you are using tags at all for this instead of some sort of inheritance pattern? Just create an interface for your parent objects to implement. Then when you add a child to the parent, get the interface and add a reference to the child. If you destroy a child remove the reference in OnDestroy. If you need an example I can write you one in C#.

I am a bit confused on what you just said. Mainly because it’s almost 1 am and frankly there’s a lot of scripting jargon I’m unfamiliar with. I would appreciate a basic example if you don’t mind.

With this you can simply store all of your Parents in a single list and attempt to cast them to either GoodParent or EvilParent on iteration. If the cast succeeds you will have access to all the children of your specific type.

/// <summary>
/// T = typeof Child in the relationship
/// </summary>
public interface IParentRelationship<T>
{
   void Add(T pChild);
   void Remove(T pChild);
}

public abstract class Parent : MonoBehaviour { }

/// GoodParent cares about all of its children
public class GoodParent : Parent, IParentRelationship<GoodChild>, IParentRelationship<BadChild>
{
   public HashSet<GoodChild> GoodChildren = new HashSet<GoodChild>();
   public HashSet<BadChild> BadChildren = new HashSet<BadChild>();

   public void Add(GoodChild pChild)
   {
     if (!GoodChildren.Contains(pChild))
     {
       GoodChildren.Add(pChild);
     }
   }

   public void Remove(GoodChild pChild)
   {
     GoodChildren.Remove(pChild);
   }

   public void Add(BadChild pChild)
   {
     if (!BadChildren.Contains(pChild))
     {
       BadChildren.Add(pChild);
     }
   }

   public void Remove(BadChild pChild)
   {
     BadChildren.Remove(pChild);
   }
}

/// EvilParent only cares about its bad children
public class EvilParent : Parent, IParentRelationship<BadChild>
{
   public HashSet<BadChild> BadChildren = new HashSet<BadChild>();

   public void Add(BadChild pChild)
   {
     if (!BadChildren.Contains(pChild))
     {
       BadChildren.Add(pChild);
     }
   }

   public void Remove(BadChild pChild)
   {
     BadChildren.Remove(pChild);
   }
}

public abstract class Child<T> : MonoBehaviour where T : class
{
   internal static ulong m_CrappyIdentifierImpl = 0;
   internal static ulong m_NextCrappyIdentifier = m_CrappyIdentifierImpl++;

   private ulong m_InternalIdentifier = m_NextCrappyIdentifier;
   private IParentRelationship<T> m_Relationship;

   void Awake()
   {
     AddRelationship();
   }

   void OnDestroy()
   {
     RemoveRelationship();
   }

   void OnTransformParentChanged()
   {
     RemoveRelationship();
     AddRelationship();
   }

   private void AddRelationship()
   {
     IParentRelationship<T> relation = GetComponentInParent<IParentRelationship<T>>();
     if (relation != null)
     {
       T c = this as T;
       if (c != null)
       {
         m_Relationship = relation;
         m_Relationship.Add(c);
       }
     }
   }

   private void RemoveRelationship()
   {
     if (m_Relationship != null)
     {
       T c = this as T;
       if (c != null)
       {
         m_Relationship.Remove(c);
       }
     }
   }

   public override int GetHashCode()
   {
     return m_InternalIdentifier.GetHashCode();
   }
}

public class GoodChild : Child<GoodChild>
{
}

public class BadChild : Child<BadChild>
{
}

Find the children, loop through them and store the ones with the desired tag in a list. Or find all objects with the desired tag, loop through them and store the ones that are are a child of the specific object in a list. Whichever would be more generally efficient for whatever situation you have. (Probably the first option.) Also don’t do this in Update.

–Eric

I tried using lists previously. There’s something there that I’m missing though - this version generated an error that the best overload method was not compatible.

#pragma strict

import System.Collections.Generic;

public class ParentGUIBase extends MonoBehaviour {
    function Start () {
        var myKids= new List.<WilhelmsJuniors>();
    }
}

function LateUpdate () {
    partyGoers = GameObject.FindGameObjectsWithTag("Partygoers");
    for (var kid : GameObject in partyGoers) {
        if (kid.transform.parent == wilhelm) {
            myKids.Add (kid);
        }
    }
}

Your line new List.(); You have a period after List. This shouldn’t be there.

All of the documentation and tutorials I’ve seen have the period there. Removing it creates a whole pile of other errors.

Alright, it’s different in javascript than csharp. Was a guess at a glance what could be wrong.

Is kid a WilhelmsJuniors? You’re making a list of WilhelmsJuniors, which I’m guessing is a class you have. But is kid a gameobject?

Yes. The list “myKids” should be comprised of gameObjects (or transforms, I honestly don’t care), carrying the script “WilhelmJuniors”. “kid” represents an item in the array “partyGoers”. If “kid” is parented to gameObject wilhelm, it should be added to list “myKids”. That way the script “WilhelmScript” attached to Wilhelm only lists, references, counts, etc those gameObjects that cary the script “WilhelmJunior” and are parented to Wilhelm at the time.

Sorry, probably wasn’t clear in my explanation.
Your list is
var myKids= new List.(); Which is a List of WilhelmsJuniors and not a list of GameObjects.
You are trying to add a GameObject to a list of WilhelmsJuniors. Make it a list of GameObjects instead.

If you want it to be a list of WilhelmsJuniors, you’ll have to use the getcomponent on the gameobjects when you add them to the list.

Ok I’ve got it down now, sorry for not being real swift on the uptake.

One remaining question - when should I do this (add the gameObject to the list)? Update, LateUpdate, etc create a situation where the list is continuously expanding regardless of how many objects there are (replicating each objects entry ad infinitum).

Honestly, I wouldn’t do it in any update. You’re going to run into problems. One, you’re going to add the same kid over and over and over. Without knowing your code, based on what you show. You’re looping through and adding all the kids. Then you’re doing it again, adding the same kids + any new ones. Then again and again… Eventually you might run into memory issues if your list grows way to big.

This is assuming you’re not doing anything else to those child objects to keep them from being added back to the list over and over.
My suggestion would be you add the kids only if/when they become a child of wilhelm if possible.

I’ve tried it many ways (on message-initiated invokes, on trigger enters, on collider enters)… it seems the only way it adds to myKids is on recurring calls (updates, onGUI, etc)

Was there a problem with the solution I provided :(?

Not a problem per se, and probably quite helpful. It was just beyond my grasp as a very very noobish scripter.

So this issue is mostly solved except for one last thing.

Each of the child objects creates a button which is supposed to activate the GUI for that specific child. I can create the right num,ber of buttons, have each of them labeled with the child’s name (using GetComponent), but clicking on any button causes only one child’s GUI to activate (I assume because BroadcastMessage goes to every child). SendMessage would work EXCEPT that these have to be child objects of the parent. Any thoughts?