Author Topic: Is there an internal dictionary of widgets ?  (Read 4259 times)

n0mad

  • Guest
Is there an internal dictionary of widgets ?
« on: July 14, 2012, 11:28:28 AM »
Hi there, I've searched the forum but didn't find anything about it :

In order to pool (or just to find easily a widget by name across multiple behaviours), I actually have to hack the UISprite, UIButton, UILabel, etc classes to insert a Awake() / OnDestroy() script that stores/removes the widget's reference into a static Dictionary<string, UISprite/etc>.
This is a pain to maintain as NGUI iterations will go up, so I'd like to know if there's an internal dictionary of all current scene's widgets that I could access by name ?

Thanks


edit : There is the UIPanel.widgets List, but it's only returning a UIWidget type...
« Last Edit: July 14, 2012, 11:52:52 AM by n0mad »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Is there an internal dictionary of widgets ?
« Reply #1 on: July 14, 2012, 01:29:27 PM »
The obvious first question is... why do you need this? If you have to find some widget by name, then you're doing something wrong to begin with. Consider having a script that has a public reference to the widget instead. You can set this reference by just drag & dropping in the inspector.

n0mad

  • Guest
Re: Is there an internal dictionary of widgets ?
« Reply #2 on: July 15, 2012, 07:59:18 AM »
I'm not sure I'm doing anything wrong ;) My framework is huge, and I can't deal with referencing tons of widgets in separate variables for the sake of clarity and accessibility. A simple static Dictionary with key strings would be as much faster (quite), much more simpler to manage, and would save dozens and dozens of manual declarations and sub class searching (class1.hud.widgets.panel3.widgetPack1.thereIAmWoohoo ... oh wait now I'm changing game mode, I have to find the new root class ... etc).
Plus, the whole purpose of the initial question was to know if NGUI could do that work (however it is managing it) so that I don't have to do it manually (kind of like it's starting to be done with UIPanel.widgets). I'm sure it could be of great use for big studios with big projets too (or UI intensive).

Ok, I guess I'll have to stay on the constant hacking way of dealing with it, like with 2DToolkit :/
« Last Edit: July 15, 2012, 09:18:01 AM by n0mad »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Is there an internal dictionary of widgets ?
« Reply #3 on: July 15, 2012, 09:39:29 AM »
Names are unreliable. 3 months down the line you may change a name of some widget without realizing it, and a month later realize that "oh shit, something isn't working" -- and then good luck trying to find what widget you changed and what it was. References, on the other hand... if you change the name or drag a widget elsewhere, they will still work properly.

In Windward, I have a "GamePrefabs" class that's accessible via a singleton reference, placed on a game object saved as a prefab, and I have it present in every scene. This prefab contains references to commonly used prefabs -- cannonball, effect sounds, explosions, etc. So when my scripts want something, such as create an explosion at point A, I simply create a new instance of GamePrefabs.instance.explosion.

If I ever decide to change the explosion, it's as simple as replacing the reference on that one prefab, and all scenes will be automatically affected. I don't have to dig through code and replace some obscure string names.

Another example -- I have a main menu in Windward. This menu has a central script attached to the root of its prefab that references all common components -- sub-windows it can open up, important input fields it needs to know about -- everything that the script needs in order to work, and nothing more. This script is the only place where these references are used.

With proper class design and hierarchy, there is absolutely no need to have something absurd like "class1.hud.widgets.panel3.widgetpack1.thereiam". Furthermore, look into NGUITools.Broadcast (or UIRoot.Broadcast for that matter) -- you can use it to trigger abstract events discretely -- which is a slow operation, but if you don't use it in every Update, perfectly acceptable. It's perfect for when you want to signal an event to some script you don't know the location of (or don't care where it's located), making your code clean, abstract, and without any trace of ugly spaghetti code.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Is there an internal dictionary of widgets ?
« Reply #4 on: July 15, 2012, 09:46:35 AM »
And one last thing.. if you really want to access some small widget -- such as a label -- and set its value -- such as current amount of gold -- then consider approaching it from the opposite end. Instead of the manager setting the value of some widget, have the widget set its own value based on the manager's data. Ie: if you have some "game manager" script that has all the data (like that gold), then make it accessible via a singleton to the rest of the scripts.

Your gold-showing label can then simply have a script that sets the label's text to GameManager.instance.gold.

n0mad

  • Guest
Re: Is there an internal dictionary of widgets ?
« Reply #5 on: July 16, 2012, 03:20:38 AM »
Well, names wouldn't be unreliable if NGUI was storing/pooling them from prefab's name ;)
(just like the way UIAtlas.GetSprite(string name) is working, in fact)

But those were some very good tips, thanks ArenMook :)
« Last Edit: July 16, 2012, 06:18:28 AM by n0mad »

Xanatus

  • Guest
Re: Is there an internal dictionary of widgets ?
« Reply #6 on: July 20, 2012, 07:19:45 AM »
Although its a bad approch, you could use something like this to find widgets by name:

static T[] GetComponentsInChildrenByGOName<T>(Transform root, string name) {
   List<T> rets = new List<T>();
   T[] widgets = root.GetComponentsInChildren<T>();
   foreach(T widget in widgets)
       if(widget.gameObject.name == name)
           rets.Add(widget);
   return rets.ToArray();
}   

use like this:

UIButton[] buttons = GetComponentsInChildrenByGOName<UIButton>(uiRoot, "Ok Button");

or to search in all widgets:

UIWidget[] widgets = GetComponentsInChildrenByGOName<UIWidget>(uiRoot, "Label");


I haven't tested it but I assume it works.
This is a slow method and very bad way of organizing stuff, so I suggest not using it at all, unless you REALY know what you doing.
« Last Edit: July 20, 2012, 08:23:23 AM by Xanatus »