- Home /
Create Dynamic buttons with info and update in new Unity 4.6 UI
Hi there
I have decided to give the 4.6 UI another go and have come up against a brick wall, hope somone can help me.
I have a number of characters (the number goes up and down) and each one has a: health bar, name and level and i would like them displayed in the top left but using the new Unity 4.6 UI. This is quite simple using GUILayout, as below, but i am strugling with the new UI
here is the older stlye GUILayout method, I have stripped this down to the basics:
[SerializeField]
GameControlScript _gameControlScript;
void OnGUI(){
TempDisplayFunction();
}
void TempDisplayFunction(){
int y = 0;
int x = 0;
Transform[] allChildren = _gameControlScript.GetComponentsInChildren< Transform >();
foreach(Transform child in _gameControlScript.gameObject.transform){
GUI.DrawTexture(new Rect(0,0, 284f, 22f), background);
GUILayout.BeginArea(new Rect(x+=2,y+=2, 64f, 24f), healthBarBG);
x-=2;y-=2;
GUILayout.EndArea();
GUI.Box(new Rect(75, y, 100.0f, 20f), "[ "+child.GetComponent<NavCharScript>().rank.ToString()+" ]");
GUI.Box(new Rect(120, y, 184f, 19f ), child.GetComponent<NavCharScript>().nameFull);
}
}
I really just need to get the names showing as dynamic buttons that would change if i renamed a character, the rest i should be able to work out.
I really can't get my head around it, thanks in advance.
P.S. Hope the moderators post this one
Answer by Mmmpies · Feb 17, 2015 at 09:12 AM
Create a parent panel where you want the buttons to appear, set the pivot to the top center and put a content size filter on the panel (Add Component) set the vertical to minimum. Also give it a vertical layout group on the panel. Untick the force expand for height.
Now create a prefab button and by button you can use a button or a panel with several child elements. Add a Layout Element and set the minimum height to whatever looks right for your button.
The instantiate the prefab just as you would any gameObject and set it's parent panel to the RectTransform of the panel.
This probably isn't a good idea as I've got no access to Unity at the moment so this is just from memory (which is bound to work):
using UnityEngine.UI; // add this at the top
public GameObject MyButtonPrefab;
public RectTransform ParentPanel;
// To instantiate
GameObject newButton = (GameObject)Instantiate(MyButtonPrefab, Vector3(1,1,1), Qauternion.identity);
newButton.transform.SetParent(ParentPanel, false);
newButton.transform.localScale = new Vector3(1, 1, 1);
newButton.name = "myPlayerName";
Of course you'll likely want to get the components on your panel and set them accordingly but that's just like any GameObject where you can GetComponent or GetChild and set Text fields as you want.
If you want to click on the panel/button add an Event Trigger to it and Add a Pointer Click event.
Like I said no access to Unity but even if it doesn't fully answer hopefully it'll set you in the right direction.
Thanks $$anonymous$$mmpies
This looks like it only instantiates the Buttons, but how can i keep the informatin in them up to date with the players health etc as this changes each frame?
Like the example, in my OP; legacy GUI can loop through all children and draw gui elements, then get the info from each child such as name and health, and display this on the screen.
See where I set the name, just instantiate the button/panel and give it a unique name. Whereever you want to update just GameObject.Find for that name and you can set the child objects as you would normally.
Or add each item to a GameObject List Array as you instantiate them and then update them from that.
This is the first method
private int playerNo = 0;
//then when you instantiate the newButton set the name
newButton.name = "Player-" + playerNo.ToString();
playerNo ++;
you can then GameObject.Find("Player-0") and reference any objects under there. Or, as you'll likely want to list through them:
for(int i = 0; i < playerNo; i++)
{
string findGO = "player-" + i.ToString();
GameObject tempGO = GameObject.Find(findGO);
tempGO.Getcomponent<Text>().text = "PLAYER" + i.ToString();
}
Not got access to Unity at the mo so just example code, and I'd be amazed if there were no errors!
Hope it helps.
Answer by dc. · Feb 17, 2015 at 01:29 PM
Thank you for the answers, i will give this some consideration.
I believe that the find method is not the best practice since i have quite a few GameObjects.
A thought just occured to me, i could instantiate the player and the button at the same time, then store the button (or reference to it) on the player thus making it easier to referencce, what do you think?
public GameObject MyCharacterPrefab;
public GameObject MyButtonPrefab;
public GameObject MyCanvas;
public RectTransform ParentPanel;
// instantiate MyCharacterPrefab
// instantiate MyButtonPrefab to the MyCanvas
// assign MyButtonPrefab to Script attached to MyCharacterPrefab
is Canvas a game object?
I would need then to get the script on the canvas to get its children and place them n the screen with the correct spacing, simple enough
$$anonymous$$issed this as you put it as an answer rather than a comment, is it supposed to be an answer as you appear to be asking questions in it?
If not click more under it and convert to comment.
Anyway any UI element can be accessed as a GameObject.
No harm in doing what you suggested, say you instantiate a GameObject newPlayer and another newButton. The player prefab has a script on it called $$anonymous$$yLinks and a "public GameObject myButton". When you instantiate the two you could do:
newPlayer.GetComponent<$$anonymous$$yLinks>().myButton = newButton;
Not tested but should work.
Your answer
Follow this Question
Related Questions
UI 4.6: custom anchors breaking sizeDelta 0 Answers
Unity 4.6 ui restrict eventSystem only to keyboard input 3 Answers
Canvas Button OnClick() function arguments 1 Answer
How to achieve this desired render order with the new 4.6 UI? 2 Answers
UI layout got messed up after transferring project files! 1 Answer