OnPointerUp not running

I found a touch screen joystick tutorial online so I could implement one into my game. I got it to work and decided to alter the script to suit my needs, I am trying to get the joystick to appear where ever you touch on the right side of the screen. After I implemented my code, everything seemed to work except the OnPointerUp method did not run when I let go of the left mouse button/lift finger from screen.

My Hierarchy:
-VirtualJoystick(canvas)
–Background(Image)
—Joystick(Image)
–JoystickZone(Transparent Image)

My scripts:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class VirtualJoystick : MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
    [HideInInspector]
    public Image backgroundImage;
    private Image joystickImage;
    public Vector3 inputVector;
    public virtual void OnDrag(PointerEventData ped)
    {
        Vector2 pos;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(backgroundImage.rectTransform, ped.position, ped.pressEventCamera, out pos))
        {
            pos.x = (pos.x / backgroundImage.rectTransform.sizeDelta.x);
            pos.y = (pos.y / backgroundImage.rectTransform.sizeDelta.y);
            inputVector = new Vector3(pos.x * 2, 0, pos.y * 2);
            inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector; //if (inputVector.magnitude > 1.0f) { inputVector = inputVector.normalized();} else{inputVector = inputVector;}
            joystickImage.rectTransform.anchoredPosition = new Vector3(inputVector.x * (backgroundImage.rectTransform.sizeDelta.x / 3),
                                                                       inputVector.z * (backgroundImage.rectTransform.sizeDelta.y / 3));
        }
    }
    public virtual void OnPointerDown(PointerEventData ped)
    {
        OnDrag(ped);
    }
    public virtual void OnPointerUp(PointerEventData ped)
    {
        Debug.Log("Pointer Up");
        inputVector = Vector3.zero;
        joystickImage.rectTransform.anchoredPosition = Vector3.zero;
        backgroundImage.gameObject.SetActive(false);
    }
    void Start()
    {
        backgroundImage = transform.Find("Background").GetComponent<Image>();
        joystickImage = backgroundImage.transform.GetChild(0).GetComponent<Image>();
    }
    public float Horizontal()
    {
        if (inputVector.x != 0)
        {
            return inputVector.x;
        }
        else
        {
            return Input.GetAxis("Horizontal");
        }
    }
    public float Vertical()
    {
        if (inputVector.z != 0)
        {
            return inputVector.z;
        }
        else
        {
            return Input.GetAxis("Vertical");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class JoystickZone : MonoBehaviour, IPointerDownHandler {
    public GameObject joystick;
    public virtual void OnPointerDown(PointerEventData ped)
    {
        Debug.Log("Pointer Down");
        joystick.transform.position = ped.position;
        joystick.SetActive(true);
    }
}

UPDATE: OnPointerUp does run but only after you stop touching the joystick after touching it again.

OnPointerUp only runs if the pointer is over the same GameObject that OnPointerDown was called on.

Are you sure you don’t want to use the various drag events instead?

https://docs.unity3d.com/Manual/SupportedEvents.html

1 Like

OnPointerDown is called on the joystick. It cant be because the joystick moves since it gets moved to the new position before its OnPointerDown is called.

I tried to emulate your design , but I have no way of knowing if my settings match yours :slight_smile:

I do not get any call to PointerDown on the virtual joystick, I am getting it for the zone.

Maybe this will help.

make sure the zone is above the background in the hierarchy and the joystick zone has “Background” in the joystick field. I have the joystick zone covering the right half of the screen and anchored as such.

3349571--261966--Background.PNG 3349571--261967--Hierarchy.PNG 3349571--261968--Joystick.PNG 3349571--261969--JoystickZone.PNG 3349571--261970--VirtualJoystick.PNG

Checking that out now. Luckily I didn’t delete my earlier test. :slight_smile:

Well, there was definitely an issue with who gets the event. A semi-easy fix is to add an Update() check? :slight_smile:
I enjoy these kinds of problems, and was trying to think up alternatives, but got a few wrong tries…
so, the update fix, which I just put in the JoystickZone script, but it could be on the background instead, say, then it’s not always running (but not a big deal) was just:

if(pointerDown && Input.GetMouseButtonUp(0))
{
   pointerDown = false;
   joystick.SetActive(false);
}

Forgot you were working with touch, but pretty sure that can squeeze in there, too.

Thank you for the swift reply! Could you explain the context of the "pointerDown’ bool you used for the update method?
I tried just adding a bool with the same name to the top of the same script and setting it to true at the end of OnPointerDown. That seems to make the joystick disappear like I wanted but the joystick does not reset to the neutral position afterwards. I could fix that by adding joystick.transform.parent.GetComponent<VirtualJoystick>().inputVector = Vector3.zero; but I feel like there should be a way to get the OnPointerUp in the VirtualJoystick to run without having to bypass it entirely.

Ah, ya sorry I didn’t reset it… it was just written quickly.
The issue is (if you want to work on it further), is that you get down on the zone and not down on the virtual joystick. So, you can’t get ‘up’ that way. I’m not exactly sure what you’d have to do to make it work beyond that Update() check. I don’t doubt that it’s possible, but I’m just not sure.

Are you sure I don’t get down on the Joystick? in order for the center of it to move, OnDrag has to be called and its called in OnPointerDown and the center is moving. I’m likely going to redo the script to just use “Input.Touch” instead then test the touch position for the right side of the screen.

Well, you get the drag event from the canvas. You do get down on the joystick (zone)… the thing is when you ‘exit’ the joystick zone and enter the background/joystick (areas) you get ‘up’ on the zone, but no new ‘down’.
Drag can still work, presumably because it’s the only valid target during the downpress raycast thing -a -ma -bob :slight_smile:

1 Like

I understand now. I am trying to redesign how I handle the Joystick zone. I decided to do it by using Input.Touch and testing if the touch happens on the right half of the screen… It seems to work as far as getting the joystick to pop up and disappear in the right place but now the OnDrag does not run on the joystick.

This is my new Joystick zone:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;


public class JoystickZone : MonoBehaviour
{

    public GameObject joystick;
    bool pointerDown = false;
    private Vector2 pos;

    public void Update()
    {
        if (Input.touchCount > 0)
        {
            if (Input.GetTouch(0).phase == TouchPhase.Began)
            {
                pos = Input.GetTouch(0).position;
            }
            if (Input.GetTouch(0).phase == TouchPhase.Moved)
            {
                if (Input.GetTouch(0).position.x > Screen.width / 2 && pos.x > Screen.width/2)
                {
                    joystick.transform.position = pos;
                    joystick.SetActive(true);
                    pointerDown = true;
                }
            }
        }
        if (pointerDown && Input.GetMouseButtonUp(0))
        {
            pointerDown = false;
            joystick.transform.parent.GetComponent<VirtualJoystick>().inputVector = Vector3.zero;
            joystick.SetActive(false);
        }
    }
}

I moved the script to the Virtualjoystick canvas and removed the transparent UI image named “JoystickZone.” .

I think because you don’t have an image to raycast against now , you cannot use the Drag.

For the record, I believe you could have continued using ‘touch’ for the pointer interfaces. Unless you literally just wanted to try writing it with the ‘Touch’ stuff… (if that makes sense when you read it!) :slight_smile:

I realized that I needed to use touch since my controls also have to allow for me to tap on objects in the game. If I have a panel on the right for movement and a panel on the left for the camera, I get some weird interactions when trying to just tap. Yes, I could use the way I was trying to do but touch seems like the easiest route for me. I just need to figure out how to get OnDrag to run.

I figured with the previous interactions with the Joystick, this would work since the mouse/finger will be moving on top of the joystick when it appears.

That’s cool, if you feel the touch is better for you :slight_smile:

Well, if I understood you correctly and you said that the script is now on the canvas, as I was saying there is no Image/raycast target.