Auf Touch-Ereignisse reagieren

Objekte gemäß einem voreingestellten Programm wie dem rotierenden Dreieck bewegen zu können, ist nützlich, um Aufmerksamkeit zu erregen. Aber was ist, wenn Nutzer mit Ihrer OpenGL ES-Grafik interagieren sollen? Wenn du deine OpenGL ES-App interaktiv gestalten möchtest, musst du deine Implementierung von GLSurfaceView erweitern, damit onTouchEvent() überschrieben wird, um Touch-Ereignisse zu erfassen.

In dieser Lektion erfahren Sie, wie Sie auf Touch-Ereignisse warten, damit Nutzer ein OpenGL ES-Objekt drehen können.

Touch-Listener einrichten

Damit Ihre OpenGL ES-Anwendung auf Touch-Ereignisse reagiert, müssen Sie die Methode onTouchEvent() in Ihrer GLSurfaceView-Klasse implementieren. Die folgende Beispielimplementierung zeigt, wie auf MotionEvent.ACTION_MOVE-Ereignisse gewartet und diese in einen Drehwinkel einer Form übersetzt werden.

Kotlin

private const val TOUCH_SCALE_FACTOR: Float = 180.0f / 320f
...
private var previousX: Float = 0f
private var previousY: Float = 0f

override fun onTouchEvent(e: MotionEvent): Boolean {
    // MotionEvent reports input details from the touch screen
    // and other input controls. In this case, you are only
    // interested in events where the touch position changed.

    val x: Float = e.x
    val y: Float = e.y

    when (e.action) {
        MotionEvent.ACTION_MOVE -> {

            var dx: Float = x - previousX
            var dy: Float = y - previousY

            // reverse direction of rotation above the mid-line
            if (y > height / 2) {
                dx *= -1
            }

            // reverse direction of rotation to left of the mid-line
            if (x < width / 2) {
                dy *= -1
            }

            renderer.angle += (dx + dy) * TOUCH_SCALE_FACTOR
            requestRender()
        }
    }

    previousX = x
    previousY = y
    return true
}

Java

private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
private float previousX;
private float previousY;

@Override
public boolean onTouchEvent(MotionEvent e) {
    // MotionEvent reports input details from the touch screen
    // and other input controls. In this case, you are only
    // interested in events where the touch position changed.

    float x = e.getX();
    float y = e.getY();

    switch (e.getAction()) {
        case MotionEvent.ACTION_MOVE:

            float dx = x - previousX;
            float dy = y - previousY;

            // reverse direction of rotation above the mid-line
            if (y > getHeight() / 2) {
              dx = dx * -1 ;
            }

            // reverse direction of rotation to left of the mid-line
            if (x < getWidth() / 2) {
              dy = dy * -1 ;
            }

            renderer.setAngle(
                    renderer.getAngle() +
                    ((dx + dy) * TOUCH_SCALE_FACTOR));
            requestRender();
    }

    previousX = x;
    previousY = y;
    return true;
}

Nach der Berechnung des Drehwinkels ruft diese Methode requestRender() auf, um dem Renderer mitzuteilen, dass es Zeit ist, den Frame zu rendern. Dieser Ansatz ist in diesem Beispiel die effizienteste, da der Frame nur neu gezeichnet werden muss, wenn sich die Rotation ändert. Dies wirkt sich jedoch nicht auf die Effizienz aus, es sei denn, Sie legen fest, dass der Renderer nur neu zeichnen soll, wenn sich die Daten mit der Methode setRenderMode() ändern. Achten Sie also darauf, dass diese Zeile im Renderer nicht als Kommentar gekennzeichnet ist:

Kotlin

class MyGlSurfaceView(context: Context) : GLSurfaceView(context) {

    init {
        // Render the view only when there is a change in the drawing data
        renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    }
}

Java

public MyGLSurfaceView(Context context) {
    ...
    // Render the view only when there is a change in the drawing data
    setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}

Drehwinkel angeben

Für den obigen Beispielcode müssen Sie den Drehwinkel durch den Renderer freigeben, indem Sie ein öffentliches Mitglied hinzufügen. Da der Renderer-Code in einem anderen Thread als dem Hauptthread der Benutzeroberfläche Ihrer Anwendung ausgeführt wird, müssen Sie diese öffentliche Variable als volatile deklarieren. Mit dem folgenden Code wird die Variable deklariert und das Getter- und Setter-Paar wird verfügbar gemacht:

Kotlin

class MyGLRenderer4 : GLSurfaceView.Renderer {

    @Volatile
    var angle: Float = 0f
}

Java

public class MyGLRenderer implements GLSurfaceView.Renderer {
    ...

    public volatile float mAngle;

    public float getAngle() {
        return mAngle;
    }

    public void setAngle(float angle) {
        mAngle = angle;
    }
}

Rotation anwenden

Um die durch die Berührungseingabe generierte Rotation anzuwenden, kommentieren Sie den Code aus, der einen Winkel generiert, und fügen Sie eine Variable hinzu, die den durch Berührung erzeugten Winkel enthält:

Kotlin

override fun onDrawFrame(gl: GL10) {
    ...
    val scratch = FloatArray(16)

    // Create a rotation for the triangle
    // long time = SystemClock.uptimeMillis() % 4000L;
    // float angle = 0.090f * ((int) time);
    Matrix.setRotateM(rotationMatrix, 0, angle, 0f, 0f, -1.0f)

    // Combine the rotation matrix with the projection and camera view
    // Note that the mvpMatrix factor *must be first* in order
    // for the matrix multiplication product to be correct.
    Matrix.multiplyMM(scratch, 0, mvpMatrix, 0, rotationMatrix, 0)

    // Draw triangle
    triangle.draw(scratch)
}

Java

public void onDrawFrame(GL10 gl) {
    ...
    float[] scratch = new float[16];

    // Create a rotation for the triangle
    // long time = SystemClock.uptimeMillis() % 4000L;
    // float angle = 0.090f * ((int) time);
    Matrix.setRotateM(rotationMatrix, 0, mAngle, 0, 0, -1.0f);

    // Combine the rotation matrix with the projection and camera view
    // Note that the vPMatrix factor *must be first* in order
    // for the matrix multiplication product to be correct.
    Matrix.multiplyMM(scratch, 0, vPMatrix, 0, rotationMatrix, 0);

    // Draw triangle
    mTriangle.draw(scratch);
}

Wenn Sie die oben beschriebenen Schritte ausgeführt haben, führen Sie das Programm aus und ziehen Sie Ihren Finger über den Bildschirm, um das Dreieck zu drehen:

Abbildung 1: Dreieck, das mit Berührung gedreht wird (Kreis zeigt die Berührungsposition)