Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: ArenMook on September 19, 2014, 08:24:07 PM

Title: Never use Instantiate(). Use gameObject.AddChild.
Post by: ArenMook on September 19, 2014, 08:24:07 PM
I have to repeat myself every single day here. Never use Object.Instantiate() when working with NGUI. Use gameObject.AddChild instead. Why? Because AddChild does this:

1. Sets the game object's layer (VERY IMPORTANT!)
2. Sets the game object's parent (also very important!)
3. Resets the position/scale
4. Works with Undo functionality

If you use Instantiate, then you are shooting yourself in the foot by creating your UI element in the middle of nowhere, orphaned without a parent. Think of the children! Save a life by using AddChild instead.
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: JumpCore on September 20, 2014, 03:41:01 PM
Quote
Think of the children! Save a life by using AddChild instead.

Hah! lol
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: Bradamante3D on September 21, 2014, 08:39:04 AM
Well, there are reasons why people use Instantiate() over AddChild().

Just like other NGUI users, I have a UIGrid that gets populated dynamically. In Editor mode, I simply don't know how many children the UIGrid will have. So, I need to populate the UIGrid via:

  1. foreach ( string shipName in tradedShips ) {
  2.  
  3.         GameObject b = (GameObject)Instantiate ( buttonGenericGo, Vector3.zero, Quaternion.identity );
  4.         b.transform.parent = transform;
  5.         b.transform.localScale = Vector3.one;
  6.         NGUITools.SetActive ( b, true );
  7.         }
  8.  

and then call Reposition(). In earlier versions of NGUI that did not work. As a fix, I used a Scrollview-as-second-camera setup in the past. But then, a changing number of UIGrid children would leave the UIGrid or scrollable content in the wrong position. Somewhere in the 3.6.x range of upgrades you introduced fixes for that (wasn't it related to the Start function?). Right now I am using NGUI v3.6.9 and I am somewhat hesitant to upgrade, since now it works.

Here (http://www.tasharen.com/forum/index.php?topic=10055.msg47262#msg47262) you have explicitely stated why AddChild can not be used in the case of UIGrid. Is the official policy changing?
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: ArenMook on September 21, 2014, 08:50:23 AM
I started that AddChild cannot be used with UIGrid? Where? It's just fine. If your example replaces Instantiate with AddChild(gameObject, buttonGenericGo), then it will work as expected.
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: Bradamante3D on September 21, 2014, 03:27:41 PM
Hm you probably overlooked the link, *here* (http://www.tasharen.com/forum/index.php?topic=10055.msg47262#msg47262) is it again.
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: Nicki on September 21, 2014, 07:58:30 PM
Bradamente3D I think you're confusing two different things. "Adding to the grid" means parenting an existing gameobject to that grid, and you do that with

  1. myobject.transform.parent = grad.transform;

When Instantiate/NGUITools.AddChild does is to create a new gameobject from a prefab. The Addchild method just does a few things more than the raw Instantiate, which copies the prefab as is. AddChild makes sure the newly created gameobject is parented and layered correctly, and resets position, scale and rotation to Vector3.zero,Vector3.zero,Vector3.one respectively. Addchild also uses the code bit above, you just provide the parent through the method.

You could do your code like this just fine:

  1. foreach ( string shipName in tradedShips )
  2. {
  3. var b = NGUITools.AddChild(transform.gameObject, buttonGenericGo);
  4. b.name = shipname; //always name nicely. ;)
  5. NGUITools.SetActive(b,true);
  6. }
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: troutmonkey on October 01, 2014, 09:22:41 PM
After some fiddling about I managed to get AddChild working, but here's the problem I ran into.

The prefab has to be a GameObject. Have the prefab be a Transform or custom MonoBehaviour script will instead create an empty gameObject. It would also be cool if there was a method that set the position as well - AddChild(GameObject parent, GameObject prefab, Vector3 position). Would save an extra line of code.
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: troutmonkey on October 01, 2014, 10:00:55 PM
EDIT: Nope, I'm an idiot.  Fixed it.
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: bariscigal on January 23, 2015, 04:30:05 AM
Hello is there a reason this line doesn't change the layer and its children tree recursively?

go.layer = parent.layer;

I will change it to

  1. foreach (Transform trans in go.GetComponentsInChildren<Transform>(true))
  2.                         {
  3.                                 //go.layer = parent.layer;
  4.                                 trans.gameObject.layer = parent.layer;
  5.                         }

but couldn't be sure why you have left it out
Title: Re: Never use Instantiate(). Use NGUITools.AddChild.
Post by: ArenMook on January 23, 2015, 09:53:40 PM
go.layer simply sets the game object's layer. Its children are different game objects. This isn't an NGUI question.

Use NGUITools.SetLayer to do it recursively.