Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Instantiating Panels Help

Discussion in 'Scripting' started by UbiquitousStudio, Oct 31, 2015.

  1. UbiquitousStudio

    UbiquitousStudio

    Joined:
    Oct 11, 2015
    Posts:
    24
    Hello, I have been spending some time on learning how to properly use the UI on a larger project however I am having a couple issues with it. I tried putting a bunch of panels, shaping them, and adding the proper layout elements for everything, but once I hit over a certain (Small) amount of panels it lags my game bad. So I have tried instantiating and destroying panels when needed. There is multiple issues as you can imagine with that and it takes way longer to do a relatively simple setup. What would be the best way to do this with the least amount of code, and gameobjects in game?

    Here is a simple code I put together to explain some issues with instantiating panels I am having.
    The issue is I need to find the transforms and that is slow, if I don't do it the prefabs can't find the proper objects. This is not even getting into button click functions that don't work below. They instantite CareersPanel and SkillsPanel, however even after finding the proper object and setting the parent, it still shows up invisible.

    Thanks

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityStandardAssets.Characters.FirstPerson;
    4.  
    5. public class SP_QMenu : MonoBehaviour {
    6.  
    7.     // Disable FPS Script for QMenu.
    8.     FirstPersonController fpsScript;
    9.  
    10.     // Transforms for the panel spawns
    11.     public Transform qmenuPanelTransform;
    12.     public Transform qmenuRightTransform;
    13.     public Transform qmenuInfoTransform;
    14.  
    15.     // The panels
    16.     [SerializeField] GameObject qmenuPanel;
    17.  
    18.     // Right Panel GameObjects
    19.     [SerializeField] GameObject careersPanel;
    20.     [SerializeField] GameObject skillsPanel;
    21.  
    22.     // Bools to let us know if the menu is opened so players can't spam.
    23.     public bool qmenuOpened = false;
    24.  
    25.     void Start()
    26.     {
    27.         fpsScript = GameObject.Find ("Singleplayer").GetComponent<FirstPersonController> ();
    28.         qmenuPanelTransform = GameObject.Find ("QMenuTransform").transform;
    29.         qmenuRightTransform = GameObject.Find ("QMenuRightTransform").transform;
    30.         qmenuInfoTransform = GameObject.Find ("QMenuInfoTransform").transform;
    31.     }
    32.  
    33.     void Update()
    34.     {
    35.         if (Input.GetKeyDown(KeyCode.Q))
    36.         {
    37.             OpenQMenu();
    38.             qmenuOpened = true;
    39.             fpsScript.enabled = false;
    40.         }
    41.         // This part is being changed later this is just to get controls back.
    42.         if (Input.GetKeyUp(KeyCode.Q))
    43.         {
    44.             fpsScript.enabled = true;
    45.         }
    46.     }
    47.  
    48.     void OpenQMenu()
    49.     {
    50.         if (qmenuOpened == true)
    51.         {
    52.             return;
    53.         }
    54.         GameObject QMenuPanel = (GameObject)Instantiate(qmenuPanel);
    55.         QMenuPanel.transform.SetParent(qmenuPanelTransform, false);
    56.     }
    57.  
    58.     // Main Q Menu Button Functions
    59.     public void CareersButtonPressed()
    60.     {
    61.         GameObject CareersPanel = (GameObject)Instantiate (careersPanel);
    62.         CareersPanel.transform.SetParent (qmenuRightTransform, false);
    63.     }
    64.  
    65.     public void SkillsButtonPressed()
    66.     {
    67.         GameObject SkillsPanel = (GameObject)Instantiate(skillsPanel);
    68.         SkillsPanel.transform.SetParent (qmenuRightTransform, false);
    69.     }
    70. }
     
  2. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,209
    the only Find I see being used is in the Start() ?? Are you creating instances of this over and over and that is slowing you down? I instantiate 20-30 prefabs with 3-4 panels each on button clicks quite often without any lag. I'm not sure what your problem is. I always have a parent Transform adding(instantiating) prefabs straight into predefined lists that the prefabs themselves make use of and/or just report back to their parent. I don't ever need to call Find during runtime, only at Start(). If you are calling Find from Start() on the prefabs maybe you could redesign it so that something always knows where things are like a parent script of a static manager and have the new prefabs request their necessary information from them.
     
  3. UbiquitousStudio

    UbiquitousStudio

    Joined:
    Oct 11, 2015
    Posts:
    24
    Sorry I may of done a terrible explanation on my issue. This is a temporary script I threw together to learn about instantiating panels. It was laggy when I was doing it the other way with animating them into the screen or setting them to active true or false cause their always in the scene. So I am trying to instantiate them instead of that. So far it has been faster and I'm not having speed problems with instantiate. However I am having issues with a few things when instantiating.

    Start is only finding those components because I made a empty gameobject called UIManager and made it a prefab. Since the transforms are in the scene, they don't get found by a prefab. So that is issue number one I worked around by finding them. It's slower and there definitely should be a better way.

    The reason I had to make UIManager a prefab was because it has the button functions on it. If I didn't make it a prefab the button functions are not found. I know there is a way to call it just couldn't find a good explanation on it.

    The last issue is when I click the buttons, they still don't instantiate into the transforms.

    So how would you suggest
     
  4. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,209
    I'm kind of bad at understanding what people are talking about without seeing their face so sorry if something's going over my head. XD

    if it's a button you can assign it an eventhandler like this:
    Code (CSharp):
    1. levelLeftButton.onClick.AddListener(() => { LevelLeftButtonClick(); });
    I assign those from my parent object onto all the buttons in this child giving them their jobs. you can add values to that too if needed.

    turning them on and off was laggy? That doesn't sound right.... I have lots of different windows open at all times some with 20-30 prefabs and panels and text and buttons and stuff and all turn on and off with the push of a button without problems? Even on my slow laptop.

    "Since the transforms are in the scene, they don't get found by a prefab. So that is issue number one"

    I see you instantiating like this:
    Code (CSharp):
    1.  GameObject QMenuPanel = (GameObject)Instantiate(qmenuPanel);
    but it might work better if you have you UIManager have a public GameObject QMenuPanel, then do
    Code (CSharp):
    1.  UIManage.QMenuPanel = (GameObject)Instantiate(qmenuPanel);
    "The last issue is when I click the buttons, they still don't instantiate into the transforms."
    I'm not sure what you mean bu instantiate into the transforms? You want an instantiate to take place when a button is clicked? use the AddListener script above to tell the button to call UIManager.InstantiateButtonClicked() and then have the UIManager instantiate the objects?
     
  5. UbiquitousStudio

    UbiquitousStudio

    Joined:
    Oct 11, 2015
    Posts:
    24
    Okay I read that ten times over now and kind of got a understanding of it.
    I am sort of new to UI stuff and listeners specifically so please stick with me lol.

    I removed all my old set up to start simple. To mostly make sure I got listeners right.
    The script below has one button qmenu and qmenutransform. It spawns the qmenu prefab and sets the parent just fine. If I don't instantiate it the button listener works. When I instantiate it, the button listener stops working. Do I need to add a script to that panel so that when it spawns on start it adds the listener?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.UI;
    4.  
    5. public class SP_UIManager : MonoBehaviour {
    6.  
    7.     public Button careersButton;
    8.  
    9.     // Move this later to another script.
    10.     public GameObject qmenuPanel;
    11.     public Transform qmenuTransform;
    12.  
    13.     void Start ()
    14.     {
    15.         careersButton.onClick.AddListener(() => { MyFunction(); });
    16.     }
    17.  
    18.     void Update ()
    19.     {
    20.         if (Input.GetKeyDown(KeyCode.Q))
    21.         {
    22.             GameObject QMenuPanel = (GameObject)Instantiate(qmenuPanel);
    23.             QMenuPanel.transform.SetParent(qmenuTransform, false);
    24.         }
    25.     }
    26.  
    27.     void MyFunction()
    28.     {
    29.         Debug.Log ("Pressed a Button");
    30.     }
    31. }
     
  6. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,209
    Anything you instantiate is brand new and will not be linked to anything unless some code somewhere specifies so. For most of my buttons they have a name to report back to their parent so I use

    Code (CSharp):
    1. Button newButton = Instantiate(MyButtonPrefab);
    2. newButton.GetComponent<MyButtonScript>()._name = buttonName;
    3. newButton.GetComponent<MyButtonScript>().Refresh();
    The Refresh() is a manual Start() that I program into a lot of things that makes it set itself up changing the buttons text to the _name, etc. Start() won't happen until the next frame and sometimes that causes problems.

    on the button itself it has

    Code (CSharp):
    1. public void OnPointerClick (PointerEventData eventData) {
    2.         UserInterface.RecipeUI.GetComponent<RecipeUI>().ButtonClick(_name);
    3.     }
    the UserInterface is static so the button can easily orient itself with its location.

    In your case you're creating QMenuPanel anew and setting its parent, but the onClick.AddListener and careersButton are completely disconnected to the new instantiation. If for example the QMenuPanel has a Button child you could locate you could then use the onClick.AddListener on that button and it would properly report back. In that case it works better to have a script on the QMenuPanel to locate the button using transform.FindChild(), or after you instantiate it use QMenuPanel.FindComponentInChildren<Button>() which will find the first Button it sees in order. Using GameObject.Find will look through the whole scene and shouldn't be used frequently.

    That way the manager script adds the listener to what it instantiated pointing to itself. you could have the button add it to itself if the manager is static or easy to find as well.
     
    UbiquitousStudio likes this.
  7. UbiquitousStudio

    UbiquitousStudio

    Joined:
    Oct 11, 2015
    Posts:
    24
    Thanks for that description. I gave me a much better understanding on it. I had a good idea it was not running because I know instantiating stops things like that. I just didn't realize the way around it.

    What I did was just removed the click event completely from UIManager and put it on a new script, added it to the QMenu prefab and it works now. Basically it's just adding the event when it opens the panel. Now I get the fun part of figuring out multiple panels, prefabs, and buttons lol.

    I thank you for your help, I hope others read this and learn from it.
     
    malkere likes this.
  8. malkere

    malkere

    Joined:
    Dec 6, 2013
    Posts:
    1,209
    I figured all this out less than six months ago myself =]
    Glad I could help.