在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:这个想法似乎不起作用。我得到一个构造函数错误,我不明白...
答案 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半径。对于您的情况,这是一种简单的方法,但如果您有更复杂的形状,光线投射是可行的方法。