Multi-touch Affects Raycast Accuracy? [SOLVED]

Hello,

in my project, designed for touch, I use raycasting to select GameObjects on the scene. Also, by dragging your finger across the screen, you can rotate the scene to reveal other GameObjects to be selected. That worked great so far, when it was all limited to Input.touchCount == 1, but it meant you could only rotate or select GameObjects, not both at once.

Once I changed the code to enable multitouch, (using a for loop), an issue appears. If I only do one thing at once, with one finger on screen, it all still works great, but if I am rotating the scene with the first finger and I try to select GameObjects with a second finger, I have to tap about 20 pixels to the left of the object to select it, instead of on the object itself. Anyone here who had a similar problem?

Thanks!

I had an issue with a ScrollRect in my software that would scroll erratically when using multiple fingers (I assume Unity’s scroll-drag code is designed to work with a single mouse position, and there’s some code that converts the touches into a simulated-mouse position for it to work with, and that conversion produces erratic results when there are multiple fingers). I eventually worked around it by disabling the ScrollRect component whenever there were multiple touches and adding my own drag code for that case.

But if you are doing all your own raycasting based on individual touch coordinates, my first guess would be some kind of bug in your own code.

That was my first thought, but it all works great with one finger touch only (even with the multi-touch enabled). If I’m rotating with the first finger, then the second one is not working as it should.

for (int i = 0; i < Input.touchCount; i++)
        {
            Touch touch = Input.GetTouch(i);

            if (touch.phase == TouchPhase.Ended)
            {
                if (Time.time - startTime < 1.2)
                {
                    if (PlayerManager.gameOn == false)
                    {
                        some unrelated code here
                    }
                    else
                    {
                        RaycastHit hitInfo = new RaycastHit();
                        if (Physics.Raycast(mainCam.ScreenPointToRay(Input.mousePosition), out hitInfo))
                        {
                            TapToDamage cubeToSelect = hitInfo.collider.GetComponent<TapToDamage>();
                            if (cubeToSelect != null)
                            {
                                cubeToSelect.tapToSelect();
                            }
                        }
                    }
                }
            }
        }

TapToDamage is a script and cubeToSelect is a function within it.

So the only difference is that before there was if (Input.touchCount == 1) instead of the for loop, and of course, Touch touch = Input.GetTouch(0) instead of Touch touch = Input.GetTouch(i). Otherwise all the code is identical. Is there something I’m doing wrong in the multi-touch implementation?

Oh, and all of this is nested within Update(), of course.

Unfortunately, you can’t assume that your code is correct for multiple touches just because it’s correct for one. It’s quite easy to write code that works fine when you’re only using it to handle one thing but fails when it tries to handle multiple things in parallel.

Your raycast on line 16 is using Input.mousePosition as the source of the raycast, instead of the position of the specific touch under consideration. That’s likely to be your problem. If I had to guess, it’s probably averaging the positions of your touches.

I also notice that you are checking the duration of the touch by comparing to the variable startTime on line 7. I don’t see where that’s initialized, but I’d guess you’re setting it equal to the current time whenever a touch starts, which means line 7 gives the duration of the touch if you only have one touch at a time, but if a second touch started while the first one was in progress then it will no longer be correct. That’s a good example of something that will work fine if you’re only monitoring one touch but could break when you try to handle multiple at once.

1 Like

Lovely!

Two very good points to investigate. Thanks for that!

And it’s fixed! As you suggested, it was probably averaging the positions of my touches because of the use of Input.mousePosition.

I didn’t include the initialization of startTime in my example by mistake, but it’s there in the code. I have updated it though to an Array, so that it checks the time difference for each finger individually now.