Search Unity

Question I Click A Button... But Also the Game Icon Beneath It!

Discussion in 'Scripting' started by redapplesonly, May 19, 2023.

  1. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    51
    In my game, my UI Canvas has a button that the player may click and hold down to build up a firing charge. The logic for the "click and hold down" part is a little involved, but it works. Take a look:

    Code (CSharp):
    1. public class PlayerInputScript : MonoBehaviour
    2. {
    3.     public Button MyButton;
    4.     private Boolean MyButtonPressed = false;
    5.     private float FiringCharge = 0;
    6.  
    7.     private void Start()
    8.     {
    9.         this.MyButton.onClick.AddListener(BuildUpCharge);
    10.         EventTrigger MyButtonTrigger = this.MyButton.GetComponent<EventTrigger>();
    11.         EventTrigger.Entry entry = new EventTrigger.Entry();
    12.         entry.eventID = EventTriggerType.PointerDown;
    13.         entry.callback.AddListener((data) => { MyButtonPressed = true; });
    14.         MyButtonTrigger.triggers.Add(entry);
    15.         entry = new EventTrigger.Entry();
    16.         entry.eventID = EventTriggerType.PointerUp;
    17.         entry.callback.AddListener((data) => { MyButtonPressed = false; });
    18.         MyButtonTrigger.triggers.Add(entry);
    19.     }
    20.  
    21.     void Update()
    22.     {
    23.         if(MyButtonPressed)
    24.         {
    25.             BuildUpCharge()
    26.         }
    27.     }
    28.  
    29.     public void BuildUpCharge()
    30.     {
    31.         this.FiringCharge += 1;
    32.     }
    33. }
    I wish the code was a little more compact and easier to follow, but it all works great.

    Here's the thing, though... My button exists in the UI canvas of my game scene. But within the scene, there are also game units moving about. The player is meant to click on a unit to access them (or attack them, if they are enemy units). Unfortunately, if a unit wanders underneath my button, and if the user clicks the button, the effect is that Unity believes that the player has clicked on the button AND on the unit. One click, two actions.

    That's no good. I need it so that if the user clicks the button, the click doesn't impact anything that might happen to be rendered beneath it. I tried this:

    Code (CSharp):
    1.     void Update()
    2.     {
    3.         if(MyButtonPressed  &&  !EventSystem.current.IsPointerOverGameObject())
    4.         {
    5.             BuildUpCharge()
    6.         }
    7.     }
    But that had the opposite effect of what I wanted: When the user clicked and held down the button, the button activated once (holding it down did nothing) but the game unit beneath the button was also selected. Do you see what I'm doing wrong? Thank you.
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    redapplesonly likes this.
  3. redapplesonly

    redapplesonly

    Joined:
    Nov 8, 2021
    Posts:
    51
    @Brathnann Thanks for writing, I really appreciate it! Yeah, my code is big and clunky, and that's because I've only been coding freeform in Unity for a few weeks now. The IPointerUp/DownHandler is a good lead, thank you. I'll investigate...

    In the meantime: My UI Canvas is overlay. I know when a game unit is clicked because at the moment, this is in their C# script:

    Code (CSharp):
    1.     private void OnMouseDown()
    2.     {
    3.         // User clicked on this game unit
    4.         Debug.Log(">>>You clicked on Game Unit "+this.name+"!");
    5.     }
    When I realized I might be having this "one click/two actions" problem, I popped this code into the Game Unit objects. There's no doubt; the text appears on the Console with every click.
     
  4. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    If this is only for a system with a single touch, a crude way of preventing multiple objects from seeing the same touch is adding a flag, like
    clickWasUsed
    . Set it to false at the start of each Update, have everything which can consume a click check first whether it's still false, and set it to true when they use it. Then (I'm not sure how your system works) make sure the things on "top" check for clicks first (for example, your UI events happen before your units check).
     
    redapplesonly likes this.
  5. Elhimp

    Elhimp

    Joined:
    Jan 6, 2013
    Posts:
    75