Author Topic: Add contents dynamically to Grid  (Read 34789 times)

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Add contents dynamically to Grid
« on: June 06, 2012, 05:37:37 PM »
Hi,

I have a store and inventory as different UIPanels (both containing their own UIGrid) in my game and now I'm coding the following script to dynamically instantiate items bought from the store into the UIGrid of the inventory:

  1. public class InventoryGUI : MonoBehaviour {
  2.        
  3.         public static InventoryGUI instance;
  4.        
  5.         public UILabel labelLoading;
  6.         public GameObject listGridRoot;
  7.         public GameObject listItemPrefab;
  8.        
  9.         void OnEnable () {
  10.                 instance = this;
  11.                 labelLoading.enabled = true;
  12.                 StartCoroutine(LoadInventory());
  13.         }
  14.         void OnDisable () {
  15.                 instance = null;
  16.                 if (listGridRoot) {
  17.                         foreach (Transform item in listGridRoot.transform) {
  18.                                 Destroy(item.gameObject);
  19.                         }
  20.                 }
  21.         }
  22.        
  23.         IEnumerator LoadInventory() {
  24.                 Debug.Log("Load Inventory: " + Inventory.instance.items.Count);
  25.                 for (int i = 0; i < Inventory.instance.items.Count; i++) {
  26.                         StoreInfo info = Inventory.instance.items[i].info;
  27.                        
  28.                         GameObject item = NGUITools.AddChild(listGridRoot, listItemPrefab);
  29.                         item.name = "InventoryItem" + i;
  30.                         item.transform.FindChild("Name").GetComponent<UILabel>().text = info.displayName;
  31.                         item.transform.FindChild("Description").GetComponent<UILabel>().text = info.description;
  32.                 }
  33.                 yield return new WaitForEndOfFrame();
  34.                 listGridRoot.GetComponent<UIGrid>().Reposition();
  35.                 yield return new WaitForEndOfFrame();
  36.                 labelLoading.enabled = false;
  37.         }
  38. }
  39.  

The two panels are disabled by default and then enabled when clicking their respective buttons on the menu (through the common UIButtonPlayAnimation).

If I open first the store, buy one or more items, close it and finally open the inventory then everything works fine. But if I open first inventory (so its Grid is empty), then open the store, buy one or more items and finally re-open the inventory then it doesn't display anything, even if I saw the instantiated items in the hierarchy on editor. I tried to add the above "WaitForEndOfFrame" to see if it could be a rendering issue in time but it isn't... they are not displayed even if I play with transform's Z on either object in the UI root.

Any suggestion on what could it be the problem?

Thanks
Skared Creations
Game Development Studio
http://skaredcreations.com

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Re: Add contents dynamically to Grid
« Reply #1 on: June 06, 2012, 06:02:37 PM »
Ok, I fixed it adding the following code after the "for" loop:

  1. // Wait for the end of frame, else the UIDraggablePanel is still disabled
  2. yield return new WaitForEndOfFrame();
  3. listGridRoot.transform.parent.GetComponent<UIDraggablePanel>().ResetPosition();
  4. listGridRoot.GetComponent<UIGrid>().Reposition();
  5.  
Skared Creations
Game Development Studio
http://skaredcreations.com

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Re: Add contents dynamically to Grid
« Reply #2 on: June 07, 2012, 01:29:07 PM »
Hello again,

As mentioned I managed to add items dynamically to UIDraggablePanel+UIGrid, but I found a problem where I am stuck now: when I destroy an item (e.g. when the player click on an item in the inventory, the real item prefab will spawn and so the UIDraggablePanelContents must be destroyed to not appear again in the inventory panel).

I am using the following code to destroy the content and refresh the list:

  1. // this script is attached to the UIDraggablePanelContents
  2. NGUITools.DestroyImmediate(gameObject);
  3. // myGrid is a reference to the UIGrid
  4. myGrid.Reposition();
  5. myGrid.transform.parent.GetComponent<UIDraggablePanel>().ResetPosition();
  6.  

The problem is that sometimes (not ever, but very often) the item is destroyed but the grid is rendered with an empty space where it was the destroyed cell, even if I can see in the hierarchy that the grid was correctly repositioned because its orange bounds in the editor window are correctly resized and the other items were repositioned correctly but not drawn.

