安卓多点触控干扰问题

15

我正在为Android开发一个空气曲棍球模拟器。在多人游戏模式下,我要跟踪屏幕上的两个触摸事件,只要触摸点不太接近,这种方法就能正常工作。

Normal Touch

但是当这两个手指靠得太近时,Android只会识别到一个触摸事件,位于两点之间的中心位置。

Two events overlapping

更糟糕的是,Android有时在碰撞后混淆ID。

Wrong IDs assigned

我已经考虑过估计下一个触摸点并手动分配ID,但是否有更好的方法或已经有人通过编程解决了这个问题呢?

注意:我是在三星 Galaxy S3上进行测试的。


你尝试过在Android 4.0中处理手势吗?从我所看到的,似乎你仍然在以Android 2.3 SDK的方式处理触摸/手势。只是猜测而已 :) - Sarath Vuyyuru
两者有什么区别?这些图片只是 Android 触摸手势调试器的截图。 - NCode
+1 表示对问题解释得好 - Saeed-rz
3个回答

6

虽然这不是解决问题的合乎逻辑的方法,但却是一种可能的应用解决方案:

如果我没有弄错,气球曲棍球游戏不应该允许对手侵入到彼此的游戏场地。如果我们假设在屏幕中央(竖屏模式)横跨一道厚厚的边框,那么我就不能越过那个边界线去做什么事情,因此在达到边界线后追踪我的手指就没有意义了。

将跟踪到的触摸事件封装成有效的物理位置可能会有所帮助,以忽略无效点(前提是物理位置不相交)。

您还需要跟踪触摸向量的方向:如果向量从屏幕中心延伸到“您的一端”,则可能是对手侵入的手指或您自己返回的手指。在任何情况下,它们都不应影响曲棍球(也许)。


将玩家的移动限制在他们的领域内是个好主意。而且,一个厚实的边框可能会从心理上阻止玩家试图越过它移动 ;) - NCode

2

这可能取决于您使用的设备,但我在华为X5上使用以下代码时,即使手指相互接触或我将它们扭曲到屏幕上,也不会出现混乱。

private static PointF touchScreenStartPtArr[] = new PointF[10];
private static PointF touchScreenStopPtArr[] = new PointF[10];
private static PointF touchScreenCurrPtArr[] = new PointF[10];

OnTouchListener onTouchListenerMulti = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        int action = event.getAction() & MotionEvent.ACTION_MASK;
        int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        int fingerId = event.getPointerId(pointerIndex);

        switch (action) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_POINTER_DOWN:
            touchScreenStartPtArr[fingerId].x = event.getX(pointerIndex);
            touchScreenStartPtArr[fingerId].y = event.getY(pointerIndex);
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_POINTER_UP:
        case MotionEvent.ACTION_CANCEL:
            touchScreenStopPtArr[fingerId].x = event.getX(pointerIndex);
            touchScreenStopPtArr[fingerId].y  = event.getX(pointerIndex);
            break;
        case MotionEvent.ACTION_MOVE:
            int pointerCount = event.getPointerCount();
            for (int i = 0; i < pointerCount; i++) {
                touchScreenCurrPtArr[fingerId].x = event.getX(i);
                touchScreenCurrPtArr[fingerId].y = event.getY(i);
            }
            break;
        }
        return true;
    }
};  

请注意,我使用的是fingerId而不是pointerId来识别正确的手指,因为当一个手指被释放时,pointer id可能会改变。
希望这对你有用。

正如@heycosmo所提到的,触摸屏分辨率会导致触摸事件过于接近时被视为一个事件。您的解决方案并不能解决这个问题。 - NCode
理论上,您可以将@heycosmo的描述想象成现实中的物理表示,其中您会有一个一像素宽的手指。但事实并非如此,您的手指同时触摸了几个像素,并且永远无法用两个不同的手指触摸相邻的像素,因为您的手指有几个像素宽并且末端是圆形的。由设备驱动程序解释每个手指同时按下的多个点的方式取决于设备驱动程序。我可以向您保证,上面的代码在我的设备上完美运行。无论如何,都不可能弄乱手指。 - Luis
抱歉关于链接的问题,这是正确的链接:http://stackoverflow.com/questions/12590738/android-multitouch-cant-move-2-pointers-at-same-time/12592940#12592940。正如我所说,这可能取决于您设备使用的特定驱动程序。我已经在几个应用程序中使用了上面的代码,在您的评论之后,我尝试将手指移动得尽可能接近,将一个手指按在另一个手指上并扭曲它们,但在我的设备上没有失败。顺便问一下,您是否为了确认尝试了我的建议? - Luis
我将所有事件发送到logcat,但当我的手指靠得太近时,只收到一个触摸点。您的解决方案缓存位置,但这并不妨碍Android混淆手指的pointerIds。因此,在接近后,在某些情况下,新位置保存在错误的索引处。可能华为拥有比三星更好的驱动程序或更好的触摸屏。 - NCode
很抱歉它没有帮到您 :-(。只是为了确认,当您说指针id是指手指id时,您是指上面代码中的fingerId,而不是pointerIndex。正确吗?因为在我的设备上,pointerIndex也会改变,但fingerId仍然正确。 - Luis
显示剩余3条评论

2

我这样理解。

触摸屏硬件会给你提供一个分辨率,低于该分辨率时两个触点会被认为是一个。这是不可改变的。

现在的问题是,当两个触点合并时怎么办?(这可以通过编程进行测试;例如,如果 2 个触点 -> 1 个触点,且前一个触点 1 足够接近于前一个触点 2 ...)。在您的情况下,我会沿着合并的触摸手势移动两个 pucks 直到它们分离,然后返回单独的控制。

当然,我还看到了一些问题,比如在拆分后哪个触点控制哪个 puck?也许有一个人在合并期间抬起了他们的手指。

如果出现合并,则可以使双方玩家失去对自己的 puck 的控制。这可以模拟手腕撞击对手时的震动 :)

我也喜欢 @dbm 的想法。

希望这能有所帮助。可能没有:)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接