2016-12-27 124 views
6

在android我已經採取了旋轉球體的例子given here。它創建了一個顯示旋轉球體(地球)的簡單應用程序。如何檢測android中某個Renderer區域內的觸摸事件?

現在,我想要做的事情,如果在手機顯示屏上按下旋轉的球體。我不想對旋轉球體的以外的觸摸事件作出反應。以下是我迄今爲止嘗試,通過使用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); 
    } 

} 

沒有錯誤行此代碼的工作,當我按下顯示我得到的X/Y座標。

然而,爲了評估該事件是球,我的做法是讓它具有Sphere對象,以確定是否X/Y座標在範圍內的渲染器。

但錯誤行不行,我得到一個錯誤說

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

我怎樣才能解決這個錯誤;或者如果事件是在Sphere -graphics-object中,是否有更自理的方法來自動找出?

也許這是一個好主意,更改構造函數並將渲染器實例傳遞給MyGLSurfaceView以及?附錄:這個想法似乎不起作用。我得到一個構造函數的錯誤,我不明白...

回答

1

我認爲,如你所說,在構造函數中傳遞渲染器是個好主意。然後傳遞事件由遊戲循環中的渲染器處理。 GLSurfaceView有一個方法來向渲染線程添加一個名爲queueEvent的runnable。

然後在渲染器中,您擁有所有渲染對象,您可以使用光線投射來檢查是否有對象被點擊。

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; 
     } 
    }); 
} 
+0

感謝您的建議,但有一個小代碼示例,我認爲我完全失去了。 「射線投射」是什麼意思? – Alex

+0

我添加了SurfaceView代碼。 光線投射是一種檢查是否通過使用視圖矩陣創建從某個點(在此情況下從具有帳戶的相機到發生觸摸事件的位置)發出的光線來「擊中」對象的方法。然後檢查光線是否與任何物體相交。網上有很多在線教程。 – satm12

4

你的問題比檢測觸摸事件複雜得多。渲染器不僅具有球體對象,還包含整個OpenGL ES內容。因此,即使在檢測到觸摸事件後,您仍然需要將屏幕2D座標轉換爲3D射線,並檢查它是否與球體相交。這被稱爲射線鑄造Here是光線投射算法的一個很好的解釋。另外還有一個good video tutorial用於實現光線投射Java。

您也可以按照您和@ satm12的建議,在GLSurfaceView的構造函數中傳遞渲染器。

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。現在屏幕上球體的二維圓弧半徑爲length(point2D - center2D)

現在檢查輸入觸摸是否在圓圈內。只需從圓的中心獲取觸摸位置的距離,並檢查其2D半徑。這對於你的情況來說是一個簡單的方法,但如果你有更復雜的形狀,光線投射就是要走的路。