Pengontrol permainan mentah
Halaman ini menjelaskan dasar-dasar pemrograman untuk hampir semua jenis pengontrol game menggunakan Windows.Gaming.Input.RawGameController dan API terkait untuk Platform Windows Universal (UWP).
Dengan membaca halaman ini, Anda akan mempelajari:
- cara mengumpulkan daftar pengontrol game mentah yang terhubung dan penggunanya
- cara mendeteksi bahwa pengontrol permainan mentah telah ditambahkan atau dihapus
- cara mendapatkan kemampuan pengontrol game mentah
- cara membaca input dari pengontrol permainan mentah
Gambaran Umum
Pengontrol game mentah adalah representasi umum dari pengontrol game, dengan input yang ditemukan pada berbagai jenis pengontrol permainan umum. Input ini diekspos sebagai array sederhana dari tombol, sakelar, dan sumbu yang tidak disebutkan namanya. Dengan menggunakan pengontrol game mentah, Anda dapat memungkinkan pelanggan untuk membuat pemetaan input kustom apa pun jenis pengontrol yang mereka gunakan.
Kelas RawGameController benar-benar dimaksudkan untuk skenario ketika kelas input lainnya (ArcadeStick, FlightStick, dan sebagainya) tidak memenuhi kebutuhan Anda—jika Anda menginginkan sesuatu yang lebih umum, mengantisipasi bahwa pelanggan akan menggunakan berbagai jenis pengontrol game, maka kelas ini adalah untuk Anda.
Mendeteksi dan melacak pengontrol game mentah
Mendeteksi dan melacak pengontrol game mentah bekerja dengan cara yang sama persis seperti untuk gamepad, kecuali dengan kelas RawGameController alih-alih kelas Gamepad . Lihat Gamepad dan getaran untuk informasi selengkapnya.
Mendapatkan kemampuan pengontrol game mentah
Setelah mengidentifikasi pengontrol game mentah yang Anda minati, Anda dapat mengumpulkan informasi tentang kemampuan pengontrol. Anda bisa mendapatkan jumlah tombol pada pengontrol game mentah dengan RawGameController.ButtonCount, jumlah sumbu analog dengan RawGameController.AxisCount, dan jumlah sakelar dengan RawGameController.SwitchCount. Selain itu, Anda bisa mendapatkan jenis sakelar menggunakan RawGameController.GetSwitchKind.
Contoh berikut mendapatkan jumlah input pengontrol game mentah:
auto rawGameController = myRawGameControllers->GetAt(0);
int buttonCount = rawGameController->ButtonCount;
int axisCount = rawGameController->AxisCount;
int switchCount = rawGameController->SwitchCount;
Contoh berikut menentukan jenis setiap sakelar:
for (uint32_t i = 0; i < switchCount; i++)
{
GameControllerSwitchKind mySwitch = rawGameController->GetSwitchKind(i);
}
Membaca pengontrol permainan mentah
Setelah Anda mengetahui jumlah input pada pengontrol game mentah, Anda siap untuk mengumpulkan input darinya. Namun, tidak seperti beberapa jenis input lain yang mungkin biasa Anda gunakan, pengontrol game mentah tidak berkomunikasi perubahan status dengan meningkatkan peristiwa. Sebagai gantinya, Anda mengambil pembacaan rutin tentang statusnya saat ini dengan melakukan polling .
Polling pengontrol permainan mentah
Polling menangkap rekam jepret pengontrol game mentah pada titik waktu yang tepat. Pendekatan pengumpulan input ini cocok untuk sebagian besar game karena logika mereka biasanya berjalan dalam perulangan deterministik daripada digerakkan oleh peristiwa. Biasanya juga lebih mudah untuk menginterpretasikan perintah game dari input yang dikumpulkan sekaligus daripada dari banyak input tunggal yang dikumpulkan dari waktu ke waktu.
Anda melakukan polling pengontrol game mentah dengan memanggil RawGameController.GetCurrentReading. Fungsi ini mengisi array untuk tombol, sakelar, dan sumbu yang berisi status pengontrol permainan mentah.
Contoh berikut melakukan polling pengontrol permainan mentah untuk statusnya saat ini:
Platform::Array<bool>^ currentButtonReading =
ref new Platform::Array<bool>(buttonCount);
Platform::Array<GameControllerSwitchPosition>^ currentSwitchReading =
ref new Platform::Array<GameControllerSwitchPosition>(switchCount);
Platform::Array<double>^ currentAxisReading = ref new Platform::Array<double>(axisCount);
rawGameController->GetCurrentReading(
currentButtonReading,
currentSwitchReading,
currentAxisReading);
Tidak ada jaminan posisi mana di setiap array yang akan menyimpan nilai input mana di antara berbagai jenis pengontrol, jadi Anda harus memeriksa input mana yang menggunakan metode RawGameController.GetButtonLabel dan RawGameController.GetSwitchKind.
GetButtonLabel akan memberi tahu Anda teks atau simbol yang dicetak pada tombol fisik, daripada fungsi tombol —oleh karena itu, sebaiknya digunakan sebagai bantuan untuk UI untuk kasus di mana Anda ingin memberikan petunjuk pemutar tentang tombol mana yang melakukan fungsi mana. GetSwitchKind akan memberi tahu Anda jenis sakelar (yaitu, berapa banyak posisi yang dimilikinya), tetapi bukan nama.
Tidak ada cara standar untuk mendapatkan label sumbu atau sakelar, jadi Anda harus mengujinya sendiri untuk menentukan input mana yang mana.
Jika Anda memiliki pengontrol tertentu yang ingin Anda dukung, Anda bisa mendapatkan RawGameController.HardwareProductId dan RawGameController.HardwareVendorId dan memeriksa apakah mereka cocok dengan pengontrol tersebut. Posisi setiap input di setiap array sama untuk setiap pengontrol dengan HardwareProductId dan HardwareVendorId yang sama, sehingga Anda tidak perlu khawatir tentang logika Anda yang berpotensi tidak konsisten di antara pengontrol yang berbeda dengan jenis yang sama.
Selain status pengontrol game mentah, setiap pembacaan mengembalikan tanda waktu yang menunjukkan dengan tepat ketika status diambil. Tanda waktu berguna untuk berkaitan dengan waktu pembacaan sebelumnya atau waktu simulasi permainan.
Membaca tombol dan sakelar
Setiap tombol pengontrol game mentah menyediakan pembacaan digital yang menunjukkan apakah tombol ditekan (turun) atau dilepaskan (naik). Pembacaan tombol direpresentasikan sebagai nilai Boolean individual dalam satu array. Label untuk setiap tombol dapat ditemukan menggunakan RawGameController.GetButtonLabel dengan indeks nilai Boolean dalam array. Setiap nilai direpresentasikan sebagai GameControllerButtonLabel.
Contoh berikut menentukan apakah tombol XboxA ditekan:
for (uint32_t i = 0; i < buttonCount; i++)
{
if (currentButtonReading[i])
{
GameControllerButtonLabel buttonLabel = rawGameController->GetButtonLabel(i);
if (buttonLabel == GameControllerButtonLabel::XboxA)
{
// XboxA is pressed.
}
}
}
Terkadang Anda mungkin ingin menentukan kapan tombol beralih dari ditekan untuk dilepaskan atau dilepaskan untuk ditekan, apakah beberapa tombol ditekan atau dilepaskan, atau jika satu set tombol disusun dengan cara tertentu—beberapa ditekan, beberapa tidak. Untuk informasi tentang cara mendeteksi setiap kondisi ini, lihat Mendeteksi transisi tombol dan Mendeteksi pengaturan tombol yang kompleks.
Nilai switch disediakan sebagai array GameControllerSwitchPosition. Karena properti ini adalah ladang bit, masking bitwise digunakan untuk mengisolasi arah sakelar.
Contoh berikut menentukan apakah setiap sakelar berada di posisi atas:
for (uint32_t i = 0; i < switchCount; i++)
{
if (GameControllerSwitchPosition::Up ==
(currentSwitchReading[i] & GameControllerSwitchPosition::Up))
{
// The switch is in the up position.
}
}
Membaca input analog (tongkat, pemicu, pembatasan, dan sebagainya)
Sumbu analog menyediakan pembacaan antara 0,0 dan 1,0. Ini termasuk setiap dimensi pada tongkat seperti X dan Y untuk tongkat standar atau bahkan sumbu X, Y, dan Z (roll, pitch, dan yaw, masing-masing) untuk tongkat penerbangan.
Nilai dapat mewakili pemicu analog, pembatasan, atau jenis input analog lainnya. Nilai-nilai ini tidak disediakan dengan label, jadi kami sarankan kode Anda diuji dengan berbagai perangkat input untuk memastikan bahwa nilai tersebut cocok dengan asumsi Anda dengan benar.
Di semua sumbu, nilainya sekitar 0,5 untuk tongkat ketika berada di posisi tengah, tetapi normal bagi nilai yang tepat untuk bervariasi, bahkan antara pembacaan berikutnya; strategi untuk mengurangi variasi ini dibahas nanti di bagian ini.
Contoh berikut menunjukkan cara membaca nilai analog dari pengontrol Xbox:
// Xbox controllers have 6 axes: 2 for each stick and one for each trigger.
float leftStickX = currentAxisReading[0];
float leftStickY = currentAxisReading[1];
float rightStickX = currentAxisReading[2];
float rightStickY = currentAxisReading[3];
float leftTrigger = currentAxisReading[4];
float rightTrigger = currentAxisReading[5];
Saat membaca nilai tongkat, Anda akan melihat bahwa nilai tersebut tidak menghasilkan pembacaan netral 0,5 saat tidak aktif di posisi tengah; sebaliknya, mereka akan menghasilkan nilai yang berbeda mendekati 0,5 setiap kali tongkat dipindahkan dan dikembalikan ke posisi tengah. Untuk mengurangi variasi ini, Anda dapat menerapkan deadzone kecil, yang merupakan rentang nilai di dekat posisi pusat ideal yang diabaikan.
Salah satu cara untuk menerapkan deadzone adalah dengan menentukan seberapa jauh tongkat telah bergerak dari tengah, dan mengabaikan pembacaan yang lebih dekat dari beberapa jarak yang Anda pilih. Anda dapat menghitung jarak secara kasar—itu tidak tepat karena pembacaan tongkat pada dasarnya polar, bukan planar, nilai—hanya dengan menggunakan teori Pythagorean. Ini menghasilkan deadzone radial.
Contoh berikut menunjukkan deadzone radial dasar menggunakan teori Pythagorean:
// Choose a deadzone. Readings inside this radius are ignored.
const float deadzoneRadius = 0.1f;
const float deadzoneSquared = deadzoneRadius * deadzoneRadius;
// Pythagorean theorem: For a right triangle, hypotenuse^2 = (opposite side)^2 + (adjacent side)^2
float oppositeSquared = leftStickY * leftStickY;
float adjacentSquared = leftStickX * leftStickX;
// Accept and process input if true; otherwise, reject and ignore it.
if ((oppositeSquared + adjacentSquared) < deadzoneSquared)
{
// Input accepted, process it.
}