• Hi Guest!

    This is a notice regarding recent upgrades to the Hub. Over the last month, we have added several new features to improve your experience.
    You can check out the details in our official announcement!

How "to press" button on scene into script?

MaxToMax333

New member
Messages
13
Reactions
3
Points
3
Hello!
I cant "press" button on scene into script. I've scene with atoms:
1. Trigger UIButton - name "Button1". When I press button - doing some actions (included in tab "Button trigger");
2. Shape Cube - "Cube1", with my plugin-script;
How "to press" button programmatically into my plugin-script?

var FindedButton = GameObject.Find("Button"); // Button (UnityEngine.GameObject)
FindedButton.onClick.Invoke(); // error: Type `UnityEngine.GameObject' does not contain a definition or method `onClick'.

Also don't work variants:
FindedButton.Click();
FindedButton.onClick();
FindedButton.Trigger();

var myTrigger = FindedGameObject.GetComponent<Trigger>(); // Also GetComponentInChildren
myTrigger.onClick.Invoke();
myTrigger.Click();
myTrigger.onClick();
myTrigger.Trigger();

var myButton= FindedGameObject.GetComponen<Button>(); // Also <UIButton>, also GetComponentInChildren
myButton.onClick.Invoke();
myButton.Click();
myButton.onClick();
myButton.Trigger();

Also tried with parents-objects:
FindedButton.transform.parent.gameObject // Canvas (UnityEngine.GameObject)
FindedButton.transform.parent.parent.gameObject // rescaleObject (UnityEngine.GameObject)
FindedButton.transform.parent.parent.gameObject // object (UnityEngine.GameObject)
FindedButton.transform.parent.parent.parent.gameObject // reParentObject (UnityEngine.GameObject)
FindedButton.transform.parent.parent.parent.parent.gameObject // Button1 (UnityEngine.GameObject)
There is only a scene above - SceneAtoms (UnityEngine.GameObject)

Text script:
using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using SimpleJSON; using UnityEngine.UI; using UnityEngine.XR; using UnityEngine.Events; public class MyPluginTest : MVRScript { protected UIDynamicButton myButton; public override void Init() { myButton = CreateButton("ButtonInPlugin", false); myButton.height = 100; myButton.button.onClick.AddListener(delegate() {FindGameObject();} ); } void FindGameObject() { var FindedGameObject = GameObject.Find("Button"); // Button (UnityEngine.GameObject) //FindedGameObject.onClick.Invoke(); //var buttonRed = FindedGameObject.GetComponentInChildren<Text>(); //buttonRed.text = "POP"; //var t = GameObject.Find("LabelInput"); } void Update() {} }
 
In your code, GameObject.Find("Button"); finds the first GameObject in the entire application (not just your script) with that name, since Find is a static function of the GameObject class, rather than a function of a specific GameObject instance. There are potentially hundreds of buttons splattered across the UI so it is very unlikely to return the button you're looking for.

This should work:

C#:
UIDynamicButton myButton;

public override void Init()
{
    myButton = ...
    myButton.button.onClick.AddListener(ClickUIButton);
}

void ClickUIButton()
{
    const string uiButtonName = "UIButton";
    Atom uiButtonAtom = SuperController.singleton.GetAtomByUid(uiButtonName);
    if(uiButtonAtom == null || uiButtonAtom.type != "UIButton")
    {
        SuperController.LogError($"No UIButton atom found with name '{uiButtonName}'");
        return;
    }

    // The transform which contains the clickable button component in the UIButton atom's gameobject hierarchy
    Transform buttonTransform = uiButtonAtom.transform.Find("reParentObject/object/rescaleObject/Canvas/Button");
    if(buttonTransform == null)
    {
        SuperController.LogError($"Could not find the button transform of UIButton '{uiButtonName}'");
        return;
    }

    buttonTransform.GetComponent<UnityEngine.UI.Button>().onClick.Invoke();
}
 
In your code, GameObject.Find("Button"); finds the first GameObject in the entire application (not just your script) with that name, since Find is a static function of the GameObject class, rather than a function of a specific GameObject instance. There are potentially hundreds of buttons splattered across the UI so it is very unlikely to return the button you're looking for.

This should work:

C#:
UIDynamicButton myButton;

public override void Init()
{
    myButton = ...
    myButton.button.onClick.AddListener(ClickUIButton);
}

void ClickUIButton()
{
    const string uiButtonName = "UIButton";
    Atom uiButtonAtom = SuperController.singleton.GetAtomByUid(uiButtonName);
    if(uiButtonAtom == null || uiButtonAtom.type != "UIButton")
    {
        SuperController.LogError($"No UIButton atom found with name '{uiButtonName}'");
        return;
    }

    // The transform which contains the clickable button component in the UIButton atom's gameobject hierarchy
    Transform buttonTransform = uiButtonAtom.transform.Find("reParentObject/object/rescaleObject/Canvas/Button");
    if(buttonTransform == null)
    {
        SuperController.LogError($"Could not find the button transform of UIButton '{uiButtonName}'");
        return;
    }

    buttonTransform.GetComponent<UnityEngine.UI.Button>().onClick.Invoke();
}
Thanks for answer!
I need "to press" same button on scene (finded button by name in scene and "press"). Not that button which I created in my plugin/script.

It worked! Thank you very much!
That's how it works:
C#:
var FindedGameObject = GameObject.Find("Button"); // Button (UnityEngine.GameObject)
FindedGameObject.transform.GetComponent<UnityEngine.UI.Button>().onClick.Invoke();

It turns out that "onClick" is the method of "UI.Button"-object, and "UI.Button"-object is a component of "transform"-object., and "transform"-object is a component of "Button (UnityEngine.GameObject)" what I founded.
 
@MaxToMax333 As mentioned, GameObject.Find searches the entire application runtime (for our purposes, that's the currently open scene and all of the user interface) for the gameobject. If there are multiple gameobjects with the name "Button" (and there are potentially hundreds), it will just return the first result it comes across in the hierarchy. E.g. if you have two UIButton atoms, the one that was created first will probably be first in the hierarchy, and GameObject.Find("Button") will return its "Button" gameobject and never the second one, assuming it doesn't run into some other "Button" at some point earlier in the hierarchy. Since it's just based on name matching, it doesn't even know if the returned gameobject has the right components on it to be able to invoke onClick - you could easily run into a null error without doing proper null checks.

For your onclick invoking to work reliably you really do need to find the correct transform on the specific UIButton atom's hierarchy as shown in my example
 
@MaxToMax333 As mentioned, GameObject.Find searches the entire application runtime (for our purposes, that's the currently open scene and all of the user interface) for the gameobject. If there are multiple gameobjects with the name "Button" (and there are potentially hundreds), it will just return the first result it comes across in the hierarchy. E.g. if you have two UIButton atoms, the one that was created first will probably be first in the hierarchy, and GameObject.Find("Button") will return its "Button" gameobject and never the second one, assuming it doesn't run into some other "Button" at some point earlier in the hierarchy. Since it's just based on name matching, it doesn't even know if the returned gameobject has the right components on it to be able to invoke onClick - you could easily run into a null error without doing proper null checks.

For your onclick invoking to work reliably you really do need to find the correct transform on the specific UIButton atom's hierarchy as shown in my example
Thank you very much for the clarification. I understood.But the search by name in the whole scene works if the search is by a unique name (I will use unique names for buttons).
PressButton.png
 
Thank you very much for the clarification. I understood.But the search by name in the whole scene works if the search is by a unique name (I will use unique names for buttons).
In practice it might be unlikely that there are other gameobjects in the scene with the name "Pink", but not impossible. I could for example have a plugin that creates a custom element in the plugin UI that's a gameobject named "Pink". Since gameobject names aren't unique identifiers, GameObject.Find is a fundamentally unreliable way to find the correct object.

If you're going by atom names (which are unique identifiers), you should use the proper method designed for finding atoms: SuperController.singleton.GetAtomByUid("Pink");. This is also much faster computationally than searching the entire scene, and describes the intent of what you're doing much better. :)

I should also note that in your screenshot, "Pink" is just the string value of the button's Text component. It's not the name of the gameobject necessarily, since the button text can be different from the atom name. The atom name however is also the atom gameobject's name so if the atom is named "Pink", it can be found with GameObject.Find (just not reliably).
 
In practice it might be unlikely that there are other gameobjects in the scene with the name "Pink", but not impossible. I could for example have a plugin that creates a custom element in the plugin UI that's a gameobject named "Pink". Since gameobject names aren't unique identifiers, GameObject.Find is a fundamentally unreliable way to find the correct object.

Since you're going by atom names (which are unique identifiers), you should use the proper method designed for finding atoms: SuperController.singleton.GetAtomByUid("Pink");. This is also much faster computationally than searching the entire scene, and describes the intent of what you're doing much better. :)
Now everything has become much clearer! Thank you very much! I will use your option.
 
Back
Top Bottom