I am trying to find out in the hierarchy if myButton is Intractable or not? You can GameObject.Find(“myGameObject”), but not a button?
I can’t find a reason it is not available in the button class, seems like a no brainer?
I’m trying to do this…
Button Obj = Button.Find("myButton").GetComponent<Button>();
if(Obj.interactable == false){
print("Call returned, the button is not clickable");
return;
}
I tried to create a ‘public Button myButton’ in the script of my prefab but it is not allowing me to drag the button from the hierarchy to the prefab, which is understandable. So once it is Instantiated I need to identify if it is intractable or not.
Components don’t have names, so there wouldn’t be any way for that to work. I can’t see how your code would be any different from using GameObject.Find anyway, so you could just do that instead. However it would be better to simply keep a reference to the object that you instantiate; in most cases you shouldn’t really use GameObject.Find.
This sounds more like a design problem than a technical one. I don’t see any reason why you would need to be checking for whether or not the button is interactable. If it’s clicked then the UnityEvent it fires is what should be executing any code you want to run on click, and the interactable boolean shouldn’t be used as a flag for some game state.
Anyway, you’re probably looking for GameObject.Find, not Button.Find. You can also just drag the button into the public variable of the gameobject in the scene, not the prefab.
Well, a Button is an object is it not, not a GameObject but a UIObject? The Button object has a Component that is called Button which has the Intractable bool I am trying to reach?
Not to get to descriptive, but players set up their pieces in which time the fire button is disabled. They can only up defense items in the beginning. By checking if the fire button is disabled prevents them from setting up the weapon before they can fire. It has caused some crashes so the easiest thing is to check to see it the fire button has it’s interactivity set to false when they click on the weapon to use. Those buttons can be clicked but nothing happens until both sides have finished setting up the pieces.
Well… not exactly. The Button class inherits from Selectable (where the interactable boolean comes from), which inherits from UIBehaviour, which inherits from MonoBehaviour.
It doesn’t have a name string that you can search for. GameObjects specifically have a name property, Components (and Objects) do not.
The Button object is a Component, it doesn’t have one. To take what Scabbage said further, MonoBehaviour inherits from Behaviour, which inherits from Component. Components are always attached to GameObjects. (Also, it’s “interactable”; an intractable bool would be highly annoying. ) Anyway, it’s not something you want or need since 1) your example would be no different from using GameObject.Find instead, and 2) you can simply use the reference when you instantiate the object, which is always better than messing with Find.
From reading this I feel you’ve missed an important point. A button isnt a special object. Its just a gameobject with a few ui scripts (One of which being Button) thats why you can use GameObject.Find to search for it, but as has been mentioned you should be avoiding using GameObject.Find (Its slow & names arent unique).
Thanks guys! I see what you are saying and I understand the inheritance. I am guessing off the top of my head that if I made that Button a child object of a empty GameObject I could find it by finding that GameObject and then getting it’s child object. It’s already a child of Canvas but that is to broad to find that child. I have been programming on and off since 2010. Took some city college course and had a couple apps in the Apple App store. I don’t think the logic of my game is that flawed. I still believe, even though I understand with your explanations, as to why there is no Button.Find, that things in the Hierarchy should have a the ability to be found with relative ease.
My 2 cents but I appreciated you guys taking the time to respond. @ : add a Find method to UI Objects
They aren’t going to because it would offer no advantage over GameObject.Find and would be just as slow. They do have a ton of different Find calls you can do though and some are faster than others, but the general rule is to not use them if you don’t have to. Even Unity tries not to use them anymore in their newer examples from what I’ve seen.
GameObject.Find(“thisButton”) would find an object in the scene called thisButton
GameObject.Find(“thisButton”).GetComponent() would find the object in the scene called thisButton and return it’s button component.
I tried last night and struggled with something similar, that is strange. I had issues with GameObject and Button not working. Let me give yours a try, it looks pretty simple and what I was expecting. But this code I tried also gave me the results I was looking for.
@larswik Really the main reasons you shouldn’t be using the Find option are coupling and speed. The architecture of the C# solution should be, ideally, as loosely coupled as you can make it. Scripts shouldn’t know about how other scripts work, or how the project is laid out.
Plus it uses a basic linear search to look through every object in the scene and that’s disgusting…
Think about it like if you were implementing it. You’d need to keep a List of all buttons in the scene, and in the Awake method of the Button class you’d need to register it with that list, and remove itself when destroyed. If that’s the case, why not just store references to the buttons you’re using as you create them, or keep the UI in a prefab with the references already created?
Then everyone else has the additional overhead as well because it’s now built in to the engine (technically not really… all the UnityEngine.UI stuff is open source so you could roll your own, but c’mon…).
But if you REALLY wanted to, you could do something like this:
public class BadButton : Button
{
void Awake()
{
ButtonList.RegisterButton(this);
}
void OnDestroy()
{
ButtonList.UnregisterButton(this);
}
}
public class ButtonList
{
static List<BadButton> buttons;
public static void RegisterButton(BadButton button) {...}
public static void UnregisterButton(BadButton button) {...}
public static void Find(string query)
{
BadButton foundButton = null;
int index = 0;
while(foundButton == null && index < buttons.Count)
{
if(buttons[index].name == query)
{
foundButton = buttons[ii];
}
index++;
}
}
}
Note that this is an incredibly naive implementation. You could speed it up quite a lot just by using a Dictionary or something similar, but this is inherently bad design anyway.
Seriously, don’t use Find; too many potential bugs and potential for breakage in your code. You mentioned instantiating an object, so you already have a reference, just use that and skip Find altogether.
Creating a Reference for that in the script on my prefab would be ideal. But for some reason I have never been able to crate a public reference in a prefab script that I can drag a game object from the Hierarchy to the prefab. It has no problem if the reference is another prefab. For my 2D game things are not very processor expensive. Also in this case it is setting up the game pieces. You have some good arguments Thanks for writing the code out for me to view. I always love learning!
@Brathnann - So your code sample will not work as I tested it. The first line is fine and it dosent through an exception. But it is now a GameObject and not a UI Button, so I can not reach the “interactable” that is in the Button component. I could be doing something wrong there but I don’t think so.
This would not execute
GameObject gObject = GameObject.Find("FireBut").GetComponent<Button>();
if(gObject.interactable == false){ // it fails here since there is no intractable in GameObject.
print("Fire Button is deactivated");
}
Well…you cast it into a GameObject. When you use GetComponent, you are getting a Component, in this case, the Button, which means you need to Cast it into a button and not a GameObject…
Button gObject…
But as has been mentioned to you over and over…Don’t use Find…
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MyScript : MonoBehaviour {
public Button myButton;
// Use this for initialization
void Start () {
print(myButton.interactable);
}
// Update is called once per frame
void Update () {
}
}
Add the script to (for example) empty gameobject, and drag your button from hierarcy to myButton field. Unity will add the Button component automagically.
In the case that you instantiated a prefab with a reference to a hierarchy in a different scene, what would the code do? The object doesn’t exist. It sounds like either the prefab you’re trying to connect to the button should be in the scene, and then you connect the button to the instance of the prefab, or you make the button a part of the prefab.
Alternatively, you could have a Menu class that has a list of buttons, and other menus/tabs can interact with that.
For my applications I use the most general approach I can, linking button activation events to function calls, keeping game state out of the UI system, and using inheritance + interfaces to keep the classes apart.
So a little more clarification as to why I am doing this.
In my game, the player enters a store and spends gold buy defense and offense items. When they purchase the item, a prefab button is instantiated and put in to their inventory box on screen, photo included. When the player uses a item from the inventory box, they press that Button which further instantiates another prefab of what they clicked on. This could be a shield, more powerful weapon and so on.
During the initial set up phase if the player clicks on a attack weapon that is a one time use weapon, it is wasted since the game has not begun yet. Since the set up phase was happening, the fire button intractable was set to false, so they could not attack by mistake. But they were still able to select an attack button from their inventory.
It seemed easier for each attack weapon prefab button, when clicked on, to see if the fire button was available before instantiating the attack object. If it was not available then nothing would happen, and they could click on the button all day long with no results. If the fire button was available, then the prefab button created the gameobject being a spell, a dragon GameObject from a prefab or something else. Then the prefab button they clicked on in their inventory would disappear Destroy() since it was used.
So I have figured out what I need to do and I am moving forward. Thanks again folks for all the ideas and the time you took to write out sample code. I love to learn!