Cara yang benar untuk abstrak Kontroler XBox

12

Saya punya pengontrol XBox360 yang ingin saya gunakan sebagai input untuk suatu aplikasi.

Apa yang tidak bisa saya lakukan adalah cara praktik terbaik untuk mengekspos ini melalui antarmuka.

Di belakang layar, kelas yang menangani pengontrol bergantung pada status tombol polling.

Saya awalnya mencoba sesuatu tautan:

Event ButtonPressed() as ButtonEnum

mana ButtonEnumitu ButtonRed, ButtonStart, dll ...

Ini sedikit terbatas karena hanya mendukung penekanan tombol, tidak menahan / pola (tekan dua kali, dll.)

Gagasan berikutnya adalah dengan hanya mengekspos keadaan tombol ke aplikasi misalnya

Property RedPressed as Boolean
Property StartPressed as Boolean
Property Thumb1XAxis as Double

Ini sangat fleksibel tetapi benar-benar memaksa terlalu banyak pekerjaan ke dalam aplikasi dan membutuhkan aplikasi untuk polling - Saya lebih suka event driven jika memungkinkan.

Saya mempertimbangkan untuk menambahkan beberapa acara, misalnya:

Event ButtonPressed(Button as ButtonEnum)
Event ButtonPressedTwice(Button as ButtonEnum)
Event ButtonHeldStart(Button as ButtonEnum)
Event ButtonHeldEnd(Button as ButtonEnum)

tapi ini agak kikuk dan terasa sangat menyakitkan di layar "Bind button".

Dapatkah seseorang tolong tunjukkan saya di "benar" cara untuk menangani input dari pengontrol.

NB: Saya menggunakan SlimDX di dalam kelas yang mengimplementasikan antarmuka. Ini memungkinkan saya untuk membaca status dengan sangat mudah. Setiap alternatif yang akan menyelesaikan masalah saya juga dihargai

Dasar
sumber

Jawaban:

21

Tidak ada satu pemetaan sempurna yang memberi Anda abstraksi platform spesifik, karena jelas sebagian besar pengidentifikasi yang masuk akal untuk pengontrol 360 salah untuk pengontrol PlayStation (A bukannya X, B, bukan Circle). Dan tentu saja pengontrol Wii adalah hal lain sama sekali.

Cara paling efektif yang saya temukan untuk mengatasinya adalah dengan menggunakan tiga lapis implementasi. Lapisan bawah sepenuhnya platform / controller khusus, dan tahu berapa banyak tombol digital dan sumbu analog yang tersedia. Lapisan inilah yang tahu cara melakukan polling pada kondisi perangkat keras, dan lapisan inilah yang mengingat kondisi sebelumnya dengan cukup baik sehingga mengetahui kapan tombol baru saja ditekan, atau apakah itu telah turun selama lebih dari satu centang, atau apakah itu tidak ditekan . Selain itu bodoh - kelas negara murni yang mewakili satu jenis pengontrol. Nilai sebenarnya adalah untuk abstrak seluk-beluk kueri keadaan controller jauh dari lapisan tengah.

Lapisan tengah adalah pemetaan kontrol aktual dari tombol nyata ke konsep game (misalnya A -> Jump). Kami menyebutnya impuls bukan tombol, karena mereka tidak lagi terikat pada jenis pengontrol tertentu. Ini pada lapisan ini Anda dapat memetakan kembali kontrol (baik selama pengembangan atau saat runtime atas perintah pengguna). Setiap platform memiliki pemetaan kontrolnya sendiri untuk impuls virtual . Anda tidak dapat dan tidak boleh mencoba untuk menjauh dari ini. Setiap pengontrol unik, dan membutuhkan pemetaannya sendiri. Tombol dapat memetakan ke lebih dari satu impuls (tergantung pada mode permainan), dan lebih dari satu tombol dapat memetakan ke impuls yang sama (misalnya A dan X keduanya berakselerasi, B dan Y keduanya melambat). Pemetaan mendefinisikan semua itu,

Lapisan atas adalah lapisan permainan. Dibutuhkan impuls, dan tidak peduli bagaimana mereka dihasilkan. Mungkin mereka datang dari pengontrol, atau rekaman pengontrol, atau mungkin mereka datang dari AI. Pada level ini, Anda tidak peduli. Apa yang Anda pedulikan adalah bahwa ada dorongan Lompat baru, atau bahwa dorongan Percepat telah berlanjut, atau bahwa dorongan Selam memiliki nilai 0,35 centang ini.

Dengan sistem semacam ini, Anda menulis lapisan bawah satu kali untuk setiap pengontrol. Lapisan atas adalah platform independen. Kode untuk lapisan tengah hanya perlu ditulis satu kali, tetapi data (remapping) perlu diulang untuk setiap platform / pengontrol.

MrCranky
sumber
Ini sepertinya pendekatan yang sangat bersih dan elegan. Terima kasih!
Dasar
1
Sangat bagus. Jauh lebih baik daripada milik saya: P
Jordaan Mylonas
3
Abstraksi yang sangat bagus. Tapi hati-hati saat mengimplementasikan: jangan membuat dan menghancurkan objek impuls baru untuk setiap tindakan pengguna. Gunakan pooling. Pengumpul sampah akan berterima kasih.
grega g
Benar. Array statis berukuran hingga jumlah maksimal impuls simultan hampir selalu merupakan pilihan terbaik; karena hampir selalu Anda hanya menginginkan satu instance dari setiap impuls aktif pada satu waktu. Paling sering array itu hanya memiliki beberapa item di dalamnya, jadi cepat untuk beralih.
MrCranky
@Grega, terima kasih kalian berdua - aku tidak memikirkan itu.
Dasar
1

Jujur, menurut saya antarmuka yang optimal akan sangat bergantung pada penggunaan dalam game. Namun, untuk skenario penggunaan umum, saya akan menyarankan arsitektur dua tingkat yang memisahkan pendekatan berbasis peristiwa dan polling.

Tingkat lebih rendah dapat dianggap tingkat "berdasarkan polling", dan memperlihatkan keadaan tombol saat ini. Satu antarmuka seperti itu hanya dapat memiliki 2 fungsi, GetAnalogState(InputIdentifier)dan di GetDigitalState(InputIdentifier)mana InputIdentifiernilai yang disebutkan mewakili tombol, pemicu atau tongkat mana yang Anda periksa. (Menjalankan GetAnalogState untuk sebuah tombol akan mengembalikan 1.0 atau 0.0, dan menjalankan GetDigitalState untuk stik analog akan mengembalikan true jika melewati ambang preset, atau false jika tidak).

Tingkat kedua kemudian akan menggunakan tingkat yang lebih rendah untuk menghasilkan peristiwa setelah perubahan keadaan, dan memungkinkan elemen mendaftar untuk panggilan balik (C # Acara sangat mulia). Callback ini akan mencakup acara untuk pers, rilis, ketuk, longhold, dll. Untuk tongkat analog, Anda dapat memasukkan gerakan, misalnya QCF untuk game pertempuran. Jumlah acara yang terbuka tergantung pada seberapa detail acara yang ingin Anda kirim. Anda bisa saja menembakkan yang sederhana ButtonStateChanged(InputIdentifier)jika Anda ingin menangani yang lainnya dalam logika yang terpisah.

Jadi, jika Anda perlu memeriksa keadaan tombol input atau tongkat kontrol saat ini, periksa tingkat bawah. Jika Anda hanya ingin mematikan fungsi pada acara masukan, daftar panggilan balik dari tingkat kedua.

Jordaan Mylonas
sumber