EventSystem.current.IsPointerOverGameObject(t.fingerId) - Not working on Android builds - Unity

EDIT: See the bottom for the new version of the update method. The touch behind the UI button is still hitting the ground below it. I’ve tried everything , and it seems that its exactly the same as the documentation, and the many tutorials and videos ive been through (although I have seen some conflicting info on how to fix this in some instances)

Ok so I have followed through about 5 tutorials and read over 5 separate forum discussions on the above method. For some reason in my game, the touch the UI button does occur, but the touch is also carrying through the button and hitting the ground below. This is in turn triggering my player to move even though i explicitly tell it not to in the same block of code.

It appears to me after much debugging already (I still could easily be wrong obviously else I wouldnt be writing this!), that its all working as it should, and t.phase Began isnt getting called when its on the button. However t.phase Ended is getting called RIGHT AT THE END WHEN I RELEASE THE BUTTON, and all my bools that I added purely to see what was happening change at this time back to currentControlState.MOVE (which is the enum i made for shoot and move. It’s supposed to stay as SHOOT until the pointer has completely left the shoot button, but somehow the touch that is registered underneath the button persists long enough to make my code set everything to mvoe to that position.

Basically here is what i wanted to happen: The player will be able to touch any area of the screen , and the ‘goodguys’ (players characters) will move to that spot using SetDestination in the NavMeshAgent. OK that was all done. Then if the player touches and holds the Shoot button (the UI button in question regarding this entire post!) , this will turn the enum state to SHOOT. Once in this state, if the player uses a second finger on the world, the ‘goodguys’ fire in the direction they are currently facing.

All the code was looking fine to me to begin with but it hasnt worked. I posted about trying to find help but didnt get a reply, so thought I’d post a more full version of the question. And this time the complete source code is to follow. Please note I have triple-checked the Inspector in Unity for missing objects, I’ve checked ‘Force Module Active’ on the Standalone Input module as suggested, I’ve added a ‘Physics Raycaster’ to the main camera as suggested. I’ve tried dozens of variations/locations of the if statement checking isPointerOveRGameObject…

It must have been 20 straight hours i’ve been trying to get it to work, and now the code looks worse than ever. Any help would be massively appreciated as always.

Code:

public class TouchHandler : MonoBehaviour 

{ RaycastHit hit; Camera cam; GameObject[] goodguys;

private void Awake()
{
    goodguys = GameObject.FindGameObjectsWithTag("Goodguy");
    cam = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>();
}

void Update()
{

if (Input.touchCount >= 0)
{
    goodguys = GameObject.FindGameObjectsWithTag("Goodguy");

    foreach (Touch t in Input.touches)
    {
        if (EventSystem.current.IsPointerOverGameObject(t.fingerId))
        {
            // hit UI , so ignore
            Debug.Log("HIT UI AN IGNORED - YEAH RIGHT!");

        }
        else
        {
            Ray ray = cam.ScreenPointToRay(t.position);
            if (Physics.Raycast(ray, out hit))
            {
                if (t.phase == TouchPhase.Began)
                {

                    Debug.Log("FINGER BEGAN = " + t.fingerId);
                    Debug.Log("BEHIND BUTTON TRUE OR FALSE? = " + EventSystem.current.IsPointerOverGameObject(t.fingerId));
                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchStart", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Moved)
                {
                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchMoved", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Stationary)
                {

                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchStill", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Ended)
                {

                    Debug.Log("FINGER PRESS ENDED = " + t.fingerId);
                    Debug.Log("BEHIND BUTTON TRUE OR FALSE (ended)? = " + EventSystem.current.IsPointerOverGameObject(t.fingerId));
                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchEnded", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Canceled)
                {

                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchCancelled", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
            }
        }
    }
}
}
// UI button toggles (called via inspector Event Trigger PointerUp and PointerDown methods:
public void UiButtonShootModeToggle()
{
foreach (GameObject goodguy in goodguys)
{
    if (goodguy.GetComponent<Goodguy>().currentControlMode != Goodguy.ControlMode.SHOOT)
    {
        goodguy.GetComponent<Goodguy>().currentControlMode = Goodguy.ControlMode.SHOOT;
    }
    else  if (goodguy.GetComponent<Goodguy>().currentControlMode == Goodguy.ControlMode.SHOOT)
    {
        goodguy.GetComponent<Goodguy>().currentControlMode = Goodguy.ControlMode.MOVE;

    }
}
}

}

public class Goodguy : MonoBehaviour {
[HideInInspector] public enum ControlMode { MOVE, SHOOT }
[HideInInspector] public ControlMode currentControlMode = ControlMode.MOVE;
public float bulletSpeed;
public float shotFireDelay;
private float shotFireTimer = 999f;

string firstName;
float health;
NavMeshAgent navMeshAgent;
GameObject bulletPrefab;

private void Start()
{
navMeshAgent = GetComponent<NavMeshAgent>();
bulletPrefab = Resources.Load<GameObject>("Bullet");
}
private void ShootGun()
{
shotFireTimer += Time.deltaTime;
if (shotFireTimer >= shotFireDelay)
{
    GameObject bullet = Instantiate(bulletPrefab, transform.position, transform.rotation);
    bullet.GetComponent<Rigidbody>().AddForce(transform.forward * bulletSpeed);
    shotFireTimer = 0f;
}
}

public void SetDestination(Vector3 target)
{

Debug.Log("at point of settingDestination, currentMode is: " + currentControlMode);

navMeshAgent.destination = target;

}

// TouchHandler calls these methods and outputs 'hit' to them:
public void OnTouchBegan(RaycastHit hit)
{
if (currentControlMode == ControlMode.SHOOT)
{
    transform.LookAt(hit.transform);
    ShootGun();
}
}
public void OnTouchEnded(RaycastHit hit)
{
if (currentControlMode == ControlMode.MOVE)
{
    SetDestination(hit.point);
}
}
public void OnTouchMoved(RaycastHit hit)
{
if (currentControlMode == ControlMode.SHOOT)
{
    transform.LookAt(hit.transform);
    ShootGun();
}
}
public void OnTouchStill(RaycastHit hit)
{

if (currentControlMode == ControlMode.SHOOT)
{
    transform.LookAt(hit.transform);
    ShootGun();
}
}
public void OnTouchCancelled(RaycastHit hit)
{

}

}

HERE IS WHAT THE UPDATE METHOD LOOKS LIKE NOW SINCE CHANGING IT BACK TO THE WAY SUGGESTED (BUT IT STILL DOESNT WORK). The touch behind the big UI button i have is still getting recorder, and upon releasing my finger, the characters move towards it, which is not what i want to happen when a finger is pressing the button, only if it presses somewhere other than the button:

void Update()
{
    if (Input.touchCount >= 0)
    {
        goodguys = GameObject.FindGameObjectsWithTag("Goodguy");

        foreach (Touch t in Input.touches)
        {
            Ray ray = cam.ScreenPointToRay(t.position);
            if (Physics.Raycast(ray, out hit))
            {
                if (t.phase == TouchPhase.Began)
                {
                    if (!EventSystem.current.IsPointerOverGameObject(t.fingerId))
                    {
                        // hit UI , so ignore
                        Debug.Log("THIS SHOULD ONLY BE CALLED IF FINGER IS NOT OVER UI !!!!!!!!!!!");

                        Debug.Log("FINGER BEGAN = " + t.fingerId);
                        Debug.Log("BEHIND BUTTON TRUE OR FALSE? = " + EventSystem.current.IsPointerOverGameObject(t.fingerId));
                        foreach (GameObject goodguy in goodguys)
                        {
                            goodguy.SendMessage("OnTouchStart", hit, SendMessageOptions.DontRequireReceiver);
                        }
                    }

                }
                if (t.phase == TouchPhase.Moved)
                {
                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchMoved", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Stationary)
                {

                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchStill", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
                if (t.phase == TouchPhase.Ended)
                {
                    Debug.Log("FINGER PRESS ENDED = " + t.fingerId);
                    Debug.Log("BEHIND BUTTON TRUE OR FALSE (ended)? = " + EventSystem.current.IsPointerOverGameObject(t.fingerId));
                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchEnded", hit, SendMessageOptions.DontRequireReceiver);
                    }
                }
                if (t.phase == TouchPhase.Canceled)
                {

                    foreach (GameObject goodguy in goodguys)
                    {
                        goodguy.SendMessage("OnTouchCancelled", hit, SendMessageOptions.DontRequireReceiver);
                    }

                }
            }
        }
    }
}

you can use this code to check touch & mouse

/// <returns>true if mouse or first touch is over any event system object ( usually gui elements )</returns>
		public static bool IsPointerOverGameObject(){
			//check mouse
			if(EventSystem.current.IsPointerOverGameObject())
				return true;
			
			//check touch
			if(Input.touchCount > 0 && Input.touches[0].phase == TouchPhase.Began ){
				if(EventSystem.current.IsPointerOverGameObject(Input.touches[0].fingerId))
					return true;
			}
			
			return false;
		}

The last line from the manual page for EventSystem.IsPointerOverGameObject states that:

Note that for touch,
IsPointerOverGameObject should be used
with OnMouseDown() or
Input.GetMouseButtonDown(0) or
Input.GetTouch(0).phase ==
TouchPhase.Began.

Also check out the second demo code on that page which takes pointerId as parameter as to how they have suggested to do it. Posting the code below for convenience.

void Update()
{
    // Check if there is a touch
    if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
    {
        // Check if finger is over a UI element
        if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
        {
            Debug.Log("Touched the UI");
        }
    }
}

And this seems to be the issue in your case.