6

我一直在玩游戏,我正在尝试制作控制器,没什么太复杂的,为此我需要跟踪 2 个输入(手指):1 开火按钮和移动键。(上、下、左、正确的)

这就是问题所在:手指 1 向下,手指 2 向下,手指 1 向上认为它是 2,然后手指 2 向上认为它是 1。

D/Controlls(18849): Action Down 1
D/Controlls(18849): Coordinates 267.7908 415.24274
D/Controlls(18849): Action Pointer Down 2
D/Controlls(18849): Coordinates 281.11423 417.23993
D/Controlls(18849): Action Pointer UP 1
D/Controlls(18849): Coordinates 272.7869 419.23718
D/Controlls(18849): Action UP 2
D/Controlls(18849): Coordinates 1148.103 439.20947

这是处理 2 个输入的 OnTouchEvent 的代码:

@Override
public boolean onTouchEvent(MotionEvent event) {
    int index = event.getActionIndex();
    int pointerId = event.getPointerId(index);
    int action = event.getActionMasked();

    int oldX, oldY;

    switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN:
        {
            hero.moveControlls((int)event.getX(), (int)event.getY());
            Log.d("Controlls", "Action Down "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
            break;
        }

        case MotionEvent.ACTION_UP:
        {
            hero.setScreenTouching(false);
            Log.d("Controlls", "Action UP "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
            break;
        }

        case MotionEvent.ACTION_POINTER_DOWN:
        {
            Log.d("Controlls", "Action Pointer Down "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());                   
            break;
        }

        case MotionEvent.ACTION_POINTER_UP:
        {
            Log.d("Controlls", "Action Pointer UP "+ pointerId);
            Log.d("Controlls", "Coordinates "+ event.getX() + " "+  event.getY());
            break;
        }
    }
    return true;
}

现在,我查看了示例,但无法理解它们。我在 API 中查找了 MotionEvent,它说要使用 $ACTION_POINTER_INDEX_SHIFT$,我不知道如何使用,因为他们没有示例或其他东西可以使其更容易理解。有关如何执行此操作的任何帮助?

4

3 回答 3

13

每当辅助指针向下或向上时,都会触发 ACTION_POINTER_DOWN 和 ACTION_POINTER_UP。如果屏幕上已经有一个指针并且有一个新的向下,您将收到 ACTION_POINTER_DOWN 而不是 ACTION_DOWN。如果指针上升但仍有至少一个触摸屏幕,您将收到 ACTION_POINTER_UP 而不是 ACTION_UP。

ACTION_POINTER_DOWN 和 ACTION_POINTER_UP 事件在操作值中编码额外信息。用 MotionEvent.ACTION_MASK 与它为我们提供动作常量,而用ACTION_POINTER_INDEX_MASK与它为我们提供向上或向下指针的索引

提取离开触摸传感器的指针索引的最佳方法。

int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;

我会相应地更改您的代码,如下所示:

case MotionEvent.ACTION_POINTER_UP:
{
    int index = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
    int pointId = event.getPointerId(index);
    Log.d("Controlls", "Action Pointer UP "+ pointerId);
    Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+  event.getY(index));
    break;
}
于 2013-02-22T17:50:50.783 回答
2

我认为混淆可能是方法总是返回getX()指针的getY()坐标(第一个/唯一一个向下)。因此,您的日志中的前三个事件手指 1 是主要事件,然后在最后一个事件中甚至只剩下手指 2,因此它成为主要事件。

如果要正确跟踪两个手指的事件,则需要使用getX(int)and getY(int); 将指针索引作为参数的版本,因此您可以离散地获取每个事件中每个手指的坐标。请注意,如果每个手指以不同的顺序上下移动,它们的索引可能会发生变化,但给定的手指将始终具有相同的指针 ID。

一个好的方法是检查每个事件中的指针数量(例如getPointerCount())。用一根手指,索引0有效;用两个手指,索引 0 和 1 有效。去获取每个有效指针的坐标,然后用getPointerId()它来确定每个坐标对应该匹配到哪个手指。

编辑

对您发布的返回右指针坐标的源代码的最简单修改是将索引添加到辅助指针的参数中,如下所示:

int index = event.getActionIndex();
int pointerId = event.getPointerId(index);
int action = event.getActionMasked();

int oldX, oldY;

switch (event.getActionMasked()) {
    case MotionEvent.ACTION_DOWN:
    {
        hero.moveControlls((int)event.getX(), (int)event.getY());
        Log.d("Controlls", "Action Down " + pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
        break;
    }

    case MotionEvent.ACTION_UP:
    {
        hero.setScreenTouching(false);
        Log.d("Controlls", "Action UP "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX() + " "+ event.getY());
        break;
    }

    case MotionEvent.ACTION_POINTER_DOWN:
    {
        Log.d("Controlls", "Action Pointer Down "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+ event.getY(index));
        break;
    }

    case MotionEvent.ACTION_POINTER_UP:
    {
        Log.d("Controlls", "Action Pointer UP "+ pointerId);
        Log.d("Controlls", "Coordinates "+ event.getX(index) + " "+  event.getY(index));
        break;
    }
}

这应该更符合您期望看到的记录数据。

于 2013-01-18T03:32:49.977 回答
0

如果您以与按下不同的顺序释放指针,上述代码可能会失败(使用多点触控时可能会发生什么情况)。我发现以下代码适用于 3 个指针,按下然后释放的顺序无关紧要:

    case MotionEvent.ACTION_UP: // for single touch
    case MotionEvent.ACTION_POINTER_UP: // when order of touch and release is the same
    case MotionEvent.ACTION_POINTER_UP + ((1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT)): // for any order of two pointers
    case MotionEvent.ACTION_POINTER_UP + ((2 << MotionEvent.ACTION_POINTER_INDEX_SHIFT)): // for any order of three pointers
    case MotionEvent.ACTION_OUTSIDE: // when moving touch out of the view
    case MotionEvent.ACTION_CANCEL: // when canceling touch (eg by home button)
    // some code to support releasing pointers
    break;

请记住, case语句旁边必须是一个常量值,因此您无法根据event.getMotion()计算值。

于 2014-01-14T21:15:28.267 回答