5

Ive been trying to develop this game where users have to click certain points on a image. Ive been storing these points based on their pixel locations. i can easily get the pixel pressed by getting the X and Y coordinates in the onTouch Event. But the problem im facing is that its practically impossible to press the exact location of the pixels every time( So for testing purposes ive set a tolerance to 40 px in all 4 directions). So is there a way i can set some sort of tolerance which can be adjusted from the settings menu so that it can be used by people with diff finger sizes with ease and played from different screen sizes? Any help or Suggestions is gratefully accepted

tolerance = 40
public boolean onTouchEvent(MotionEvent event) {
    // MotionEvent object holds X-Y values
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        int XCood = (int) event.getX();
        int YCood = (int) event.getY();
        int XMin = ActXCod[index] - tolerance, 
            XMax = ActXCod[index] + tolerance, 
            YMin = ActYCod[index] - tolerance, 
            YMax = ActYCod[index] + tolerance;
        if (index < (limit - 1)) // loop to check number of images
        {
            if(XCood > XMin && XCood < XMax && YCood > YMin && YCood < YMax){
            //Do stuff
        }}}

here XMin and XMax are the min and max rage the X co-ordinate can be in and Ymin and Ymax are the min and max range of the Y co-ordinate.
XCood and YCood are the a and y coordinates of the users touch.

candied_orange
  • 7,036
  • 2
  • 28
  • 62
Clinton Dsouza
  • 330
  • 4
  • 20
  • If you custom `onTouchEvent` method is working you can implement setting menu with seek bar and store you `tolerance` variable using [Shared Preferences][1]. [1]: http://developer.android.com/guide/topics/data/data-storage.html#pref – JohnDow Oct 27 '14 at 19:57
  • I can't tell if this question is about the collision detection problem, getting a tolerance setting from the user, or about how to calculate tolerance as a percentage. Are you really stuck on all three? – candied_orange Nov 01 '14 at 11:59

3 Answers3

3

I suggest you to take a look at the TouchDelegate, if I got your question right it should be exactly what you need. Once you have the tolerance from the settings, you can compute the proper amount of pixels to properly size the delegate.

There is some more information and sample code at http://developer.android.com/training/gestures/viewgroup.html#delegate

happy coding!

  • hi @francesco thanks for the suggestion. but the problem is that since i have set the tolerance to 40,it might be to small on a bigger screen is there a way to change that dynamically with the screen size?because i have to make sure that the touched pixel is close to actual pixel. – Clinton Dsouza Oct 28 '14 at 15:46
  • what about sizing the touchdelegate using the tolerance and image width and height? assuming you have a tolerance between 0 and 1, something like: (this is modified from the link I posted in the answer, not tested) `delegateArea.left -= tolerance*myButton.getWidth(); delegateArea.top -= tolerance*myButton.getHeight(); delegateArea.right += tolerance*myButton.getWidth(); delegateArea.bottom += tolerance*myButton.getHeight();` – Francesco Mapelli Oct 29 '14 at 09:32
1

users have to click certain points on a image tells me that rather than putting invisible/transparent buttons over the image, each with it's own event handling, you've opted to have any clicks on the image sent to one place and are going to decide what clicks go with what target.

enter image description here(a) enter image description here(b) enter image description here(c)

Which means if your image looked like (a) that you'd set up your dots (pixel locations) like (b):

This is understandably causing you problems since it's very hard for humans to hit those little targets.

You've decided the way to fix this is to give the human fatter fingers and are trying to calibrate how fat to make them. Lets try a use case where a user tries to dial 1238. In (c) I increase the size of their finger as they go. Since the press on 8 covered the dots from both 8 and 0 I'd say that's too big.

enter image description here(d) enter image description here(e) enter image description here(f)

(d) shows a reasonable size to calibrate with this approach. Notice that 1 and 3 still miss. 1 is a miss simply because these buttons aren't square. That's a limitation of this fat finger approach. 3 is a miss because the human actually missed and hit between the buttons. If you insist that 3 should count I don't know how we'd do it without 2, 5, & 6 counting as well. If that's what you want we need rectangular collision detection. More on that later.

