When Panning camera, the objects get selected (Drag Threshold fix did not work)

I have been developing a mobile game lately and I stumbled on a problem that seems a bit harder to solve than I thought.

To better understand my explanation, I’m uploading an image of a part of my map below.

As it is a mobile game the user will interact with the game by touch. That being said, the player can interact with the camera by using pan, zoom and rotate which are functioning perfectly. One of the other possible interactions, is clicking these blue rectangles on the map that will perform an action.

The problem is, that when panning the camera, the rectangles will be selected if you start the panning movement on top of one of them.

I did some research and found that changing the Drag Threshold can usually fix the problem. So I did something like this but it didn’t fix the issue. I want to make clear that I am aware that in order to correctly test that, building the project is required.

void Start () {
int defaultValue = EventSystem.current.pixelDragThreshold; 
EventSystem.current.pixelDragThreshold =
Mathf.Max(
defaultValue ,
(int) (defaultValue * Screen.dpi / 160f));
}
}```
Code from: http://ilkinulas.github.io/programming/unity/2016/03/18/unity_ui_drag_threshold.html

The last thing that I believe is relevant to mention is that both of those functions (camera controlling and rectangle selections) are in different scripts.

What makes sense to me is doing something like "When the camera is panning, do not cast the ray that checks if the click was on a rectangle", but I'm unsure of how to that given that they are different scripts and also not sure if It will work, because I have doubts if it selects the rectangle before or after it enters the panning loop.

Anyways, I am opened to suggestions and If further information is required, please do not hesitate to ask, I will provide it swiftly.

Drag threshhold might fix the problem, or it might just be hiding it, only to have it come up later on higher-resolution screens (for instance).

The traditional way is to have a stateful controller, something that has states like this:

OFF
SELECTING
DRAGGING

If there are no touches, it goes to OFF

When a touch comes in, it switches to SELECTING

As soon as the finger moves “enough,” it switches to DRAGGING and stays there until returning to OFF

If the finger lifts, and it is DRAGGING, no further action

If the finger lifts and it is still SELECTING, then do the selection.

It can be helpful to sketch out a flow diagram for something like this, and then the coding is much easier.

Your panning script and the blue boxes (which I assume is using the eventsystem) are doing their work in parallel from each other. Since the behavior of the one script needs to directly affect the control flow of the others you need to set up some interaction between them

You can have your camera control script access the PointerInputModule (the one which is propagating the click events to the blue squares) and call the method GetPointerData(touch or touchId, out pointerEventData,false) when it begins its panning behaviour. Then set pointerEventData.pointerClick to null if GetPointerData() returned true (true meaning one existed). Basically what this does is it tells the input module that there is no object to send an OnClick event to. Thus when the pointer is released the input module will not raise a click event down to the blue boxes.

You can also do other things to the recovered pointereventdata as well, such as change the dragstate or access what object the player pressed on.

Thanks for the replies!

Hey Joshua, I’m sorry for the delay in my response, but I have been using my time to solve other issues of the project.

I really liked how your logic would fit into my existing code and I understood the general idea, thought I need to figure some things out, like how can I use the GetPointerData method if it is protected?

Its protected, you can write a custom class that inherits from the Inputmodule, its not a sealed class. And you can have that class clear the click state internally on function call.

I see. I know it’s a lot to ask, but I have no idea on how to do that and make it work.
Would it be possible to give me a quick example?

–EDIT–

The only thing I found was this post and it no longer works. I tried it and I got the same error as them.

https://answers.unity.com/questions/897514/how-to-get-last-raycast-info-from-eventsystem-or-p.html

The code isn’t too difficult. The answer you are referring to was for Unity 4.6 which was years ago. The Eventsystem has since then been moved to a package and the API documentation likewise also moved to the Packages API site

using UnityEngine.EventSystems;

public class MyInputModule : StandaloneInputModule
{
    public void ClearAllPressedPointers()
    {
        PointerEventData data;
        for(int index = 0, count = Input.touchCount; index < count; index++)
        {
            if(GetPointerData(index,out data,false))
            {
                data.pointerPress = null;
            }
        }
    }
}

This simply loops through all the current pointers being tracked and clears the tagged gameobject that was pressed in them. When you release your pointer Unity will then process the Pointer event data and will find that theres no Pointer Press object to process, and thus no object to send OnPointerUp and OnPointerClick messages to. The pointereventdata may still be tracking that object in its rawPointerPress field, so you may need to null that field as well if it still causes problems, but iirc Unity only uses that field on pointer press, not on pointer release.

[JoshuaMcKenzie]( When Panning camera, the objects get selected (Drag Threshold fix did not work) members/joshuamckenzie.866650/) thanks for explaining it thoroughly, but despite preferring the logic you proposed I could not get it to work. I got a lot of errors and decided to take [Kurt-Dekker]( When Panning camera, the objects get selected (Drag Threshold fix did not work) members/kurt-dekker.225647/)'s approach and it worked!

Thank you both for the suggestions. I learned A LOT from them.

1 Like

That’s fine. Glad you were able to get it to work for you.

@JoshuaMcKenzie and @Kurt-Dekker , Hello!

I came across a very strange bug related to this.
I have an iPhone 11 Pro and I have been building the project onto it from the beginning and it worked perfectly. Once I released my game to the public, I got some reports that this functionality was being an issue (When trying to select something, it does not work as it’s supposed to, probably because the code thinks the person is dragging).

So, I tested it out on three different iPhoneX’s (Xs and X) and one iPhone 7 and it really has the issue the users were claiming.

What is weird is that it works perfectly on Android phone’s and in mine iPhone 11 Pro.

I am posting this because I have no clue of what this might be. I already have the “Drag Threshold Fix Script” added to my EventSystem.