Perangkap mouse di SDL

12

Bagaimana saya bisa menjebak mouse pengguna di dalam gim saya? Ini bukan game layar penuh, tapi saya menginginkannya agar pengguna tidak dapat menyeret mouse ke luar layar.

Apakah saya harus memeriksa koordinat mouse dan SDL_WarpCursor untuk membuatnya di dalam jendela (secara manual), atau apakah ada cara otomatis?

Terima kasih.

David Gomes
sumber
Sudahkah Anda mempertimbangkan menyembunyikan kursor dan membelokkannya kembali ke tengah? Kemudian, cukup gambar garis silang Anda di tengah layar menggantikan kursor OS.
Vaughan Hilts

Jawaban:

24

Meskipun Anda dapat menerapkan ini menggunakan SDL_WarpCursor (), saya mengalami masalah dengan metode itu pada beberapa platform. Saya punya masalah nyata dengan beberapa platform yang tidak dapat diandalkan melakukan aksi WarpCursor (), terutama ketika saya menyebutnya setiap frame.

Juga, ingat bahwa pada banyak platform, kursor ditangani pada frekuensi yang lebih tinggi daripada aplikasi Anda. Ini terutama benar jika Anda menjalankan di bawah 60fps! Jadi, bahkan jika platform berhasil membengkokkan mouse di setiap frame game Anda, kursor masih bisa menjauh dari jendela Anda jika ia menerima pembaruan di antara frame yang Anda render.

Metode yang benar untuk menjebak mouse di bawah SDL adalah:

SDL_WM_GrabInput( SDL_GRAB_ON );

Ini memberi tahu SDL bahwa niat Anda adalah untuk benar-benar mengambil kendali penuh atas keyboard + mouse (lihat dokumentasi ), dan untuk itu menjaga mouse tetap berada di dalam jendela tidak peduli apa pun yang terjadi. Mulai saat ini, mouse tidak akan bergerak di luar jendela, terlepas dari kecepatan bingkai Anda, dan Anda tidak boleh memanggil SDL_WarpCursor, kecuali jika Anda benar-benar berniat untuk memindahkan kursor ke suatu tempat, alih-alih mengirim spam secara terus-menerus.

Saat berada dalam mode "grabbing", Anda akan terus menerima aktivitas gerakan mouse seolah-olah mouse tidak dibatasi di dalam jendela. (Jadi, jika kursor berada di tepi kanan layar, dan pengguna menggerakkan mouse lebih jauh ke kanan, Anda akan menerima acara gerakan mouse yang menunjukkan gerakan ke kanan, meskipun posisi kursor tidak akan berubah). Ini sangat berguna untuk (misalnya) memutar kontrol untuk game FPS, di mana Anda hanya peduli pada gerakan relatif kursor, bukan posisi absolutnya.

Pembaruan untuk SDL2 - 9 Desember 2013

Antarmuka ini telah berubah untuk SDL2. Jika Anda menggunakan SDL1.2, jawaban di atas masih benar. Namun, di bawah SDL2 SDL_WM_GrabInput(SDL_GrabMode)fungsi tidak tersedia lagi Cara baru SDL2 untuk menangkap mouse adalah:

SDL_SetRelativeMouseMode(SDL_TRUE);

Jika tidak, ini identik dengan fungsi sebelumnya - dalam mode ini Anda akan terus menerima SDL_MOUSEMOTIONacara seolah-olah mouse tidak dibatasi di dalam jendela.

Trevor Powell
sumber
1
Peringatan: Saya perhatikan bahwa pada beberapa platform, saya segera menerima acara MouseMotion palsu dengan gerakan yang sangat besar, segera setelah menyalakan mouse. Untuk mengatasinya, saya meminta kode saya untuk mengabaikan aktivitas gerakan mouse pertama yang diterima setelah mengaktifkan mode ini.
Trevor Powell
Itu bekerja dengan sempurna, dan itu jauh lebih mudah daripada cara manual. Terima kasih!
David Gomes
3

Sementara jawaban Trevor yang diperbarui mencerminkan kondisi SDL2 saat ini, Anda juga dapat menjebak mouse dengan membuat Anda SDL_Windowmenggunakan SDL_WINDOW_INPUT_GRABBEDset. Perlu diketahui bahwa saya telah mengalami beberapa masalah aneh di Linux (mungkin karena beberapa kekhasan windowing X) di mana Anda tidak pernah dapat keluar dari jendela kecuali SDL_QUIT dipanggil (bahkan jika acara OS lain mencuri fokus).

Justin Skiles
sumber
Terima kasih, SDL_WINDOW_INPUT_GRABBED berfungsi dengan baik pada kode SDL2 saya.
Adrian Maire
3

Untuk SDL2 tampaknya juga ada fungsi SDL_SetWindowGrab jika Anda ingin mengaktifkan dan menonaktifkannya.

SDL_SetWindowGrab(SDL_Window* window, SDL_bool grabbed)
Michael Shaffer
sumber
2

Anda dapat menggunakan SDL Motion Event untuk mendeteksi kapan mouse bergerak. Kemudian, Anda dapat memanggil WarpCursor di dalamnya bahkan setelah menembakkan peristiwa untuk menyalurkan nilai relX dan relY. Anda juga dapat menyembunyikan kursor OS dan menggambar crosshair atau yang serupa di tengah layar. Ini memastikan bahwa mouse tampaknya selalu berada di tengah untuk pengguna dan Anda masih dapat menerima nilai untuk gerakan dan sejenisnya.

Vaughan Hilts
sumber