Is it the correct way to remove an item from an UIGrid or I'm doing it wrong?

By the way I'm targeting iOS as output platform (using NGUI 2.0.7c), and this happens also to a modified version of the "Scroll View" example shipped with the library that you can try yourself from the attachment (it will need to be imported in a project where there is already NGUI imported).

This is very urgent, since the release date of the game is very soon and the GUI is the last thing missing.
Thanks

EDIT: I forgot to mention that as soon as I drag the list (or destroy the first element of the grid, after having destroyed another one in the middle) it is again correctly rendered without the empty space in the middle, so I'm guessing if there is a method to force the render update. I also tried to move the destroy script on another GameObject passing the object to be destroyed, but the result is the same, the object is destroyed but the grid is wrongly rendered with an empty space.
« Last Edit: June 07, 2012, 01:43:04 PM by Skared Creations »
Skared Creations
Game Development Studio
http://skaredcreations.com

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Add contents dynamically to Grid
« Reply #3 on: June 07, 2012, 03:19:17 PM »
The way Unity works, deleting an object does not delete it immediately. The call is delayed until the frame ends.

Since you are calling Reposition() right away, it will happily use the "deleted" object. What you need to do is unparent the object, delete it, and only then call reposition. You can also use "repositionNow = true" instead, but it may or may not work -- depends on the order of script execution.

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Re: Add contents dynamically to Grid
« Reply #4 on: June 07, 2012, 04:23:36 PM »
Unfortunately unparenting it didn't make any difference, here is the code (called from another GameObject called through a SendMessage from the deleting UIDraggablePanelContents):

  1. IEnumerator DeleteMe (GameObject go) {
  2.         go.transform.parent = null;
  3.         DestroyImmediate(go);
  4.         yield return new WaitForEndOfFrame();
  5.         myGrid.Reposition();
  6.         myGrid.transform.parent.GetComponent<UIDraggablePanel>().ResetPosition();
  7. }
  8.  

and it's still the same behavior, here is a screenshot when I try to delete an object in the middle:



and again if I drag the panel to scroll after the destroy then the grid is rendered correctly. Isn't there a function I can call to force the render update?
« Last Edit: June 07, 2012, 04:25:16 PM by Skared Creations »
Skared Creations
Game Development Studio
http://skaredcreations.com

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Re: Add contents dynamically to Grid
« Reply #5 on: June 07, 2012, 06:36:55 PM »
mh.. well, until I'll find an acceptable solution for now I'm using for now the following hack:

  1. // Hack: simulate a drag upwards on the UIDraggablePanel to update the render of deleted item
  2. myPanel.SendMessage("MoveAbsolute", new Vector3(0, 0.001f, 0));
  3.  

Of course I would prefer a fix, also because this little hack scroll the panel to the first item of the grid (it should be better to scroll only very few points before the current content, but at list it avoids now the empty destroyed cells).
Skared Creations
Game Development Studio
http://skaredcreations.com

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Add contents dynamically to Grid
« Reply #6 on: June 08, 2012, 02:16:59 AM »
You can try calling UIPanel.Refresh().

Skared Creations

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 12
    • View Profile
    • Skared Creations
Re: Add contents dynamically to Grid
« Reply #7 on: June 08, 2012, 02:45:39 AM »
Oh finally I got rid of it, unchecking the parameter "Static" in the UIDraggablePanel properties did the trick... I didn't understand what it would be used for, since it was checked in the Scroll View example scene.
Skared Creations
Game Development Studio
http://skaredcreations.com

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Add contents dynamically to Grid
« Reply #8 on: June 08, 2012, 03:29:51 AM »
Marking something as "static" means the contents won't change. In the example the contents don't change.

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Add contents dynamically to Grid
« Reply #9 on: June 08, 2012, 05:54:06 AM »
Static panels gives you a bunch of performance, so if you never change the contents, it's a good thing to have on. ;)

kennard.laviers@gmail.com

  • Guest
Re: Add contents dynamically to Grid
« Reply #10 on: October 24, 2013, 11:27:29 AM »
I had this same problem and for me it was caused by UIOffset which automatically attached to button widgets.