Author Topic: Never use Instantiate(). Use gameObject.AddChild.  (Read 34404 times)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Never use Instantiate(). Use gameObject.AddChild.
« 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.
« Last Edit: March 17, 2016, 07:13:41 AM by ArenMook »

JumpCore

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 18
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #1 on: September 20, 2014, 03:41:01 PM »
Quote
Think of the children! Save a life by using AddChild instead.

Hah! lol

Bradamante3D

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 79
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #2 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 you have explicitely stated why AddChild can not be used in the case of UIGrid. Is the official policy changing?
#301224014, #301432336, #302399130

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #3 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.

Bradamante3D

  • Jr. Member
  • **
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 79
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #4 on: September 21, 2014, 03:27:41 PM »
Hm you probably overlooked the link, *here* is it again.
#301224014, #301432336, #302399130

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #5 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. }

troutmonkey

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #6 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.

troutmonkey

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #7 on: October 01, 2014, 10:00:55 PM »
EDIT: Nope, I'm an idiot.  Fixed it.
« Last Edit: October 01, 2014, 10:43:30 PM by troutmonkey »

bariscigal

  • Newbie
  • *
  • Thank You
  • -Given: 2
  • -Receive: 0
  • Posts: 15
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #8 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
« Last Edit: January 23, 2015, 08:07:10 AM by bariscigal »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Never use Instantiate(). Use NGUITools.AddChild.
« Reply #9 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.