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. Dismiss Notice

Question prevent click event on world objects when a click on ui element occurs

Discussion in 'UI Toolkit' started by SamTyurenkov, Jan 14, 2023.

  1. SamTyurenkov

    SamTyurenkov

    Joined:
    May 12, 2018
    Posts:
    83
    What Im doing: menu with options appearing at a click point
    Short video: https://gyazo.com/1f64bddfbb0a2c99fccf4b17bdc139ce

    I used to have a script on canvas which decides whenever its a click on classic UI or is a click on a world object:

    Code (CSharp):
    1.    
    2.     private void Update()
    3.     {
    4.         HandleClickInput();
    5.     }
    6.  
    7.     private void HandleClickInput()
    8.     {
    9.  
    10.         if (Input.GetMouseButtonDown(0))
    11.         {
    12.             Debug.Log("user click");
    13.             eventData.position = Input.mousePosition;
    14.             List<RaycastResult> results = new List<RaycastResult>();
    15.             graphicRaycaster.Raycast(eventData, results);
    16.             bool hitUIButton = false;
    17.  
    18.             foreach (RaycastResult result in results)
    19.             {
    20.                 if (result.gameObject.tag == "UIButton")
    21.                 {
    22.                     hitUIButton = true;
    23.                     break;
    24.                 };
    25.             }
    26.  
    27.  
    28.             if (hitUIButton)
    29.             {
    30.                 //DO STUFF THAN CLOSE
    31.                 Debug.Log("CLICK ON UI ELEMENT");
    32.             }
    33.             else
    34.             {
    35.                 CloseMenus();
    36.                 mousePositionGlobal = Input.mousePosition;
    37.                 PositionContextMenu();
    38.                 ShowActionOptions();
    39.             }
    40.         }
    41.     }
    So it was raycasting through gameobjects and if clicked on any object in the world, it would trigger appearance of buttons with actions related to this object. e.g.:
    -click on ground - show button with movement option
    -click on unit - show button with attack or interact option
    and if one of the raycast results is an UI button it was just doing whats bound to the button.

    Now Im trying to achieve the same logic with UIDocument, I wrote some logic already for UXML and connected it with the above script:

    Code (CSharp):
    1.  
    2. public class ContextMenuUXML : MonoBehaviour
    3. {
    4.     private VisualElement root;
    5.     private VisualElement contextMenu;
    6.     private UQueryBuilder<Button> buttons;
    7.  
    8.     private void OnEnable()
    9.     {
    10.         UIDocument uiDoc = GetComponent<UIDocument>();
    11.         root = uiDoc.rootVisualElement;
    12.         contextMenu = root.Q<VisualElement>(name: "ContextMenu");
    13.         buttons = GetAllButtons();
    14.  
    15.         RegisterButtonCallbacks();
    16.     }
    17.  
    18.     public void PositionContainer(Vector2 mousePosition)
    19.     {
    20.         Debug.Log("position container ");
    21.  
    22.         contextMenu.style.top = Screen.height - mousePosition.y;
    23.         contextMenu.style.left = mousePosition.x;
    24.     }
    25.  
    26.     private void OnDisable()
    27.     {
    28.         UnregisterButtonCallbacks();
    29.     }
    30.  
    31.     public void ShowButton(string buttonName)
    32.     {
    33.         Debug.Log("showing button");
    34.         contextMenu.Q(name: buttonName).style.display = DisplayStyle.Flex;
    35.     }
    36.  
    37.     public void HideButtons()
    38.     {
    39.         buttons.ForEach((Button button) =>
    40.         {
    41.             button.style.display = DisplayStyle.None;
    42.         });
    43.  
    44.     }
    45.  
    46.     private void RegisterButtonCallbacks()
    47.     {
    48.  
    49.         buttons.ForEach((Button button) =>
    50.         {
    51.             button.RegisterCallback<ClickEvent>(ButtonOnClick);
    52.         });
    53.     }
    54. }

    However i dont quite understand how to only trigger whats bound to UI button, and not trigger a world click in this case.

    So the question in short:
    How to prevent click event on world objects when a click on ui element occurs?


    Thank you
     
  2. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    700
    dr4 likes this.
  3. SamTyurenkov

    SamTyurenkov

    Joined:
    May 12, 2018
    Posts:
    83
  4. dlorre

    dlorre

    Joined:
    Apr 12, 2020
    Posts:
    700
    I don't know why it works for me then.
     
  5. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    5,848
    UI Toolkit is meant to work with the event system. It receives inputs from it after all.

    Otherwise from memory,
    RegisterCallback
    method has overloads with an enum to specify whether the input should 'tickle down' or not. 'NoTrickleDown' should stop it from going through.