Hello everyone,
I am currently working on a huge project and most of it is done. Now I am doing GUI stuff.
Well, I have a few buttons in a re-orderable Grid ScrollRect. All of these buttons have the same children and scripts attached to them, currently only one script (I have one prefab for all buttons).
One child of each button is an empty GameObject which is the parent of two other children (UI Buttons). The empty GameObject is disabled by default. With the help of my script I can use the “On Click()” function of the ‘Button’-Component to disable and enable my empty GameObject when the button (parent of all children) gets clicked. Working as it should.
Now to my problem. I am now trying to disable the empty GameObject (which still is the parent of two other UI buttons), if it’s currently enabled, when I click on another button in my Scene, and then the clicked button should enable its empty GameObject. I hope you understand what I am saying.
If not, here is what I want:
I tried it with different techniques and searched a long time for it, went through many forums, especially the unity forum, but nothing helped or was a solution for what I want to achieve. I read something about using EventSystems, but I couldn’t get it to work so I concentrated on another possible solution.
Now I tried to search for each button and get the ‘Button’-Component of each empty GameObjects children, of each button. It’s confusing, I know. And maybe it is as simple as searching for gameObjects with tag but I don’t know what I should try next.
And btw. here is my code for the Buttons:
ShowUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ShowUI : MonoBehaviour
{
bool isActive = false;
// The gameobject being activated or deactivated
GameObject theGameobject;
GameObject otherButton;
public void ShowGameObject ()
{
theGameobject = transform.FindChild("Buttons").gameObject;
if (isActive == false)
{
theGameobject.SetActive(true);
isActive = true;
cardEnabled = true;
}
else if (isActive == true)
{
theGameobject.SetActive(false);
isActive = false;
cardEnabled = false;
}
}
public void HideOther()
{
GameObject[] otherButtons = GameObject.FindGameObjectsWithTag("card");
foreach (GameObject button in otherButtons)
{
otherButton = button.transform.FindChild ("Buttons").gameObject;
Debug.Log (otherButton.name);
}
if (cardEnabled = true)
{
otherButton.SetActive(false);
isActive = false;
}
}
}
I know it isn’t the best code in ‘HideOther()’, I just tried something at, wait… oh, it’s 1 am now… well, I am going to sleep to now, hopefully someone can help me or at least leads me in the right direction. ^^
So , if you have x number of buttons with an empty child, and each empty child has 2 UI Buttons?
If I have that part correct, I would consider making a static “CurrentlyActive” empty gameObject reference.
Be sure to check if this is null before you try to disable it (only if non-null), and if it’s not null and not the new one you’re activating, then de-activate it.
public class YourScript : MonoBehaviour {
protected static GameObject CurrentlyActive;
// inside ShowGameObject
// if it was off...
if(CurrentlyActive != null) CurrentlyActive.setActive(false);
CurrentlyActive = // gameObject or null depending if you just turned this one on or off.
Yes, I have x number of buttons, for example 10. Now every single button has an empty child, and this child has two UI buttons as children.
Okay, I will try that as soon as I can, thank you! Could you explain what the static empty gameObject reference exactly is for and why it has to be protected? I can’t remember if I saw something like this before or not.
protected part is not necessary: ‘protected’ simply means that only the class (or any derived class) can access that member.
What it does is like this… you wanna activate the empty object, so you click your button and activate it.
now, you assign the one you activated to this new variable i mentioned.
because it’s static, there’s only ever 1 of them in the class (so 10 scripts means they all access this one variable for currentlyActive)
Now, when you activate a new object and want the old one to be disabled, you have a “memory” of which one is currently on so you can turn it off. That make sense?
Ah okay, I tested it and it works good, thank you, but not perfect.
I can click on a button and the empty GamObject of this button gets enabled, if I click the same button again the empty GameObject gets disabled, just like before.
When I now click on a button (empty GameObject gets enabled) and then not disable the empty GameObject with the same button I pressed the first time rather pressing another button and disable the empty GameObject of the first button and enable the empty GameObject of the new button :)confused:) I cannot enable the empty GameObject of the first button again if I click it, only after pressing twice and also the GameObject of the new button then doesn’t gets disabled, because I think it is still enabled in the script attached to it, but disabled in the script of the other button.
Hard to explain, easier to understand by watching this (don’t know why this isn’t visible, just click on the error picture or the Link):
Okay, I think I see the problem…And yes, it was slightly difficult to follow what you said and I have gifs disabled in my browser so I don’t think I can watch that.
This code snippet replaces the part from else if(isActive == false) etc
else // don't really need else if since it's a bool ;)
{
// as I understood it, you can have only 1 'on' at a time, so if this 'else' statement is reached, the current active object must be this one.. and since you're about to disable it, just set the currenctlyActive to null
CurrentlyActive = null;
theGameobject.SetActive (false);
isActive = false;
}
You can also simplify : if(isActive == true) to simply: if(isActive) (means exactly the same thing, just shorter to type, if you’re comfortable doing that.)
If a problem is still happening… I am a tiny bit confused. Let me know how it goes.
Finally got the gif to play, and I see what you mean at least for future reference if it’s not working later
I am not sure if I understood exactly. You said I should replace the part from else if (isActive == false) which doesn’t exist, but I guess you meant else if (isActive == true).
So I replaced this part with your code, unfortunately it doesn’t change anything.
I still have the same problem as before… I don’t know how I should explain it better without using pics/gifs
ShowUI.cs with your script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ShowUI : MonoBehaviour
{
protected static GameObject CurrentlyActive = null;
bool isActive = false;
// The gameobject being activated or deactivated
GameObject theGameobject;
public void ShowGameObject ()
{
theGameobject = transform.FindChild ("Buttons").gameObject;
if (isActive == false)
{
if (CurrentlyActive != null)
{
CurrentlyActive.SetActive (false);
}
CurrentlyActive = theGameobject;
theGameobject.SetActive (true);
isActive = true;
}
else // this was 'else if (isActive == true)' and not 'else if (isActive == false)' :P
{
CurrentlyActive = null;
theGameobject.SetActive (false);
isActive = false;
}
}
}
oh my goodness, I found the problem lol… a “duh” moment.
We are never setting “isActive” to its new state when changing the static variable.
So there are 2 options.
we do not use "isActive’ but rather check “isActiveSelf” or “activeinHierarchy” (sp?)
we get the ShowUI component and set that, as well.
Hi, it’s me again. ^^
Unfortunately, I have a new small problem.
I know how you can disable scripts from another script. But my biggest problem here is to find the part where I can enable the attached scripts again when another button was clicked and disable it from the previous button.
To make it clear:
I want to disable every PropertiesOfButton.cs script (which is attached to each button) when a button was clicked, except the attached script of the currently clicked button. Now, if I click another button, I want to disable the script of the previous clicked button and enable it for the new button which was clicked. It works that it disables it when clicking, but I can’t find the part where I should enable it again… I thought it has to be in ‘else’ but that doesn’t work.
I think it’s too late for my brain… as always ^^
This is my current ShowOrHideUI.cs script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ShowOrHideUI : MonoBehaviour
{
// The gameObject which is currently active
protected static GameObject currentlyActive = null;
// The gameObject being activated or deactivated
GameObject theGameobject;
// All other buttons
GameObject[] otherButtons;
// Boolean for checking if active or not
bool isActive = false;
public void ShowOrHide()
{
// create an array for all buttons which will be disabled when clicking another button
otherButtons = GameObject.FindGameObjectsWithTag("button");
// find the gameObject we want to activate/deactivate
theGameobject = transform.FindChild("UIElements/Buttons").gameObject;
// check if the gameObject isn't activated
if (isActive == false)
{
// check if the variable of the currently activated gameObject isn't null
if (currentlyActive != null)
{
// set the boolean 'isActive' in the 'ShowUI'-Component of the parent to false
currentlyActive.GetComponentInParent<ShowOrHideUI>().isActive = false;
// deactivate the currently activated gameObject
currentlyActive.SetActive(false);
}
// The currently activated gameObject is the gameObject
currentlyActive = theGameobject;
// activate the gameObject
theGameobject.SetActive(true);
// set the boolean 'isActive' to true
isActive = true;
// go through the array of all buttons and disable every PropertiesOfButton script except of the current button
foreach (GameObject button in otherButtons)
{
if (button == gameObject)
{
continue;
}
else
{
button.GetComponent<PropertiesOfButton>().enabled = false;
}
}
}
else
{
// currently activated gameObject is null
currentlyActive = null;
//deactivate the gameObject
theGameobject.SetActive(false);
// set the boolean 'isActive' to false
isActive = false;
}
}
}
Before I get into this, again… Are properties of Button script(s) somewhere on the same object as the as each ShowUI script, too? Like the same buttons you were hiding and showing, do they have those new scripts? That would make me think of a certain way to approach this… if they’re not, I’d think up something else (Haven’t thought too much, yet)
but if you let me know that part, I’ll think more
Okay, so I forget exactly how the structure of your buttons looks like lol. I kinda remember but I don’t want to make an incorrect guess.
However, what I was thinking was you can use: GetComponent (if it’s just 1) or GetComponents(if it’s more than 1)
on the game object that you are looking to disable its scripts.
I assume these are the buttons that never unhide, as i recall your setup… not their children.
Remember how we made a CurrentlyActive reference?
We can use that same object to disable the last ones open, and then we can just get the component on the new one we’re activating and enable it.
You already did the first part in a longer kinda way, just turned everything off on every other button (not just the last one). that’s cool.
** You can read from just the part forward if you want lol **
If you wanna keep your loop the way it is, see where you check : if (button == gameObject) in the loop? Just set it on there. This is the loop where you are disabling the component scripts.
just to give my two cents. if I were to write this I would simply have the OnClick trigger a static event that turns off all propertybuttons, unconditionally including its own buttons. Then a second invoke within the same onclick would enable the child propertybuttons
public static UnityEvent OnHideAll = new UnityEvent();
private void Awake()
{
OnHideAll.AddListener(Hide);
}
private void OnDestroy()
{
OnHideAll.RemoveListener(Hide);
}
public void Hide()
{
gameObject.SetActive(false);
}
public void HideAll()
{
OnHideAll.Invoke();
}
public void Show()
{
gameObject.SetActive(true);
}
}
this way the context of the button’s behaviours can primarily be controlled in the inspector. plus the hooks make it easier for non-button sources to also close your UI.