Search Unity

Parenting issues...

Discussion in 'Scripting' started by jeremyace, Feb 17, 2006.

  1. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Hey guys, I am still working on my Debug controller script, and I was adding some things that freyr suggested in my other post, but it doesn't work.

    What I am trying to do is duplicate my GUIText objects like before, and then parent each object to the original. The code snippet in Awake() looks like this:

    Code (csharp):
    1.  
    2. void Awake() {
    3.         s_Instance = this;
    4.         if (DebugGui == null)  // If an external GUIText is not set, provide the default GUIText
    5.         {
    6.             DebugGui = new GameObject();
    7.             DebugGui.AddComponent("GUIText");
    8.             DebugGui.name = "DebugGUI(0)";
    9.             DebugGui.transform.position = defaultGuiPosition;
    10.             DebugGui.transform.localScale = defaultGuiScale;
    11.         }
    12.          
    13.          // Create our GUI objects to our maxMessages count
    14.          Vector3 position = DebugGui.transform.position;
    15.          guis.Add(DebugGui);
    16.          int x = 1;
    17.          while(x < maxMessages)
    18.          {
    19.             position.y -= lineSpacing;  
    20.             GameObject clone = null;
    21.             clone = (GameObject)Instantiate(DebugGui, position, transform.rotation);
    22.             clone.name = string.Format("DebugGUI({0})", x);    // Add the current loop number to the DebugGui() name string
    23.             clone.transform.parent = DebugGui.transform;       // Parent our clones to the original DebugGui so we can move the console around
    24.             guis.Add(clone);                                   // add the gui object to our guis array
    25.             position = clone.transform.position;
    26.             x+=1;
    27.          }
    28.          
    29.          
    30.     }
    31.  
    What happens is when the line:
    Code (csharp):
    1.  
    2. clone.transform.parent = DebugGui.transform;
    3.  
    is not commented out, Unity locks up ("sits and spins") and I have to do a force quit. When I comment it out all is fine. I also tried doing the parenting in a seperate loop afterword which worked fine, except the scale of my dupicated GUITexts was 0,0,0. I then tried to fix that with transform.localScale but that is a relative scale to the original object, and when I put 1,1,0 for the scale, they are far too big. Any idea's? Am I doing something wrong or is this a tricky bug? Limitation?

    Thanks a lot guys,
    -Jeremy
     
  2. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    I'm not sure if this is the case, but that line might make the transform its own parent. I imagine something like that might make Unity go into an infinite loop.

    Can you comment out that line and instead run this code?

    Code (csharp):
    1.  
    2. if (clone.transform == DebugGui.transform)
    3. {
    4.     Debug.Log("They are the same.");
    5. }
    6.  
     
  3. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Well, what's weird is when I do the exact same parenting line as before in a seperate loop using the guis[] array, it works fine except the scale is 0 across the board. When I modify the scale from code, it's the scale relative to the parent so I get sizing issues. I will try your test in the next few mins though.

    -Jeremy
     
  4. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Nope, they are different. You see clone is actually the new instantiated copy of DebugGui, so it shouldn't give me these issues. And it's weird that I can properly parent the GUIs in another loop outside that one. As I said the only error with that is the scaling.

    -Jeremy
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Could you post the entire script or just send it to me, I would like to try this out.
     
  6. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Here you go:
    Code (csharp):
    1.  
    2. //========== DebugGUIController.cs ================
    3. // Class for formatting and displaying multi-line,
    4. // user debug messages with individual line
    5. // coloring.
    6. // Author: Jeremy Hollingsworth
    7. // Version 1.0.2
    8. // Feb-14-2006
    9. //
    10. // USAGE:
    11. // Attach to empty GO then call from any script:
    12. // DebugGUIController.instance.myFunction();
    13. //=================================================
    14.  
    15. using UnityEngine;
    16. using System.Collections;
    17.  
    18.  
    19. public class DebugGUIController : MonoBehaviour {
    20.  
    21. public GameObject DebugGui = null;             // The GUI that will be duplicated
    22. public Vector3 defaultGuiPosition = new Vector3(0.01F, 0.98F, 0F);
    23. public Vector3 defaultGuiScale = new Vector3 (0.5F, 0.5F, 0F);
    24. public Color normal = Color.green;
    25. public Color warning = Color.yellow;
    26. public Color error = Color.red;
    27. public int maxMessages = 30;                   // The max number of messages displayed
    28. public float lineSpacing = 0.02F;              // The amount of space between lines
    29. public ArrayList messages = new ArrayList();  
    30. public ArrayList guis = new ArrayList();      
    31. public ArrayList colors = new ArrayList();    
    32. public bool visible = true;                    // Does output show on screen by default or do we have to enable it with code?
    33. public bool isVisible {                        // Accessor property for visiblility (bool visible)              
    34.    get {
    35.            return visible;
    36.        }
    37.    
    38.    set {
    39.            visible = value;
    40.            if (value == true)
    41.            {
    42.                Display();
    43.            }
    44.            else if (value == false)
    45.            {
    46.                ClearScreen();
    47.            }
    48.        }
    49. }
    50.  
    51. private static DebugGUIController s_Instance = null;   // Our instance to allow this script to be called without a direct connection.
    52. public static DebugGUIController instance {
    53.     get {
    54.         if (s_Instance == null)
    55.         {
    56.             s_Instance =  FindObjectOfType(typeof (DebugGUIController)) as DebugGUIController;
    57.             if (s_Instance == null)
    58.                 Debug.Log ("Could not locate a DebugGUIController object.  You have to have exactly one DebugGUIController in the scene.");
    59.             }
    60.            
    61.             return s_Instance;
    62.         }
    63.     }
    64.    
    65.     void Awake() {
    66.         s_Instance = this;
    67.         if (DebugGui == null)  // If an external GUIText is not set, provide the default GUIText
    68.         {
    69.             DebugGui = new GameObject();
    70.             DebugGui.AddComponent("GUIText");
    71.             DebugGui.name = "DebugGUI(0)";
    72.             DebugGui.transform.position = defaultGuiPosition;
    73.             DebugGui.transform.localScale = defaultGuiScale;
    74.         }
    75.          
    76.          // Create our GUI objects to our maxMessages count
    77.          Vector3 position = DebugGui.transform.position;
    78.          guis.Add(DebugGui);
    79.          int x = 1;
    80.          while(x < maxMessages)
    81.          {
    82.             position.y -= lineSpacing;  
    83.             GameObject clone = null;
    84.             clone = (GameObject)Instantiate(DebugGui, position, transform.rotation);
    85.             clone.name = string.Format("DebugGUI({0})", x);    // Add the current loop number to the DebugGui() name string
    86.             clone.transform.parent = DebugGui.transform;       // Parent our clones to the original DebugGui so we can move the console around
    87.             guis.Add(clone);                                   // add the gui object to our guis array
    88.             position = clone.transform.position;
    89.             x+=1;
    90.          }
    91.          
    92.          
    93.     }
    94.  
    95.  
    96.  
    97.  
    98.     //---------- void AddMesage(string message, string color) ------
    99.     //Adds a mesage to the list
    100.     //--------------------------------------------------------------
    101.    
    102.     public void AddMessage(string message, string color)
    103.     {
    104.        messages.Add(message);
    105.        colors.Add(color);  
    106.        Display();
    107.     }
    108.     //++++++++++ OVERLOAD for AddMessage ++++++++++++++++++++++++++++
    109.     // Overloads AddMessage to only require one argument(message)
    110.     //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    111.     public void AddMessage(string message)
    112.     {
    113.        messages.Add(message);
    114.        colors.Add("normal");
    115.        Display();
    116.     }
    117.  
    118.    
    119.     //----------- void ClearMessages() ------------------------------
    120.     // Clears the messages from the screen and the lists
    121.     //---------------------------------------------------------------
    122.     public void ClearMessages()
    123.     {
    124.         messages.Clear();
    125.         colors.Clear();
    126.         ClearScreen();
    127.     }
    128.    
    129.    
    130.     //-------- void ClearScreen() ----------------------------------
    131.     // Clears all output from all GUI objects
    132.     //--------------------------------------------------------------
    133.     void ClearScreen()
    134.     {
    135.         int x = 0;
    136.         while (x < guis.Count)
    137.         {
    138.             GameObject gui = (GameObject)guis[x];   //find our gui object
    139.             gui.guiText.text = "";
    140.             //increment and loop
    141.             x+=1;
    142.         }
    143.     }
    144.    
    145.    
    146.     //---------- void Prune() ---------------------------------------
    147.     // Prunes the array to fit within the maxMessages limit
    148.     //---------------------------------------------------------------
    149.     void Prune()
    150.     {
    151.     int diff;
    152.         if (messages.Count > maxMessages)
    153.         {
    154.            if (messages.Count <= 0)
    155.            {
    156.             diff = 0;
    157.            }
    158.            else
    159.            {
    160.             diff = messages.Count - maxMessages;
    161.            }
    162.            messages.RemoveRange(0, (int)diff);
    163.            colors.RemoveRange(0, (int)diff);
    164.         }
    165.    
    166.     }
    167.    
    168.    
    169.     //---------- void Display() -------------------------------------
    170.     // Displays the list and handles coloring
    171.     //---------------------------------------------------------------
    172.     void Display()
    173.     {
    174.         //check if we are set to display
    175.         if (visible == false)
    176.         {
    177.            ClearScreen();
    178.         }
    179.         else if (visible == true)
    180.         {
    181.             if (messages.Count > maxMessages)
    182.             {
    183.                Prune();
    184.             }            
    185.        
    186.             // Carry on with display
    187.             int x = 0;
    188.             while (x < messages.Count)
    189.             {
    190.                 GameObject gui = (GameObject)guis[x];   //find our gui object
    191.            
    192.                 //set our color
    193.                 switch ((string) colors[x])
    194.                 {
    195.                     case "normal": gui.guiText.material.color = normal;
    196.                     break;
    197.                     case "warning": gui.guiText.material.color = warning;
    198.                     break;
    199.                     case "error": gui.guiText.material.color = error;
    200.                     break;
    201.                 }
    202.             //now set the text for this element
    203.             gui.guiText.text = (string)messages[x];
    204.            
    205.             //increment and loop
    206.             x += 1;
    207.             }
    208.                  
    209.         }    
    210.     }
    211.    
    212.    
    213. }// End DebugGUIController Class
    214.  
    -Jeremy
     
  7. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    It actually doesn't lock up. It just becomes very very slow.

    The following line is causing it:
    Code (csharp):
    1.  
    2. clone.transform.parent = DebugGui.transform;
    3.  
    Remember that Instantiate instantiates the entire child transform hierarchy.

    You are adding the instantiated gui as a child to to the old DebugGUI object.
    Then you instantiate it again. Which means now you are instantiating 2 Debug GUI's. Next time 4 and so. Until you end up with a couple of hundred thousand Debug GUI's.
     
  8. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Ok, thanks. When I do the parenting in a seperate loop based on my guis array, the scale is 0,0,0 after parenting. When I modify localSale to try to fix it, of course it's the scale relative to the parent so I can't get a proper size (even 1,1,0). What is wrong?
    Is there any way I can modify the scale of the object (like in the inspector) and not just the localScale?

    -Jeremy
     
  9. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    I think there is a problem with parenting if you have one of x, y, z in localScale be zero. Then after parenting all components of the scale will be zero.
    You should never assign a transform.localScale of zero.
     
  10. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    Since variable assignments can have side effects, it would be good to have those side effects documented. It would be especially nice if function and variable documentation had cross references to each other. Certainly nothing too major, but very much a "nice to have."

    BTW, is there a way to get all the immediate childen of a transform?
     
  11. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    You can loop through the children like this:

    Code (csharp):
    1.  
    2. // Javascript
    3. foreach(var child : Transform in transform) {
    4.     child.position = Vector3.zero;
    5. }
    6.  
    7. // C#
    8. foreach(Transform child in transform) {
    9.     child.position = Vector3.zero;
    10. }
    11.  
    Ps. sorry for having posted that bad code... Next time I'd better test my code before posting it. :p
     
  12. jeremyace

    jeremyace

    Joined:
    Oct 12, 2005
    Posts:
    1,661
    Thanks Joe, the parenting was screwing up because my DefaultGui object's scale was 0.01,0.98,0. I changed the last 0 to a 1 and it works perfectly thanks.

    No problem. :D Figuring this out helped me learn more about how this all works.

    Thanks guys,
    -Jeremy
     
  13. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    Thanks -- are there any other objects that act as their own containers? Would it be safe to assume that anything (in Unity) inherting from IEnumerable is essentially self-nesting? (That is, classes that hold instances of the same class without any intermediate variable.)
     
  14. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Transform implements the foreach functionality by implementing a method called GetEnumerator. Transform models a tree of Transform objects, that's why the iterator returns more Transform objects.

    No. It's up to the implementation of the enumerator returned what type of objects are returned.
     
  15. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    [This is mostly rhetorical -- food for thought as the documentation evolves.]

    Thanks -- I guess the next question would be which Unity classes inherit from (or implement) IEnumerable and which classes do their respective enumerators return? (Or is that two questions? :wink:) So, it's not a matter of what's an enumeration (which should be outside the scope of Unity documentation), but rather knowing how they are being used in particular Unity classes, such as Transform.

    I was digging through the script reference class hierarchy and couldn't easily tell which classes implement IEnumerable. Once I started checking every class, I found that Transform not only implements IEnumerable, but also inherits from Component, which really surprised me since it doesn't match with the HTML layout of the class hierarchy page.

    Some relevance -- I need to implement animated eels that swim. The animation is pretty straightforward, but the eels also need to turn in an arbitrary direction. Without programatic access to all the transforms (one for each logical vertebra), then it would mean having a public variable for each vertebra that would have to be set in the inspector. In either case, I was thinking of a "following with oscillations" sort of algorithm.
     
  16. freyr

    freyr

    Joined:
    Apr 7, 2005
    Posts:
    1,148
    Classes in .net can only inherit from one parent class (which is Component in Transform's case.... and yes, you found a bug in our index page generator... :) )

    IEnumerable is not a parent class but an interface (Thus the 'I' in the name.) .Net classes can implement more than one interface. Interfaces do not contain any code. They only guarantee that a class has a set of methods and properties are available. (Which have to exist in the class in order for it to compile.)

    Transform is currently the only class in the Unity libraries that implements the IEnumerable interface, and it is documented at the top of the Transform documentation what the iterator returns.

    For your eel example, iterating through the child transforms should solve your problem.
     
  17. tsphillips

    tsphillips

    Joined:
    Jan 9, 2006
    Posts:
    359
    Ah, now I see the iterator code example in the Transform section.

    I didn't want to split hairs over the terminology. I would normally talk about inheriting from or extending classes, and implementing interfaces. That is, I would normally never talk about inheriting from an interface. I'm just trying to go with the flow of whatever conventions you guys want to use. :wink: