How do I parent a Transform to another Transform that's stored in a List?

I’ve got a list of Transforms which are Empty children of an object in my scene, named Mount_000 through Mount_007, and at runtime I want to pick a random Mount and attach a gun to it. So I did this:

           foreach (Transform child in attachedParts[attachedParts.Count - 1]){
               // do whatever you want with child transform here
               if(child.name.Contains("Mount")){
                   dirtyMounts.Add(child);
               }
               if(child.name.Contains("Hardpoint")){
                   dirtyHardPoints.Add(child);
               }
           }

          int chosenMount = Random.Range(0,dirtyMounts.Count - 1);
          Debug.Log("Chose mount #"+ chosenMount + ", which is "+mounts[chosenMount]);
          newPart.SetParent(mounts[chosenMount] as Transform);
          Debug.Log(newPart.parent);

I can’t figure out why it’s not working.

Try changing this:

foreach (Transform child in attachedParts[attachedParts.Count - 1]){
// to this...
foreach (Transform child in attachedParts){

Also, you should change this:

int chosenMount = Random.Range(0,dirtyMounts.Count - 1);
// to this:
    /* as the upper bound is exclusive */
int chosenMount = Random.Range(0,dirtyMounts.Count);

attachedParts[ ] is a list of Gameobjects which are known to have children. I’m trying to grab the last item from that list and get its children when I do foreach (Transform child in attachedParts[attachedParts.Count - 1])

Here, I seperated it out into another variable for clarity; didn’t change the result:

            Transform lastAttachedPart = attachedParts[attachedParts.Count - 1];
            foreach (Transform child in lastAttachedPart){
                // do whatever you want with child transform here
                if(child.name.Contains("Mount")){
                    dirtyMounts.Add(child);
                }
                if(child.name.Contains("Hardpoint")){
                    dirtyHardPoints.Add(child);
                }
            }
            Debug.Log(dirtyMounts);
            //int randomAttachmentPoint = Random.Range(0,dirtyMounts.Count - 1);
            int chosenMount = Random.Range(0,dirtyMounts.Count);
            Debug.Log("Chose mount #"+ chosenMount + ", which is "+dirtyMounts[chosenMount]);
            newPart.SetParent(dirtyMounts[chosenMount] as Transform);
            Debug.Log(newPart.parent);

I see, I see… Does it work if you use dirtyMounts[chosenMount] instead of Mounts?

Nope. I already fixed that in the second post anyway.

I feel like there must be something fundamental about Lists that I’m not grokking. Look at my debug statements results. There’s no reason I can think of for the second thing to return null if the first thing doesn’t return null, but that’s what keeps happening at runtime.

What is your List<> of? Why the cast to Transform during SetParent()?

It looks like the cast is failing for some reason, which when you cast with as returns null rather than an exception.

Hmm… I didn’t think of that, but in the output log he posted, it does say ‘transform’.

Is there any chance that newPart is null?

I can’t remember why I cast to Transform during SetParent(). I think I might have been flailing about earlier trying to get it to work without really understanding what was wrong? Anyway, I removed the cast and added a few Debugs to test the newPart is Null theory. No dice.

Here’s the whole script for greater context:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BossMaker : MonoBehaviour {
   
    [SerializeField]
    private Transform corePrefab;
    [SerializeField]
    private List <Transform> botParts = new List<Transform> ();
    private List <Transform> sanitizedBotParts = new List<Transform> ();
    [SerializeField]
    private int maxBranches = 4;
    private int branchesSolved;
    private List <Transform> attachedParts = new List<Transform> ();
    private List <Transform> dirtyMounts;
    private List <Transform> dirtyHardPoints;
   
    void Awake(){
        //Clean up after sloppy IDE users
        foreach(Transform p in botParts)
        {
            if(p!= null){
                sanitizedBotParts.Add(p);
            }
        }       
    }
   
    // Use this for initialization
    void Start () {
        GenerateBoss();
    }
   
    // Update is called once per frame
    void Update () {
       
    }
   
    private void GenerateBoss(){
        branchesSolved = 0;
        Transform core = (Transform) Instantiate(corePrefab, transform.position, transform.rotation) as Transform;
        attachedParts.Add(core);
       
        for (var i = 1; i< maxBranches; i++){
            dirtyMounts = new List<Transform>();
            dirtyHardPoints = new List<Transform>();
            int randomPart = Random.Range(1,sanitizedBotParts.Count - 1);
            Transform newPart = Instantiate(sanitizedBotParts[randomPart], transform.position, transform.rotation) as Transform;
            attachedParts.Add(newPart);
            Transform lastAttachedPart = attachedParts[attachedParts.Count - 1];
            foreach (Transform child in lastAttachedPart){
                // do whatever you want with child transform here
                if(child.name.Contains("Mount")){
                    dirtyMounts.Add(child);
                }
                if(child.name.Contains("Hardpoint")){
                    dirtyHardPoints.Add(child);
                }
            }
            //int randomAttachmentPoint = Random.Range(0,dirtyMounts.Count - 1);
            int chosenMount = Random.Range(0,dirtyMounts.Count);
            Debug.Log("New Part is " +newPart);
            Debug.Log("Chose mount #"+ chosenMount + ", which is "+dirtyMounts[chosenMount]);
            newPart.SetParent(dirtyMounts[chosenMount]);
            Debug.Log("After Assigning, new parent is "+newPart.parent);
            Debug.Log(" ");
        }
       
       
    }
}

And this is running 32 times when I run the game to procedurally generate a structure, so the fact that some parts appear in the world, just not properly parented, means they can’t all be null. But as you can see, no matter what part it returns, the end parent is always, always Null.

Just out of curiousity can you make a small repro package & post it here? Just the minimum to test this?

Maybe there is an issue with SetParent. I’ve never used it myself. I would just do;

newPart.parent = dirtyMounts[chosenMount];

Seeing your full code, it looks like you’re trying to parent newPart to itself or a child of itself which is going to fail every time.

// create a new part:
Transform newPart = Instantiate(sanitizedBotParts[randomPart], transform.position, transform.rotation) as Transform;

// add it to the attachedParts list:
attachedParts.Add(newPart);

// get the last item from the attachedParts list, which is newPart
Transform lastAttachedPart = attachedParts[attachedParts.Count - 1];

At this point, newPart and lastAttachedPart are the same thing. Then you run your selection code, which selects a random child of lastAttachedPart / newPart and finally you try to parent it to itself.

I am sad that I missed that. :slight_smile:

Oh, wow. I can’t believe I was that stupid. Thank you so much, everybody!

I moved attachedParts.Add(newPart); down one line and it magically started working.

You answer like 400 questions a day, I wouldn’t sweat 1 missed error :wink:

No problem mate. Next time post the full code from the get-go so you pull less of your hair out. :stuck_out_tongue:

Awesome… I still enjoy a happy ending, mishaps included :wink: