Search Unity

Calling OnClick() from a script?

Discussion in 'Scripting' started by Studio_Akiba, Aug 16, 2016.

  1. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,422
    Not sure why I am unable to do this easily (or even find any information on how to do it) but here goes nothing...

    I am looking for a way to call the OnClick() function of a UI button from within another script.
    Now before you ask why, read on!

    I have a world-space UI and as my cursor is locked to the centre and hidden, the UI is unable to find the cursor or log any of it's clicks (seems stupid, I know).

    My solution to this (if inefficient or there is a better way, please speak up), I have a script that raycasts to the UI, and gets the clicked object.

    If this is a button, I want to be able to call the OnClick function of said button.

    Is this do-able?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEngine.EventSystems;
    4. using System.Collections.Generic;
    5. using UnityEngine.UI;
    6.  
    7. public class UIWorldDetect : MonoBehaviour
    8. {
    9.     private GameObject player;
    10.  
    11.     void Start()
    12.     {
    13.  
    14.         player = GameObject.FindGameObjectWithTag("Player").gameObject;
    15.  
    16.     }
    17.  
    18.     void Update()
    19.     {
    20.         if (Vector3.Distance(transform.position, player.transform.position) <= 1)
    21.         {
    22.             RaycastWorldUI();
    23.         }
    24.     }
    25.  
    26.     void RaycastWorldUI()
    27.     {
    28.         if (Input.GetMouseButtonDown(0))
    29.         {
    30.             PointerEventData pointerData = new PointerEventData(EventSystem.current);
    31.  
    32.             pointerData.position = Input.mousePosition;
    33.  
    34.             List<RaycastResult> results = new List<RaycastResult>();
    35.             EventSystem.current.RaycastAll(pointerData, results);
    36.  
    37.             if (results.Count > 0)
    38.             {
    39.                 //WorldUI is my layer name
    40.                 if (results[0].gameObject.layer == LayerMask.NameToLayer("World UI"))
    41.                 {
    42.                     //string dbg = "Root Element: {0} \n GrandChild Element: {1}";
    43.                     //Debug.Log(string.Format(dbg, results[results.Count - 1].gameObject.name, results[0].gameObject.name));
    44.                     Debug.Log("Root Element: "+ results[results.Count-1].gameObject.name);
    45.                     if(results[results.Count - 1].gameObject.GetComponent<Button>())
    46.                     {
    47.                         //results[results.Count - 1].gameObject.GetComponent<Button>().onClick.AddListener();
    48.                     }
    49.                     //Debug.Log("GrandChild Element: "+results[0].gameObject.name);
    50.                     results.Clear();
    51.                 }
    52.             }
    53.         }
    54.     }
    55. }
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    G76Dev, Fenikkel, StellarVeil and 5 others like this.
  3. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,422
    @KelsoMRK this works well, wasn't coming up on IntelliSense for some reason though :|

    Is there a way to get it to act the same way as a button though with the colour tint on hover and click, or is this something I can't get at?
     
    OddBawlStudios likes this.
  4. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    that's nothing to do with the event.

    When you interact with the button there is the code which handles what the button does, and then there is the things the button calls.

    You'll likely have to manipulate the "spriteState" of the button seperately to simulate the graphical changes the button goes through

    https://docs.unity3d.com/ScriptReference/UI.Selectable-spriteState.html

    I'm thinking coroutine with a wait between hover, click and return to idle (or whatever it's called)






    edit: everything below is more a "how to dig into ui elements to see how they work since they're open source" braindump :D

    or if you want to dig into what the button is actually doing. Buttons are extensions of "selectable" which handles the states like highlighted/clicked/etc.

    selectable source
    https://bitbucket.org/Unity-Technol...ctable.cs?at=5.2&fileviewer=file-view-default

    around line 300 there is an enum which has the states, you're looking for something in there that is based off that enum :D

    edit: which appears to be DoStateTransition (line 253) which has lines like
    Code (csharp):
    1.  
    2. private SpriteState m_SpriteState;
    3. //...
    4. transitionSprite = m_SpriteState.highlightedSprite;
    5. transitionSprite = m_SpriteState.disabledSprite;
    6.  
    which ultimately calls DoSpriteSwap (line 473)
    Code (csharp):
    1.  
    2. image.overrideSprite = newSprite; // newSprite being "transitionSprite" as a parameter from the code pasted above
    3.  
    4.  
     
    Last edited: Aug 17, 2016
    KelsoMRK likes this.
  5. Studio_Akiba

    Studio_Akiba

    Joined:
    Mar 3, 2014
    Posts:
    1,422
    In that case, I don't suppose there is an alternative to using the raycast method I am using... perhaps an alternative to hiding the cursor with
    Code (CSharp):
    1. Cursor.lockState = CursorLockMode.Locked;
    ?
     
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I went a little off piste there, if you want to emulate the button's graphical state changes I think you just need to manipulate the button's sprite state.
     
  7. alizmember

    alizmember

    Joined:
    Dec 7, 2018
    Posts:
    1
  8. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    Can you post your script/code, to see how you set it ?
     
  9. n8burba

    n8burba

    Joined:
    Feb 4, 2013
    Posts:
    12
    Use button.Select() to select it, thus changing the color.
     
  10. valentin56610

    valentin56610

    Joined:
    Jan 22, 2019
    Posts:
    156
    That doesn't work anymore, at least not in Unity 2021.3.x

    However, I am adding onClick action myself, the button when instantiated doesn't have any action linked to it

    Any other solution to call the onClick from a button from script? Would be very useful for a double click kind of action... I already registered my actions on my button when I instantiated it, so I'd like to just call whatever the action is..

    My script:
    Code (CSharp):
    1. using TMPro;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4. using UnityEngine.EventSystems;
    5.  
    6. public class CampaignSlotGO : MonoBehaviour, IPointerClickHandler
    7. {
    8.     public Button button;
    9.     public TMP_Text saveName;
    10.  
    11.     // PRIVATE VARS
    12.     float _lastClick = 0f;
    13.     float _interval = 0.4f;
    14.     // PRIVATE VARS
    15.  
    16.     public void OnPointerClick(PointerEventData eventData)
    17.     {
    18.         if ((_lastClick + _interval) > Time.time)
    19.         {
    20.             Debug.Log("here");
    21.             button.onClick.Invoke();
    22.         }
    23.  
    24.         _lastClick = Time.time;
    25.     }
    26. }
     
  11. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
  12. valentin56610

    valentin56610

    Joined:
    Jan 22, 2019
    Posts:
    156
    Thanks for answering me :)
     
  13. DhiaSendi

    DhiaSendi

    Joined:
    May 16, 2018
    Posts:
    43
    If you get errors on new Unity versions
    Change the
    Code (CSharp):
    1. using UnityEngine.UIElements;
    2.  
    to

    Code (CSharp):
    1. using UnityEngine.UI;
    2.  
     
  14. Nad_B

    Nad_B

    Joined:
    Aug 1, 2021
    Posts:
    730
    Trying to raise a button's click event manually from code just to execute the click action is... really weird. The cleaner solution is just to assign the click event to a method, which you can call any time you want, from anywhere...


    Code (CSharp):
    1. private void Awake()
    2. {
    3.     myButton.onClick.AddListener(MyButtonClicked); // or assign it from Editor if you want
    4. }
    5.  
    6. public void MyButtonClicked()
    7. {
    8.     // Handle button clicked here...
    9. }
    Now just call
    MyButtonClicked
    from any script you want:
    Code (CSharp):
    1. scriptThatContainsButton.MyButtonClicked();