如何检测android中某个渲染器区域内的触摸事件?

时间:2016-12-27 14:25:17

标签: android opengl-es

在android中我采用了旋转球体示例given here。它创建了一个显示旋转球体(地球)的简单应用程序。

现在,如果在手机显示屏上按下旋转球体,我想做点什么。我不想对旋转球体的的触摸事件做出反应。以下是我到目前为止尝试使用GLSurfaceView的派生版本:

public class MyGLSurfaceView extends GLSurfaceView {



    MyGLSurfaceView(Context context) {
        super(context);
    }

    public boolean onTouchEvent(MotionEvent event) {
        int x = (int)event.getX();
        int y = (int)event.getY();
        Log.d("onTouchEvent",String.format("keyCode: %d  coords: %d  %d", event.getActionMasked(), x, y));

        Renderer renderer = this.Renderer.getRenderer(); // ERROR
        return super.onTouchEvent(event);
    }

}

没有ERROR行,此代码可以工作,当我按下显示器时,我得到x / y坐标。

但是,为了评估事件是否球体中,我的方法是获取具有Sphere对象的渲染器以确定x / y坐标是否在球体。

但是ERROR行不起作用,我收到错误说

Error:(26, 56) error: cannot find symbol method getRenderer()

如何修复此错误;或者,如果事件发生在Sphere - 图形对象上,是否有更明智的方法可以自动查找?

更改构造函数并将渲染器实例传递给MyGLSurfaceView也许是一个好主意? ADDENDUM:这个想法似乎不起作用。我得到一个构造函数错误,我不明白...

3 个答案:

答案 0 :(得分:4)

您的问题要比检测触摸事件复杂得多。渲染器不仅具有球体对象,还包含整个OpenGL ES内容。因此,即使您检测到触摸事件,也需要将屏幕2D坐标转换为3D光线并检查它是否与球体相交。这称为光线投射Here是光线投射算法的一个很好的解释。还有一个good video tutorial用于实现光线投射Java。

此外,您将希望在GLSurfaceView的构造函数中传递渲染器,就像您和@ satm12建议的那样。

答案 1 :(得分:1)

我认为,就像你建议的那样,在构造函数中传递渲染器是个好主意。然后传递事件以由渲染器在游戏循环中处理。 GLSurfaceView有一个方法可以将一个runnable添加到名为queueEvent的渲染线程中。

然后在渲染器中,您拥有所有渲染的对象,您可以使用光线投射来检查是否已单击某个对象。

public SurfaceView(Context context, GLRenderer renderer) {
    super(context);

    setEGLContextClientVersion(2);
    setRenderer(renderer);

    setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if(event == null)
                return false;

            // set touch coordinates to be between -1 and 1 
            float normalizedX = ((event.getX()/v.getWidth())*2 - 1;
            float normalizedY = -((event.getY()/v.getHeight())*2 - 1);

            if (event.getAction() == MotionEvent.ACTION_UP){
               queueEvent(new Runnable() {
                   @Override
                   public void run() {
                       renderer.handleTouchUP(normalizedX,
                                              normalizedY);
                   }
                });
                return true;                          
            }
            return false;
        }
    });
}

答案 2 :(得分:1)

您要做的是检查您的触控是否在球体上。最直接的答案是制作穿过触摸位置的3D光线,并观察光线是否与球体碰撞,即Ray-Sphere碰撞。为此,您可以使用gluUnProject()。请记住,您需要使用此功能两次使用近和远平面点来获得3D近远矢量。此向量是用于检查碰撞的3D射线。

但在你的情况下,你有一个简单旋转的球体。中心是固定的,半径是已知的。因此,更简单的方法是在屏幕上找到适合球体的圆圈,并检查触摸是否在此圆圈内。

首先从你问题中链接的代码示例中获取球体的中心。因为您转换为(0,0,-10)即3D中心。 center3d(0.0f, 0.0f, -10.0f)。将其投影到屏幕上并获得一个屏幕中心。您可以使用gluProject()。让我们说这导致center2d。现在在球体表面上取另一个点,因为球体半径为2(来自您的代码链接),一个点可能是point3d(2.0f, 0.0f, -10.0f)。现在将其投影到屏幕上,让我们说你得到point2d。现在,球体在屏幕上的2D圆半径为length(point2D - center2D)

现在检查输入触摸是否在圆圈内。只需从圆的中心获取触摸位置的距离,然后检查其2D半径。对于您的情况,这是一种简单的方法,但如果您有更复杂的形状,光线投射是可行的方法。