به رویدادهای لمسی پاسخ دهید

حرکت دادن اجسام بر اساس یک برنامه از پیش تعیین شده مانند مثلث چرخان برای جلب توجه مفید است، اما اگر بخواهید کاربران با گرافیک OpenGL ES شما تعامل داشته باشند، چه؟ کلید تعاملی کردن لمسی برنامه OpenGL ES شما این است که پیاده سازی GLSurfaceView را گسترش دهید تا onTouchEvent() را برای گوش دادن به رویدادهای لمسی لغو کنید.

این درس به شما نشان می‌دهد که چگونه به رویدادهای لمسی گوش دهید تا به کاربران اجازه دهید یک شی OpenGL ES را بچرخانند.

یک شنونده لمسی راه اندازی کنید

برای اینکه برنامه OpenGL ES شما به رویدادهای لمسی پاسخ دهد، باید متد onTouchEvent() در کلاس GLSurfaceView خود پیاده سازی کنید. اجرای مثال زیر نحوه گوش دادن به رویدادهای MotionEvent.ACTION_MOVE و ترجمه آنها را به زاویه چرخش برای یک شکل نشان می دهد.

کاتلین

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
}

جاوا

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

توجه داشته باشید که پس از محاسبه زاویه چرخش، این متد requestRender() را فراخوانی می کند تا به رندر کننده بگوید که زمان رندر کردن فریم است. این روش در این مثال کارآمدترین است زیرا فریم نیازی به ترسیم مجدد ندارد مگر اینکه تغییری در چرخش ایجاد شود. با این حال، هیچ تاثیری بر کارایی ندارد، مگر اینکه شما همچنین درخواست کنید که رندر تنها زمانی که داده ها با استفاده از متد setRenderMode() تغییر می کند، دوباره ترسیم کند، بنابراین مطمئن شوید که این خط در رندر بدون توضیح است:

کاتلین

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

جاوا

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

زاویه چرخش را در معرض دید قرار دهید

کد مثال بالا مستلزم آن است که زاویه چرخش را از طریق رندر خود با افزودن یک عضو عمومی در معرض دید قرار دهید. از آنجایی که کد رندر در یک رشته مجزا از رشته رابط کاربری اصلی برنامه شما اجرا می شود، باید این متغیر عمومی را به عنوان volatile اعلام کنید. در اینجا کدی برای اعلام متغیر و نمایش جفت گیرنده و تنظیم کننده وجود دارد:

کاتلین

class MyGLRenderer4 : GLSurfaceView.Renderer {

    @Volatile
    var angle: Float = 0f
}

جاوا

public class MyGLRenderer implements GLSurfaceView.Renderer {
    ...

    public volatile float mAngle;

    public float getAngle() {
        return mAngle;
    }

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

چرخش را اعمال کنید

برای اعمال چرخش ایجاد شده توسط ورودی لمسی، کدی که یک زاویه ایجاد می کند را نظر دهید و متغیری را اضافه کنید که حاوی زاویه ایجاد شده ورودی لمسی است:

کاتلین

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

جاوا

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

پس از انجام مراحل توضیح داده شده در بالا، برنامه را اجرا کنید و انگشت خود را روی صفحه بکشید تا مثلث بچرخد:

شکل 1. مثلثی که با ورودی لمسی می چرخد ​​(دایره مکان لمس را نشان می دهد).