Reagowanie na zdarzenia dotknięcia

Ruch obiektów zgodnie z gotowym programem, takim jak obracający się trójkąt, jest przydatny ale co w sytuacji, gdy użytkownik chce korzystać z grafiki OpenGL ES? Kluczem do tego, aby aplikacja OpenGL ES była interaktywna, jest rozszerzenie wdrożenia GLSurfaceView, aby zastąpić parametr onTouchEvent(), aby nasłuchiwać zdarzeń dotknięcia.

Z tej lekcji dowiesz się, jak nasłuchiwać zdarzeń dotknięcia, aby umożliwić użytkownikom obracanie obiektu OpenGL ES.

Skonfiguruj detektor dotyku

Aby aplikacja OpenGL ES reagowała na zdarzenia dotknięcia, musisz zaimplementować klucz Metoda onTouchEvent() w: GLSurfaceView zajęcia. Przykładowa implementacja poniżej pokazuje, jak nasłuchiwać MotionEvent.ACTION_MOVE zdarzeń i przetłumacz je na język kąt obrotu kształtu.

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;
}

Zwróć uwagę, że po obliczeniu kąta obrotu metoda ta wywołuje requestRender(), aby poinformować że nadszedł czas na wyrenderowanie klatki. W tym przykładzie to właśnie ta metoda sprawdza się najlepiej. ponieważ ramki nie trzeba ponownie rysować, chyba że obrót nastąpi zmiana. Jednak nie ma żadnego wpływu na wydajność, chyba że zażądasz również, aby mechanizm renderowania dane zmieniają się za pomocą funkcji setRenderMode() , więc upewnij się, że ten wiersz nie jest skomentowany w mechanizmie renderowania:

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

Pokaż kąt obrotu

Przykładowy kod powyżej wymaga udostępnienia kąta obrotu za pomocą mechanizmu renderowania dodanie członka publicznego. Ponieważ kod mechanizmu renderowania działa w osobnym wątku niż główny użytkownik wątku interfejsu Twojej aplikacji, musisz zadeklarować tę zmienną publiczną jako volatile. Oto kod do zadeklarowania zmiennej i udostępnienia pary metody pobierającej i ustawiającej:

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;
    }
}

Zastosuj rotację

Aby zastosować obrót wygenerowany przez sterowanie dotykowe, zmień w komentarz kod, który generuje kąt, a następnie dodaj zmienną, która zawiera kąt wygenerowany za pomocą dotyku:

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

Po wykonaniu powyższych czynności uruchom program i przeciągnij palcem po ekranie aby obrócić trójkąt:

Rysunek 1. Trójkąt obracający się po włączeniu sterowania dotykowego (koło pokazuje dotyk lokalizacja).