0

I have a Unity WebGL player that is embedded in a React application. The React application has drag and drop tiles that can be drug and dropped onto the WebGL player. When the tiles begin to be drug unity starts raycasting so that you can tell what object in the screen you are going to drop onto. All of this works perfectly when using a mouse, but I've noticed Input.touchCount always returns 0 unless the touch originates inside the WebGL player. Does anyone know a fix to this? Been head bashing this one for a moment now...

Here is the raycasting code. Like I said, it works perfectly for a mouse... but I cannot get a touch.position returned.

public void LateUpdate()
{
    if (SHOULD_CAST_RAY)
    {
        // always returning 0
        Debug.Log(Input.touchCount);

        RaycastHit hit;
        Vector3 position = Input.touchSupported
            && Input.touchCount == 1
                ? new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 0)
                : Input.mousePosition;

        if (Physics.Raycast(RigsCamera.ScreenPointToRay(position), out hit, CameraRigControllerScript.CameraDistanceMax * 1.5f, 1 << 10))
        {
            if (CURRENT_SELECTION == null)
            {
                CURRENT_SELECTION = UnsafeGetModelInstantiationFromRaycast(hit);
                ApplySelectionIndication();
            }
            else if (!IsAlreadySelected(hit))
            {
                RemoveSelectionIndication();
                CURRENT_SELECTION = UnsafeGetModelInstantiationFromRaycast(hit);
                ApplySelectionIndication();
            }
            return;
        }

        if (CURRENT_SELECTION != null)
        {
            RemoveSelectionIndication();
            CURRENT_SELECTION = null;
        }
    }
}

Also, if I touch the screen on the Unity WebGL player and then start dragging one of my React components which sends a message to Unity to start raycasting; I get atouch.position that is at the point I touched and does not move with the finger... The hell?

Kyle Richardson
  • 5,567
  • 3
  • 17
  • 40

2 Answers2

0

If you have Unity 5+ version you can use mousePosition for everything, since the Input class handles the Touch (0) and Mouse (0) exactly the same, have you tried that?

Vector3 position = Input.touchSupported && Input.touchCount == 1
? new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 0)
: Input.mousePosition;

Try changing this to only

Vector3 position = Input.mousePosition;
Horothenic
  • 680
  • 6
  • 12
  • Do you have a link to any documentation that states this? This is not mentioned in the Unity documentation for `Input` nor `Input.mousePosition`. I also tried it, and unfortunately it doesn't work; it just always returns (0, 0, 0). – Kyle Richardson Aug 16 '18 at 18:34
  • I know that by experience, but here is a post that states that too. https://answers.unity.com/questions/180987/inputmouseposition-equivalent-to-first-finger-touc.html – Horothenic Aug 16 '18 at 22:33
  • It may be a problem like you stated with the hardware events from mouse and touch screen, if that is the case you should look for a way to "manually" find the touch from Unity instead of waiting for Unity to detect it, but don't know if that is possible. – Horothenic Aug 16 '18 at 22:36
  • 1
    It has something to do with the touch originating outside of the player. From that point forward it only returns (0, 0, 0) until you lift your finger and then touch inside the player. Then the point you touched is returned for touches outside of the player... very strange. I know how to work around this, but this behaviour needs attention from the unity team. I'll move to their forums and post a video. – Kyle Richardson Aug 16 '18 at 23:22
0

I posted a solution on the Unity forums in-case there is any update to this thread in the future.

In WebGL, the Unity Input class does not register touch events that originate begin outside of the WebGL player. To solve this problem I used a couple boolean values that are toggled by my React components through the GameInstance.SendMessage method; as well as a Vector3 to store a value sent from React, also through SendMessage. Here are the important c# bits. If anyone has any questions, please ask and I'll walk you through the rest!

bool SHOULD_CAST_RAY;
bool USE_EXTERNAL_ORIGINATING_TOUCH_POS;
Vector3 EXTERNAL_ORIGINATING_TOUCH_POS;

public void LateUpdate()
{
    if (SHOULD_CAST_RAY)
    {
        if (USE_EXTERNAL_ORIGINATING_TOUCH_POS && EXTERNAL_ORIGINATING_TOUCH_POS.z < 0) { return; }

        RaycastHit hit;
        Vector3 screenPoint = Input.mousePresent ? Input.mousePosition : Vector3.zero;
        Vector3 viewportPoint = USE_EXTERNAL_ORIGINATING_TOUCH_POS ? RigsCamera.ScreenToViewportPoint(EXTERNAL_ORIGINATING_TOUCH_POS) : Vector3.zero;

        if (Physics.Raycast(
            USE_EXTERNAL_ORIGINATING_TOUCH_POS
                ? RigsCamera.ViewportPointToRay(new Vector3(viewportPoint.x, 1 - viewportPoint.y, 0))
                : RigsCamera.ScreenPointToRay(screenPoint),
            out hit,
            CameraRigControllerScript.CameraDistanceMax * 1.5f,
            1 << 10
        )) {
            if (CURRENT_SELECTION == null)
            {
                CURRENT_SELECTION = UnsafeGetModelInstantiationFromRaycast(hit);
                ApplySelectionIndication();
            }
            else if (!IsAlreadySelected(hit))
            {
                RemoveSelectionIndication();
                CURRENT_SELECTION = UnsafeGetModelInstantiationFromRaycast(hit);
                ApplySelectionIndication();
            }
            return;
        }

        if (CURRENT_SELECTION != null)
        {
            RemoveSelectionIndication();
            CURRENT_SELECTION = null;
        }
    }
}

// The below methods are used to control the raycasting from React through sendMessage
public void ClearExternalOriginatingTouchPosition()
{
    EXTERNAL_ORIGINATING_TOUCH_POS = new Vector3(0, 0, -1f);
    USE_EXTERNAL_ORIGINATING_TOUCH_POS = false;
}

public void DisableRaycasting()
{
    SHOULD_CAST_RAY = false;
    RemoveSelectionIndication();
    CURRENT_SELECTION = null;
}

public void EnableRaycasting()
{
    SHOULD_CAST_RAY = true;
}

public void SetExternalOriginatingTouchPosition(string csv)
{
    string[] pos = csv.Split(',');
    EXTERNAL_ORIGINATING_TOUCH_POS = new Vector3(float.Parse(pos[0]), float.Parse(pos[1]), 0);
    USE_EXTERNAL_ORIGINATING_TOUCH_POS = true;
}
Kyle Richardson
  • 5,567
  • 3
  • 17
  • 40