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): void Awake() { s_Instance = this; if (DebugGui == null) // If an external GUIText is not set, provide the default GUIText { DebugGui = new GameObject(); DebugGui.AddComponent("GUIText"); DebugGui.name = "DebugGUI(0)"; DebugGui.transform.position = defaultGuiPosition; DebugGui.transform.localScale = defaultGuiScale; } // Create our GUI objects to our maxMessages count Vector3 position = DebugGui.transform.position; guis.Add(DebugGui); int x = 1; while(x < maxMessages) { position.y -= lineSpacing; GameObject clone = null; clone = (GameObject)Instantiate(DebugGui, position, transform.rotation); clone.name = string.Format("DebugGUI({0})", x); // Add the current loop number to the DebugGui() name string clone.transform.parent = DebugGui.transform; // Parent our clones to the original DebugGui so we can move the console around guis.Add(clone); // add the gui object to our guis array position = clone.transform.position; x+=1; } } What happens is when the line: Code (csharp): clone.transform.parent = DebugGui.transform; 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
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): if (clone.transform == DebugGui.transform) { Debug.Log("They are the same."); }
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
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
Here you go: Code (csharp): //========== DebugGUIController.cs ================ // Class for formatting and displaying multi-line, // user debug messages with individual line // coloring. // Author: Jeremy Hollingsworth // Version 1.0.2 // Feb-14-2006 // // USAGE: // Attach to empty GO then call from any script: // DebugGUIController.instance.myFunction(); //================================================= using UnityEngine; using System.Collections; public class DebugGUIController : MonoBehaviour { public GameObject DebugGui = null; // The GUI that will be duplicated public Vector3 defaultGuiPosition = new Vector3(0.01F, 0.98F, 0F); public Vector3 defaultGuiScale = new Vector3 (0.5F, 0.5F, 0F); public Color normal = Color.green; public Color warning = Color.yellow; public Color error = Color.red; public int maxMessages = 30; // The max number of messages displayed public float lineSpacing = 0.02F; // The amount of space between lines public ArrayList messages = new ArrayList(); public ArrayList guis = new ArrayList(); public ArrayList colors = new ArrayList(); public bool visible = true; // Does output show on screen by default or do we have to enable it with code? public bool isVisible { // Accessor property for visiblility (bool visible) get { return visible; } set { visible = value; if (value == true) { Display(); } else if (value == false) { ClearScreen(); } } } private static DebugGUIController s_Instance = null; // Our instance to allow this script to be called without a direct connection. public static DebugGUIController instance { get { if (s_Instance == null) { s_Instance = FindObjectOfType(typeof (DebugGUIController)) as DebugGUIController; if (s_Instance == null) Debug.Log ("Could not locate a DebugGUIController object. You have to have exactly one DebugGUIController in the scene."); } return s_Instance; } } void Awake() { s_Instance = this; if (DebugGui == null) // If an external GUIText is not set, provide the default GUIText { DebugGui = new GameObject(); DebugGui.AddComponent("GUIText"); DebugGui.name = "DebugGUI(0)"; DebugGui.transform.position = defaultGuiPosition; DebugGui.transform.localScale = defaultGuiScale; } // Create our GUI objects to our maxMessages count Vector3 position = DebugGui.transform.position; guis.Add(DebugGui); int x = 1; while(x < maxMessages) { position.y -= lineSpacing; GameObject clone = null; clone = (GameObject)Instantiate(DebugGui, position, transform.rotation); clone.name = string.Format("DebugGUI({0})", x); // Add the current loop number to the DebugGui() name string clone.transform.parent = DebugGui.transform; // Parent our clones to the original DebugGui so we can move the console around guis.Add(clone); // add the gui object to our guis array position = clone.transform.position; x+=1; } } //---------- void AddMesage(string message, string color) ------ //Adds a mesage to the list //-------------------------------------------------------------- public void AddMessage(string message, string color) { messages.Add(message); colors.Add(color); Display(); } //++++++++++ OVERLOAD for AddMessage ++++++++++++++++++++++++++++ // Overloads AddMessage to only require one argument(message) //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ public void AddMessage(string message) { messages.Add(message); colors.Add("normal"); Display(); } //----------- void ClearMessages() ------------------------------ // Clears the messages from the screen and the lists //--------------------------------------------------------------- public void ClearMessages() { messages.Clear(); colors.Clear(); ClearScreen(); } //-------- void ClearScreen() ---------------------------------- // Clears all output from all GUI objects //-------------------------------------------------------------- void ClearScreen() { int x = 0; while (x < guis.Count) { GameObject gui = (GameObject)guis[x]; //find our gui object gui.guiText.text = ""; //increment and loop x+=1; } } //---------- void Prune() --------------------------------------- // Prunes the array to fit within the maxMessages limit //--------------------------------------------------------------- void Prune() { int diff; if (messages.Count > maxMessages) { if (messages.Count <= 0) { diff = 0; } else { diff = messages.Count - maxMessages; } messages.RemoveRange(0, (int)diff); colors.RemoveRange(0, (int)diff); } } //---------- void Display() ------------------------------------- // Displays the list and handles coloring //--------------------------------------------------------------- void Display() { //check if we are set to display if (visible == false) { ClearScreen(); } else if (visible == true) { if (messages.Count > maxMessages) { Prune(); } // Carry on with display int x = 0; while (x < messages.Count) { GameObject gui = (GameObject)guis[x]; //find our gui object //set our color switch ((string) colors[x]) { case "normal": gui.guiText.material.color = normal; break; case "warning": gui.guiText.material.color = warning; break; case "error": gui.guiText.material.color = error; break; } //now set the text for this element gui.guiText.text = (string)messages[x]; //increment and loop x += 1; } } } }// End DebugGUIController Class -Jeremy
It actually doesn't lock up. It just becomes very very slow. The following line is causing it: Code (csharp): clone.transform.parent = DebugGui.transform; 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.
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
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.
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?
You can loop through the children like this: Code (csharp): // Javascript foreach(var child : Transform in transform) { child.position = Vector3.zero; } // C# foreach(Transform child in transform) { child.position = Vector3.zero; } Ps. sorry for having posted that bad code... Next time I'd better test my code before posting it.
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. Figuring this out helped me learn more about how this all works. Thanks guys, -Jeremy
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.)
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.
[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.
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.
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: