Penanganan sistem input keyboard

13

Catatan: Saya harus melakukan polling, daripada melakukan panggilan balik karena keterbatasan API (SFML). Saya juga minta maaf karena kurangnya judul yang 'layak'.

Saya pikir saya punya dua pertanyaan di sini; cara mendaftar input yang saya terima, dan apa yang harus dilakukan dengannya.

Menangani Input

Saya sedang berbicara tentang fakta bahwa Anda telah mendaftarkan bahwa tombol 'A' telah ditekan, misalnya, dan bagaimana melakukannya dari sana.

Saya telah melihat array seluruh keyboard, seperti:

bool keyboard[256]; //And each input loop check the state of every key on the keyboard

Tetapi ini tampaknya tidak efisien. Anda tidak hanya menyambungkan kunci 'A' ke 'pemain bergerak ke kiri', misalnya, tetapi memeriksa setiap kunci, 30-60 kali per detik.

Saya kemudian mencoba sistem lain yang hanya mencari kunci yang diinginkan.

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.

Namun, masalah dengan ini adalah saya sekarang tidak bisa mengetik nama, misalnya, tanpa harus mengikat setiap kunci.

Lalu, saya memiliki masalah kedua, yang saya tidak bisa memikirkan solusi yang baik untuk:

Mengirim Input

Saya sekarang tahu bahwa tombol A telah ditekan atau bahwa playerLeft benar. Tetapi bagaimana saya pergi dari sini?

Saya berpikir untuk mengecek if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
input pasangan ini sangat ke entitas, dan saya merasa agak berantakan. Saya lebih suka pemain untuk menangani gerakannya sendiri ketika diperbarui. Saya pikir beberapa jenis sistem acara bisa berfungsi, tetapi saya tidak tahu bagaimana caranya. (Saya mendengar sinyal dan slot bagus untuk pekerjaan semacam ini, tetapi tampaknya sangat lambat dan saya tidak bisa melihat bagaimana itu cocok).

Terima kasih.

Bebek Komunis
sumber

Jawaban:

7

Apa yang akan saya lakukan adalah menggunakan pola pengamat dan memiliki kelas input yang memelihara daftar panggilan balik atau objek penanganan input. Objek lain dapat mendaftarkan diri dengan sistem input untuk diberi tahu ketika hal-hal tertentu terjadi. Ada berbagai jenis panggilan balik yang bisa Anda daftarkan, berdasarkan pada jenis acara yang ingin diberitahukan oleh pengamat. Level ini bisa serendah 'kunci x sedang turun / naik' atau lebih spesifik game seperti 'peristiwa melompat / menembak / pergerakan terjadi'.

Secara umum objek permainan memiliki komponen penanganan input yang bertanggung jawab untuk mendaftarkan dirinya dengan kelas input dan menyediakan metode untuk menangani peristiwa-peristiwa yang diminati. Untuk pergerakan, saya memiliki komponen penggerak input yang memiliki metode move (x, y). Ini mendaftar sendiri dengan sistem input dan mendapat pemberitahuan tentang peristiwa pergerakan (di mana x dan y akan menjadi -1 dan 0 untuk menandakan bergerak ke kiri), komponen penggerak kemudian mengubah koordinat objek permainan induknya berdasarkan arah gerakan dan kecepatan objek.

Saya tidak tahu apakah ini solusi yang baik tetapi sejauh ini berhasil untuk saya. Khususnya itu memungkinkan saya untuk menyediakan berbagai jenis sistem input yang memetakan ke peristiwa permainan logis yang sama sehingga tombol gamepad x dan ruang keyboard keduanya menghasilkan acara lompatan misalnya (itu sedikit lebih rumit dari itu, memungkinkan pengguna untuk menetapkan kembali kunci pemetaan).

Firas Assaad
sumber
Ini pasti menarik minat saya; apakah komponen input mendaftar sendiri untuk acara-acara tertentu (seperti playerInput mendaftar 'kiri', 'kanan', dll) atau akankah setiap komponen input yang terdaftar menerima semua pesan?
Bebek Komunis
Itu sangat tergantung pada kebutuhan Anda dan bagaimana Anda ingin menerapkannya. Dalam kasus saya, pendengar mendaftarkan diri untuk acara tertentu dan mengimplementasikan antarmuka input handler yang sesuai. Agar setiap komponen input menerima semua pesan harus berfungsi, tetapi format pesan harus lebih umum daripada yang saya miliki.
Firas Assaad
6