Assuming 3 should be treated as a miss I'd like you to consider that (d) is mathematically identical to (e). It's achievable simply by adding the tolerance to the targets point not the users finger. 1 and 3 are still misses but now rather than being concerned with calibrating the fatness of a users finger, we only concern ourselves with how big the targets are.

Simply thinking this way gives us the freedom deal with the fact that our targets aren't square. They're rectangles. Doing that in (f) fixes 1 being missed. If you're targets are all the same size and proportional you don't need to deal with using different x and y tolerances. If you want to have the flexibility to change sizes so you can deal with that green button properly then stop modeling targets as a single point. Model them with a android.graphics.Rect. Actually I'd prefer you model them with their own class that contains a android.graphics.Rect but that's an OOP soap box I'll climb up some other time.

Assuming you've defined the target with a new Rect(left, top, right, bottom)] somewhere and assigned it to Rect r; you can now detect a hit with r.contains( (int) event.getX(), (int) event.getY() ); Since we've already thumbed our nose at the OOP gods and rejected the button idea I'd say for each click you loop thru all targets testing contains().

enter image description here(g)

Now, if you really insist that 2, 3, 5, and 6 should all trigger when the user misses hitting 3 then look into motionEvent.getSize(). That will measure the "fatness" of the touch from 0 to 1. If getToolMajor() or getTouchMajor() are available they might help you estimate the actual pixels touched. It may help to know the screen size but as far as I can tell from the documentation any pixel sizes produced by using any of this are going to be approximate. Some testing will help determine if this works as is or if any scaling constant is needed. This is likely smaller than you expect because these were designed for paint programs that give a bolder stroke with added pressure, not for watching your fingertip bump into things.

Use that like tolerance to build another Rect around the click (lets call it fatFinger). Test r.intersects(fatFinger) in a loop that supplies you with every r over your image. Every time it's true you've found another r to deal with.

That should give you something like (g). Now the 3 press is a 2, 3, 5, & 6 press, the 1 press is now a 1 & 4 press and the 8 press is a 8 & 0 press.

The 2 press is miraculously still just a 2 press. Pulling that off is nearly as hard as hitting the dots with touch dots. This might be fine for your game but please don't do it to my phone. :)

If you don't want to go insane, do a little OOP and make a class for your targets that contains a Rect and provide your own intersects method backed by the Rect one. That way you can loop them, get each t and when t.intersects(fatFinger) is true you can call your own t.wasTouched();

In short, fatten the targets, not the finger, unless you want it touching everything it comes near. If so, fatten both.

Regardless of if you decide to go with (f) or (g) I think you'll find much less of a need for the user to configure finger size if you take this approach. Happy coding!

candied_orange
  • 7,036
  • 2
  • 28
  • 62
  • +1 because of the deep thinking. Depending on the needs I see the risk of adding not needed complexity, but great analysis! – Francesco Mapelli Nov 03 '14 at 12:22
  • Thanks! If he's not doing (g) the easiest way to avoid complexity is to use the transparent buttons over the image trick I mentioned at the start. It's equivalent to (f) and takes the collision detection off your hands. – candied_orange Nov 03 '14 at 12:58
  • @ClintonDsouza Thanks for the hard earned bounty points. Just curious, out of all these solutions, transparent buttons, f, g or whatever, what did you end up going with? – candied_orange Nov 04 '14 at 03:24
  • @CandiedOrange F seemed the most interesting and closest to what i wanted so im going with that :) – Clinton Dsouza Nov 04 '14 at 06:24
0

So is there a way i can set some sort of tolerance which can be adjusted from the settings menu so that it can be used by people with diff finger sizes with ease and played from different screen sizes

If I understand you correctly, just store your tolerance in DP and convert it depending on screen density. Programmatically you may convert as described here: Convert dip to px in Android Or store available tolerance values in dimens.xml file and read this values from there.

Community
  • 1
  • 1
Dmitry_L
  • 1,004
  • 7
  • 8