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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Differentiate touch Event inside and outside of a button

Discussion in 'UGUI & TextMesh Pro' started by mondeon, Oct 4, 2016.

  1. mondeon

    mondeon

    Joined:
    May 29, 2015
    Posts:
    46
    Hello Unity Community!

    right now, I have the following problem that tortures me for a couple of time:

    I have a centralized InputManager Script that observes for Input Events in Update(). So basically:
    Code (CSharp):
    1. void Update () {
    2.         if (Input.GetMouseButtonDown(0))
    3.         {
    4.            doMoveA();
    5.         }
    6.     }
    So whereever on the screen the player performs a touch (sounds really awkward), doMoveA() is executed.

    My problem is, that I have a UI Button, that, when pressed, should start a function doMoveB() INSTEAD doMoveA(). How to do that?!

    EDIT: My initial idea was to use the EventSystem with a function set in OnClick() as here described http://answers.unity3d.com/questions/974622/unity-502f1-ui-button-onclick-function.html

    At the end it should work like that:
    1 - add a function theButtonPressed() and set it in Unity to be called when the user touches the button.
    2 - That function sets a boolean in my script buttonTouched=true
    3 - and in the Update() before I execute doMoveA() I check if buttonTouched=true
    4 - and in that case execute doMoveB()
    5 - otherwise doMoveA()

    The real question is: is the triggered function theButtonPressed() executed ALWAYS(!) before Update() method? So doMoveA() never interferes with doMoveB()...

    Open to any ideas, thoughts, solutions! Thank you!
     
    Last edited: Oct 4, 2016
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @modeon

    Hi there,

    I'm not sure what you trying to do. I think you should check Unity UI tutorials / manual chapters!

    But anyway, if you are trying to capture touches not button presses:

    You can use Input classes: Input.GetTouch, Input.touchCount and Input touch phase and so on.

    Then again, if you want to have a simple way to relay button clicks (be it mouse click or tap/touch) to your method just add a method to Button's OnClick.

    Or add EventTrigger component, and you can add OnClick or any other available methods and wire your method call there. Same can be done using code with less overhead.
     
    Otavio_ likes this.
  3. mondeon

    mondeon

    Joined:
    May 29, 2015
    Posts:
    46
    @eses

    Simplified:
    touch on a button1 -> a gameobject makes doMoveB() - let's say two steps to the right
    touch on a button2 -> the gameobject jumps
    touch anywhere on display EXCEPT on buttons -> a gameobject makes doMoveA() - let's say two steps to the left
    Important 1: all of the three movements are mutually exclusive and cannot interrupt each other.

    The problem: Input.GetMouseButtonDown(0) together with doMoveA() is triggered on ANY/ALL touch/mouseclicks in Update() - be it on screen or on UI buttons. When I click button1 I don't want the gameobject to start doMoveA()(<- that is defined in the Update()), because that will interfere with doMoveB()(<- that is the actual and only movement that should be executed when clicked on button1)

    Did I specify and explain the problem better now? Any idea how to solve it? Anyone?
     
    ChrisP999 likes this.
  4. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @mondeon

    OK that explanation helps.

    Like I said, please check Unity tuts, you are not thinking it in UI terms.

    First of all you don't have to catch generic mouse clicks.
    That is not how UI works.
    That essentially just means that you clicked mouse button.
    You already have ways to get specific button clicks on specific objects, if you check the tutorials.

    If you have button A and buttonB:

    1. Add a OnClick listener method to button

    A. It modifies whatever variable inside your script.
    doMoveB = true or whatever and calls your moveB method for example.

    2. Add a OnClick listener to buttonB.

    Same here, just that it does something different.
    Jumping = true and calls jump.

    3. Then add canvas size empty RectTransform.

    It should be below these two buttons in Canvas Hierarchy.
    So make it so that it's parent or above in list.
    Make it have button too.
    Add OnClick method here too, CanvasClicked or whatever.

    By default buttons and other UI items block next item below, so first gets the click.

    Now when you click buttonA, you ButtonAClicked method will be called.
    When you click buttonB, you ButtonBClicked method will be called.
    If you click anywhere else (if you made your empty RectTransform full screen size, you get ScreenClicked called.

    So you don't need your Update method.
     
    Otavio_ likes this.
  5. mondeon

    mondeon

    Joined:
    May 29, 2015
    Posts:
    46
    Thx a ton for the answer, @eses

    Believe me, I watched a lot of video tutorials and read a lot of forum threads... I have found some solutions, but I want to find the correct one, which is also performant (I watch all the time at the fps counter).

    I thought about your sugegsted solution, but isn't drawing a rectTransform over the whole Canvas a "dirty" solution? Didn't tested it yet, but would that reduce performance, where the EventSystem runs in background and listens to a button, that has the whole screen size? Btw. noone anywhere suggested your solution, so thanks! I am gonna test that on weekend.
     
  6. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @mondeon

    Yes, it probably will waste your rendering power simply because you are drawing transparent item over screen/full canvas area.

    There's a clever way to circumvent this if you want to go this route, see this thread and answer by @Martin-Sharkbomb:
    https://forum.unity3d.com/threads/empty-rect-to-catch-clicks.383765/#post-2526493

    Anyway, it might be better to find some other solution than that. If you want to have some other items clickable in your game world having that transparent element there might cause issues no matter if it wastes rendering time or not...
     
    Otavio_ likes this.
  7. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @mondeon

    Just a note for the future;

    if one wants to take clicks from plain Input.GetMouseButton etc. these will be done in each and every frame.

    However, UI buttons clicks might take longer to be registered, as this depends on scene EventSystem component.

    If you click screen and count frames, you can see that Input.GetMouseButtonDown(0) for example will spit out current frame.

    However, depending on what is set in EventSystem Input Action per Second, this might take longer.

    So you might have to wait for several frames depending on your polling rate. So it is more than likely that if you don't use UI elements to catch clicks you have to collect the Input click and then wait for a while for UI/EventSystem.
     
    Otavio_ likes this.
  8. mondeon

    mondeon

    Joined:
    May 29, 2015
    Posts:
    46
    Well that is really BAD news! Late detection of clicks (>0,2s) can be deadly for my gameplay! How and where can I adjust EventSystem Input Action per Second?

    In case I can't make the game register clicks in less than 0.2 seconds I am gonna revert back to the GetMouseButtonDown(0) solution and continue working on it. On weekend I will continue digging on the solution then..

    Btw. @eses tx for sharing the other thread, maintaining rendering performance is important..
     
  9. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @mondeon

    If you already have created canvas, you will automatically have EventSystem object / component in your scene.
    Just change the default value.
     
    Otavio_ likes this.