2
\$\begingroup\$

I'm trying to implement a virtual DPad in android, but I'm still very confused about how do I keep track of each trouch point, from the moment it is pressed, till it is released.

In my code, I test if there is a "DOWN" or "MOVED" event, then if one of this events collides with one of the 4 rectangles of my DPad, I set the pressedDirectin variable to the side of the DPad which the user pressed.

The thing I'm not sure, is how do I get track of the touch points, I want to store the ID of the touch point which collided with the DPad direction, so when this ID is moved I update the direction of the DPad and when it gets released I set the Direction to None.

I don't want my DPad to handle multiple directions, but I still didn't get how to handle the multiple touch points, so I can know exacly which touch point is touching the DPad and store it's ID so I know when it is released.

Is the onTouchEvent called for every touch point, or all touch points comes in a single call? I still don't get it.

Here is the code I wrote so far, it works, but guess that it will only handle one touch point.

public boolean onTouchEvent(MotionEvent event)
    {
        if (event.getPointerCount() == 0) 
            return true;

        int touchX = -1;
        int touchY = -1;

        pressedDirection = DPadDirection.None;
        int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
            if (actionCode == MotionEvent.ACTION_UP)
            {
                if (event.getPointerId(0) == idDPad)
                {
                    pressedDirection = DPadDirection.None;
                    idDPad = -1;
                }
            }
            else if (actionCode == MotionEvent.ACTION_DOWN || actionCode == MotionEvent.ACTION_MOVE)
            {                                     
                touchX = (int)event.getX();
                touchY = (int)event.getY();     

                if (rightRect.contains(touchX, touchY))
                    pressedDirection = DPadDirection.Right;
                else if (leftRect.contains(touchX, touchY))
                    pressedDirection = DPadDirection.Left;
                else if (upRect.contains(touchX, touchY))
                    pressedDirection = DPadDirection.Up;
                else if (downRect.contains(touchX, touchY))
                    pressedDirection = DPadDirection.Down;

                if (pressedDirection != DPadDirection.None)
                    idDPad = event.getPointerId(0);    
            }              

        return true;
    }
\$\endgroup\$
4
  • \$\begingroup\$ When I asked about building a dpad on a touch screen, I was advised against it: gamedev.stackexchange.com/questions/5384/… -- there is some wisdom there. Unless your game requires it because its a port from another platform you might want to look at another solution. \$\endgroup\$
    – Nate
    Feb 17, 2011 at 16:21
  • \$\begingroup\$ The game I want to make requires it, I'll make some controls use the touch screen, but the movement itself (basicay walk left, right and dash/run) requires it because the touch screen will be used to aim/shoot, so you move the char with the dpad and "point and click" to blow things up :) \$\endgroup\$ Feb 17, 2011 at 16:38
  • \$\begingroup\$ Could please you explain what you are trying to accomplish? What is your goal when keeping track of multiple touch points? Gestures? \$\endgroup\$
    – f20k
    Feb 17, 2011 at 19:51
  • \$\begingroup\$ No, I want to keep track of which finger is pressing the DPad, the player can press down, and then move the finger to the right, so if I dont't keep track, the event ACTION_DOWN will modify the direction to down, but when the touch point is moved to the left the DPad will not correct the direction to left, so I need to know where the finger is until the ACTION_UP is triggered, that's why I store the ID of the touch Point, but I'm confused about the correct way of doing it in android. \$\endgroup\$ Feb 18, 2011 at 14:41

3 Answers 3

2
\$\begingroup\$

Given what you've told me in your comment, you can do something like this:

float touchX, touchY;

public boolean onTouchEvent(MotionEvent event)
{
        if (event.getAction() == MotionEvent.ACTION_DOWN || 
            event.getAction() == MotionEvent.ACTION_MOVE)
        {   
           // store values
           touchX = event.getX();
           touchY = event.getY();
        } else if(event.getAction() == MotionEvent.ACTION_UP) 
        {
           // reset values
           touchX = 0f;
           touchY = 0f;
        }     
        // consume motion event
        return true;
}

In action_down or action_move, you store the event.getX() and event.getY() coordinates in a field outside the onTouchEvent class. Then in your update loop, before you do anything with the pressedDirection, you have your code:

           if (rightRect.contains(touchX, touchY))
             pressedDirection = DPadDirection.Right;
            else if (leftRect.contains(touchX, touchY))
                pressedDirection = DPadDirection.Left;
            else if (upRect.contains(touchX, touchY))
                pressedDirection = DPadDirection.Up;
            else if (downRect.contains(touchX, touchY))
                pressedDirection = DPadDirection.Down;

            if (pressedDirection != DPadDirection.None)
                idDPad = event.getPointerId(0);    

           // do something based on pressedDirection

So in the onTouchEvent you store the values the touch coordinates. In your game loop, you do the checks to see if the coordinates are in the appropriate Rects. Then you run the rest of your game code. You reset the values to zero when the MotionEvent is an ACTION_UP

\$\endgroup\$
0
\$\begingroup\$

All the touch points come in a single call. And most of the accessor functions on the MotionEvent class have an overloaded function that takes in pointer index.

So use MotionEvent.getPointerCount() and loop through your mouse pointers.

http://developer.android.com/reference/android/view/MotionEvent.html

Hope this helps.

\$\endgroup\$
6
  • \$\begingroup\$ The event is called for every action then? Because I didn't find out how to get the action of each pointer. \$\endgroup\$ Feb 18, 2011 at 15:27
  • \$\begingroup\$ Yeah. Each time a new finger hits the touch surface the event will be called. Check the ACTION_POINTER_INDEX_MASK for figuring out which pointer has which state. \$\endgroup\$
    – Nailer
    Feb 18, 2011 at 15:29
  • \$\begingroup\$ Hm. It seems you can use getAction() to get the action and getActionIndex to find out which pointer caused the action. \$\endgroup\$
    – Nailer
    Feb 18, 2011 at 15:40
  • \$\begingroup\$ Now I'm starting to get it (or not), I found this article: firstdroid.com/2010/06/10/making-sense-of-multitouch and if I understood correctly, the pointer index is really an index, so If I want to keep track of that SPECIFIC pointer I need to use the ACTION_POINTER_INDEX_MASK with ACTION_POINTER_UP to see if the pointer I'm tracking was released, is that it? \$\endgroup\$ Feb 18, 2011 at 15:45
  • \$\begingroup\$ One question though: Why do you have to store the pointer id? Can't you just loop through all the pointers and determine which buttons have collisions with them every time the touchEvent has fired? \$\endgroup\$
    – Nailer
    Feb 18, 2011 at 15:54
0
\$\begingroup\$

Remember that many (most?) Android devices don't allow true multitouch; on those phones, once the user is using one finger on your virtual dpad and press elsewhere on the screen at the same time you're going to get random positions sent to your app from the phone and there's nothing you can do about it.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .