Finding children in subgroups and attaching items

So I am trying to make a simple script to pick up an item/model and connect/disconnect it to the player.

I was trying to use a tagged spot on each object to set my location for mounting the item. but my script in its current form only finds the child for the second object. The first object has many sub groups that do not seem to get searched with my current method.

I also get an unassigned variable error and a gameObjec read only error with my final line to atatch the item

Any help would be appreciated, been banging my head against the wall for an hour with this one.

        private void OnTriggerStay(Collider other)
        {
            if (Input.GetKeyDown(KeyCode.R) && other.gameObject.CompareTag("HandHeld"))
            {
                GameObject getNewParent;  //somewhere to hold the new parent part
                GameObject getNewChild;  //somewhere to hold the new child part
                Debug.Log("created the variables check for children");


                //Search for the spot on the main character
                foreach (Transform child in gameObject.transform)
                {
                    Debug.Log("not the child"); //finds the first few children but does not look in groups

                    if (child.tag == "HoldSpot")  //Child never found as does not search offspring/sub groups
                    {
                        getNewParent = child.gameObject;
                        Debug.Log("found the child");
                    }       
                }

                //search for the spot on the item to connect
                foreach (Transform child in other.gameObject.transform)
                {
                    if (child.tag == "HoldSpot")
                    {
                        getNewChild = child.gameObject;
                        Debug.Log("found the other child");
                    }
                }
                getNewChild.transform = getNewParent.transform;  //Unassigned Variable yet it is used above
               
            }


        }

I cannot test this right now, but i believe

foreach (Transform child in gameObject.transform)

does not what you think it does, since gameObject.transform is exactly one transform. You want to look through the list of its children instead if i’m not mistaken.

That said, wouldnt it be easier to just reference the correct gameobject or parent and then go from there? Your script will take 2xO(n^2) to execute, which you probably want to avoid if it’s called often, or your gameobjects have a large child hierarchy.
Do you really have to do this on collision? Are the objects not known beforehand (for example because you have tons of them, or an unknown, generated amount of them)?
If that’s not possibly, i’d probably rather put the ā€˜HoldSpot’ object at a fixed location and then reference it in constant time, instead of interating over all children. If you knew where exactly it was, you could for example reference it like so: other.transform.GetChild(0).GetChild(0).GetChild(xyz)....gameObject;
While i dont think this is a good solution (since it depends on the correct position of the object and thus easily breaks if you forge that), it would be way faster.

1 Like

@Yoreki is right. A foreach loop is used to loop through all entries in a List or Array. Your better of using a for loop accessing all children of the transform like:

for (int i = 0; i < other.transform.childCount; i++)
{
if (other.transform.GetChild(i).tag == "HoldSpot")
{
getNewChild = other.transform.GetChild(i).gameObject;
Debug.Log("found the other child");
break;
}
}
1 Like

Hi thanks for the responses, I tried moving to a For loop(thank you for that) but it has the same issue as the for each and its not going through them recursively and is just checking the root for children.

The reason I wanted to find the locations instead of defining them was to hopefully make things easier down the line so I can just tag a part and be done with it when adding more models that the user can hold but I am starting to think maybe I should just define the hand/parent object.

Both the ā€œforā€ and ā€œforeachā€ seam to do the job fine when there is no recursive items to check, is there a cpu benefit to using the ā€œforā€ loop instead?

I would still like to do this recursively if possible, and I also get an error with my last statement,

Property or indexer ā€˜GameObject.transform’ cannot be assigned to – it is read only

Thanks for the help! Sorry for being a pest :stuck_out_tongue:

        private void OnTriggerStay(Collider other)
        {

            if (Input.GetKeyDown(KeyCode.R) && other.gameObject.CompareTag("HandHeld"))
            {

                Debug.Log("check for children");

                //does not search the chilred recursively

                for (int i = 0; i < gameObject.transform.childCount; i++)
                {
                    Debug.Log("looking for child");
                    if (gameObject.transform.GetChild(i).tag == "HoldSpot")
                    {
                        getNewParent = gameObject.transform.GetChild(i).gameObject;
                        Debug.Log("Found the child");
                    }
                }


                //search for the spot on the item to connect works fine as these models dont have subchildren
               
                foreach (Transform child in other.gameObject.transform)
                {
                    if (child.tag == "HoldSpot")
                    {
                        getNewChild = child.gameObject;
                        Debug.Log("found the other child");
                    }
                }

                getNewChild.transform = getNewParent.transform;
               
            }


        }

No problem at all, this forum thread is here if you have questions, you shouldn’t feel like being a pest for asking questions :slight_smile:

if I understand you correctly you want to also check for children of the children of the transform, which can be done by a nested for loop :

private void OnTriggerStay(Collider other)
    {
        if (Input.GetKeyDown(KeyCode.R) && other.gameObject.CompareTag("HandHeld"))
        {

            Debug.Log("check for children");

            //check each child object and it's children (if any)
            for (int i = 0; i < transform.childCount; i++)
            {
                Debug.Log("looking for child");

                //check the childObject
                if (transform.GetChild(i).tag == "HoldSpot")
                {
                    getNewParent = transform.GetChild(i).gameObject;
                    Debug.Log("Found the child");
                    break;
                }
                //check it's children (if any)
                for (int j = 0; j < transform.GetChild(i).childCount; j++)
                {
                    if (transform.GetChild(i).GetChild(j).tag == "HoldSpot")
                    {
                        getNewParent = transform.GetChild(i).GetChild(j).gameObject;
                        Debug.Log("Found the child");
                        break;
                    }
                }
            }


            //search for the spot on the item to connect works fine as these models dont have subchildren
            foreach (Transform child in other.gameObject.transform)
            {
                if (child.tag == "HoldSpot")
                {
                    getNewChild = child.gameObject;
                    Debug.Log("found the other child");
                }
            }

            getNewChild.transform.SetParent(getNewParent.transform);
        }
    }

I hope this solves your issue, but if not, just ask again :slight_smile:

Edit: I think you wanted to set the parent of the getNewChild GameObject so I fixed it to do just that, but if that is not what you want then please tell me.

I ended up going with a different solution for the task but that will come in handy later on for another issue I’ve got elsewhere, thank you very much