Saya pikir diskusi OP menyatukan banyak hal, dan masalahnya dapat disederhanakan secara substansial dengan memecahnya sedikit.

Saran saya:

Pertahankan susunan status kunci Anda. Apakah tidak ada panggilan API untuk mendapatkan seluruh kondisi keyboard sekaligus? (Sebagian besar pekerjaan saya adalah pada konsol, dan bahkan pada Windows untuk pengontrol yang terhubung Anda mendapatkan seluruh status pengontrol sekaligus.) Keadaan kunci Anda adalah peta "keras" pada tombol-tombol keyboard. Tidak diterjemahkan adalah yang terbaik, tetapi bagaimanapun Anda membuatnya termudah keluar dari API.

Kemudian simpan beberapa array paralel yang menunjukkan apakah kunci naik bingkai ini, yang lain menunjukkan bahwa itu turun, dan yang ketiga menunjukkan hanya bahwa kunci itu "turun". Mungkin melempar timer sehingga Anda dapat melacak berapa lama kunci telah dalam kondisi saat ini.

Selanjutnya buat metode untuk membuat pemetaan kunci untuk tindakan. Anda akan ingin melakukan ini beberapa kali. Satu kali untuk hal-hal UI (dan berhati-hatilah untuk menanyakan pemetaan Windows karena Anda tidak dapat menganggap scancode ketika Anda menekan 'A' akan memberikan nilai A pada komputer pengguna). Lain untuk setiap "mode" dalam game. Ini adalah pemetaan kode kunci untuk tindakan. Anda dapat melakukan ini dengan beberapa cara, satu untuk menjaga enum yang digunakan oleh sistem penerima, yang lain akan menjadi penunjuk fungsi yang menunjukkan fungsi yang akan dipanggil pada perubahan keadaan. Mungkin bahkan hibrida dari keduanya, tergantung pada tujuan dan kebutuhan Anda. Dengan "mode" ini, Anda dapat mendorong dan memasukkannya ke tumpukan mode pengontrol, dengan tanda yang memungkinkan input yang diabaikan untuk terus turun ke tumpukan atau apa pun.

Akhirnya, tangani tindakan-tindakan kunci itu entah bagaimana. Untuk gerakan, Anda mungkin ingin melakukan sesuatu yang rumit, menerjemahkan 'W' ke bawah berarti "bergerak maju," tetapi itu tidak perlu menjadi solusi biner; Anda dapat memiliki "W is down" berarti "meningkatkan kecepatan dengan X sampai maksimum Y," dan "W is up" menjadi "menurunkan kecepatan oleh Z sampai menyentuh nol." Secara umum - Anda ingin "antarmuka penanganan pengontrol dalam sistem permainan" Anda menjadi sangat sempit; lakukan semua terjemahan kunci di satu tempat dan kemudian gunakan hasil itu di tempat lain. Ini berbeda dengan memeriksa secara langsung untuk melihat apakah bilah spasi ditekan di sembarang tempat dalam kode, karena jika itu di beberapa tempat acak mungkin akan terkena pada waktu acak ketika Anda tidak menginginkannya, dan Anda tidak Aku tidak mau berurusan dengan itu ...

Saya benar-benar benci merancang pola dan saya pikir komponen membawa lebih banyak biaya pengembangan daripada yang baik, jadi itu sebabnya saya tidak menyebutkan keduanya. Pola akan muncul jika ditakdirkan untuk, seperti halnya komponen, tetapi berangkat untuk melakukan keduanya sejak awal hanya akan mempersulit hidup Anda.

dash-tom-bang
sumber
Tidakkah Anda pikir itu agak kotor untuk mengikat acara ke bingkai grafik? Saya pikir itu harus dipisahkan.
Jo So
Maksudku, saya mendapatkan bahwa dalam hampir semua kasus pemain akan lebih lambat untuk memasukkan tombol daripada kartu grafis akan memancarkan bingkai, tetapi sebenarnya mereka harus independen, dan sebenarnya mereka untuk jenis acara lainnya, seperti yang dikumpulkan diambil dari jaringan .
Jo So
Memang; tidak ada alasan mengapa polling keyboard (atau perangkat input lainnya) tidak dapat dijalankan pada tingkat yang berbeda dari tampilan. Memang, jika Anda polling input pada 100Hz maka Anda dapat memberikan pengalaman kontrol pengguna yang benar-benar konsisten terlepas dari frekuensi pembaruan perangkat keras video. Anda harus menjadi sedikit lebih pintar tentang bagaimana Anda menangani data Anda (tentang mengunci dll.) Tetapi itu akan membuat hal-hal seperti gerakan lebih mudah untuk membuat konsisten.
dash-tom-bang
3

Di SFML, Anda memiliki tombol secara berurutan sesuai dengan jenis peristiwa KeyPressed. Anda memproses setiap kunci dalam beberapa saat (getNextEvent ()).

Jadi jika tombol yang ditekan ada di peta Key-> Action Anda, jalankan tindakan yang sesuai, dan jika tidak, teruskan ke widget / hal-hal yang mungkin membutuhkannya.

Mengenai pertanyaan kedua Anda, saya sarankan Anda untuk tetap seperti ini karena membuatnya lebih mudah untuk mengubah gameplay Anda. Jika Anda menggunakan sinyal atau semacamnya, Anda harus membuat slot untuk "RunKeyDown" dan yang lainnya untuk "JumpKeySlot". Tetapi apa yang terjadi jika dalam gim Anda, tindakan khusus dilakukan ketika keduanya ditekan?

Jika Anda ingin menghubungkan input dan entitas, Anda dapat menjadikan input Anda sebagai Status (RunKey = true, FireKey = false, ...) dan mengirimkannya ke pemain seperti Anda mengirim acara lain ke AI Anda.

Calvin1602
sumber
Saya tidak menangani acara keyboard dengan sf :: Event, melainkan sf :: Input, karena ini adalah deteksi real-time IIRC. Saya mencoba menjaganya sebagai API-agnostik mungkin. : P (Pertanyaannya, yaitu)
Bebek Komunis
1
Tapi saya pikir poin Calvin1602 adalah bahwa pernyataan asli Anda dalam pertanyaan "Saya harus polling, daripada melakukan panggilan balik karena keterbatasan API (SFML)" tidak benar; Anda memiliki acara, sehingga Anda dapat mengeluarkan panggilan balik saat Anda menangani suatu acara.
Kylotan
3

Solusi yang tepat seringkali merupakan kombinasi dari dua metode yang Anda diskusikan:

Untuk fungsionalitas gameplay dengan seperangkat tombol yang telah ditentukan, polling setiap frame benar-benar tepat dan Anda hanya harus polling untuk kunci yang benar-benar terikat pada sesuatu. Ini sebenarnya analog dengan bagaimana Anda akan meminta input controller dalam game konsol, itu akan sepenuhnya polling terutama ketika datang ke perangkat input analog. Selama bermain game umum, Anda mungkin ingin mengabaikan acara penekanan tombol dan cukup gunakan polling.

Saat mengetik input untuk hal-hal seperti nama, Anda harus mengalihkan game ke mode penanganan input yang berbeda. Misalnya, segera setelah prompt "masukkan nama Anda" muncul, Anda dapat mengubah apa yang Anda lakukan dengan kode input. Itu bisa mendengarkan acara pers kunci melalui beberapa antarmuka panggilan balik, atau Anda dapat mulai polling untuk setiap tombol jika diperlukan. Ternyata biasanya selama acara mengetik Anda tidak terlalu peduli dengan kinerja, jadi pemungutan suara tidak akan seburuk itu.

Jadi, Anda ingin menggunakan polling selektif untuk input gameplay, dan penanganan event untuk input mengetik nama (atau semua polling keyboard jika penanganan event tidak tersedia).

Ben Zeigler
sumber