Touch and hold a button on new UI

I tried Click Event, and all the Events from Event Trigger Component, i cant figure out how to make my 2D character walk when i hold the button, it just walk for a click, im using Rigidbody.AddForce, if i click a lot of times the Virtual D-Pad it walks, but i want it to be continuous, my script is not wrong because using WASD it work if i just click or hold down, but with the UI Button it just detect the click not if i hold.

2 Likes

A click is down+up on a button. What you want is OnPointerDown() and OnPointerUp().

6 Likes

Add an EventTrigger script to your button, and that will enable you to set callbacks for all the events.

4 Likes

Can you explain how i use it, a guy said that i need to use OnPointerDown and OnPointerUp, to make a bool true and false.

Now i`m using this

public void WalkToLeft()
{
Rigidbody2D.AddForce(blablabla);
}

And call it from listener on click, every click it apply force to my 2D character, but i still not getting how i can make a bool with OnPointerDown/Up with Event Trigger Component. With old UI was easier to use GetTouch.phase == Stationary;

You could trigger a bool on OnPointerDown which triggers a timer stored in the Update function

1 Like

yeah but the game actually will look every frame right, i was trying to avoid that, but ok so, can you just show me a code example of OnPointerDown?

The point of OnPointerDown() is that you only get it once before OnPointerUp() is sent. They’re a single change of state, not a constant event.

2 Likes

There’s no code really, you have to attach an EventTrigger script to your object, and then click Add New and select OnPointDown from the list, then direct it to a function that will flip a bool, that if true will fire WalkToLeft from Update

8 Likes

Thank you guys, now i understand it, and works pretty, thanks ‘-’, was just that simple and i was complicating it, really thanks

1 Like

The code may be a little messy but bare with me aha.

public static bool mouseDown;
public float timeMouseDown;

void Update(){
    if(mouseDown){
       timeMouseDown += time.deltaTime;
}

void OnPointerDown(){
      mouseDown = true;
}
void OnPointerUp(){
      mouseDown = false;
      timeMouseDown = 0;
}

The code probably isn’t functional cos i wrote this on a phone but you can use it as an example and it should help :slight_smile:

4 Likes

For Anyone looking for help and a working script here is mine

using UnityEngine;
using System.Collections;

public class PlayerMovement : MonoBehaviour {
    public float speed = 10.0f;
    private bool walkUp;
    private bool walkLeft;
    private bool walkRight;
    private bool walkDown;

    public void Update()
    {
        if (walkUp)
        {
            GetComponent<Rigidbody2D> ().AddForce (Vector2.up * speed);
        }
        else if (walkLeft)
        {
            GetComponent<Rigidbody2D> ().AddForce (-Vector2.right * speed);
        }
        else if (walkRight)
        {
            GetComponent<Rigidbody2D>().AddForce(Vector2.right * speed);
        }
        else if (walkDown)
        {
            GetComponent<Rigidbody2D>().AddForce(-Vector2.up * speed);
        }
    }
    public void PlayerWalkUp(int value){
        if (value == 1)
        {
            walkUp = true;
        }
        else
        {
            walkUp = false;
        }

    }

    public void PlayerWalkLeft(int value){
        if (value == 1)
        {
            walkLeft = true;
        }
        else
        {
            walkLeft = false;
        }
       
    }

    public void PlayerWalkRight(int value){
        if (value == 1)
        {
            walkRight = true;
        }
        else
        {
            walkRight = false;
        }
       
    }

    public void PlayerWalkDown(int value){
        if (value == 1)
        {
            walkDown = true;
        }
        else
        {
            walkDown = false;
        }
       
    }
}
4 Likes

It really bothered me that Unity didn’t provide such an obvious function simply to know in what state button is… the solution up there does not work for mobile phones as they don’t have pointers… so I found an akward solution:

GetComponent().GetColor() == GetComponent().colors.pressedColor * GetComponent().colors.colorMultiplier

if this is true then the button is active. Note that it has to be based on color change AND pressed color must be different from other colors to detect it. Not sure how it would work with animations or sprites. ALSO you could make an invissible same-shaped button just for the purpose of this kind of trigger detection.

If someone designs a script that autamatically creates another image (that copies and sustains same important values) and tracks if it’s triggered or not by returning a bool when asked (through the same method described above)… well post it here (unless I’ll be forced to do it myself someday)

4 Likes

Excuse me but how are you setting your event triggers for this, cant seem to get mine workking properly.

1 Like

Hey,I have a same problem as you .How can you solve it? I try to use event trigger to command to move gameobject by hold button by touch. Please help me!!

I’ve created a request on my UI Extensions repo to create a proper script that doesn’t use EventTrigger. Bit ties up at the mo but should have it there in the next week. (https://bitbucket.org/ddreaper/unity-ui-extensions/issue/2/a-touch-and-hold-button)
Reminder, EventTrigger should only be used if you REALLY have to, it is a very overweight component. For specific events, it is better to use the event interfaces to implement your behaviour.

1 Like

As SimonDarksideJ was saying EventTrigger is super over kill for handling events. Just make your own classes or extend the default ones. If you extend the button class you can just do this.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class DownstateButton : Button
{
  public void Update()
  {
//A public function in the selectable class which button inherits from. 
    if(IsPressed())
    {
      WhilePressed();
    }
  }

  public void WhilePressed()
  {
    //Move your guys
  }
}
2 Likes
public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    bool _pressed = false;
    public void OnPointerDown(PointerEventData eventData)
    {
        _pressed = true;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        _pressed = false;
    }

    void Update()
    {
        if (!_pressed)
            return;

        // DO SOMETHING HERE
    }
}

This is a component that will work on any ui object and handle the pointer down and up events. I’m not 100% sure if it properly handles dragging off of the object while pressed, but you can add an IPointerExitHandler and set pressed to false as well if you’d like.

This solution does not require sub-classing the button object and can be added to all of the buttons. It also doesn’t burn your cpu with needless Update calls. You could also add a public property for the direction the button represents. That way you can configure it visually in the inspector for each button, and have your code act upon the value dynamically:

[System.Serializable]
public enum eMovementDirection
{
    Up, Down, Left, Right
}
public class PointerListener : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
    public eMovementDirection Direction;
   
    bool _pressed = false;
    public void OnPointerDown(PointerEventData eventData)
    {
        _pressed = true;
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        _pressed = false;
    }

    void Update()
    {
        if (!_pressed)
            return;

        switch(Direction)
        {
            case eMovementDirection.Up:
                break;
               
            // (etc...)
       
        }
    }
}
11 Likes

Fantastic work @LunaticEdit & @BMayne I’ll get those two scripts added to the UI Extensions Bitbucket repository
https://bitbucket.org/ddreaper/unity-ui-extensions with suitable attributions :smile:

I have to comment in this thread just to say thanks & how useful the above is - not having an isPressed state in the UI button class is a huge omission in a game engine UI!
I like BMayne’s solution which I can only assume would not be very cpu intensive but I wouldn’t know without trawling the UI code.
But the ‘isPressed’ function is not even documented as far as I can see so is it only to be found by opening the UI source? This seems poor too.

1 Like

There is a problem with the above approaches for in-game input, namely if you do not start your touch ON the button, it will never register the button as down, so you can not slide between 2 buttons for left/right or up/down and you must tap accurately at the start of a press to hit it.

1 Like