Bagikan melalui


Roda balap dan umpan balik paksa

Halaman ini menjelaskan dasar-dasar pemrograman untuk roda balap pada Xbox One menggunakan Windows.Gaming.Input.RacingWheel dan API terkait untuk Platform Windows Universal (UWP).

Dengan membaca halaman ini, Anda akan mempelajari:

  • cara mengumpulkan daftar roda balap yang terhubung dan penggunanya
  • cara mendeteksi bahwa roda balap telah ditambahkan atau dilepas
  • cara membaca input dari satu atau beberapa roda balap
  • cara mengirim perintah umpan balik paksa
  • bagaimana roda balap berulah sebagai perangkat navigasi UI

Gambaran umum roda balap

Roda balap adalah perangkat input yang menyerupai nuansa kokpit racecar nyata. Roda balap adalah perangkat input yang sempurna untuk game balap gaya arkade dan gaya simulasi yang menampilkan mobil atau truk. Roda balap didukung di aplikasi Windows 10 atau Windows 11 dan Xbox One UWP oleh namespace Windows.Gaming.Input .

Roda balap ditawarkan pada berbagai titik harga, umumnya memiliki lebih banyak dan lebih baik input dan kemampuan umpan balik paksa saat poin harga mereka naik. Semua roda balap dilengkapi dengan roda kemudi analog, throttle analog dan kontrol rem, dan beberapa tombol on-wheel. Beberapa roda balap juga dilengkapi dengan kontrol kopling dan handbrake analog, pergeser pola, dan kemampuan umpan balik paksa. Tidak semua roda balap dilengkapi dengan serangkaian fitur yang sama, dan juga dapat bervariasi dalam dukungannya untuk fitur tertentu—misalnya, roda kemudi mungkin mendukung berbagai rotasi dan pergeser pola mungkin mendukung jumlah roda gigi yang berbeda.

Kemampuan perangkat

Roda balap yang berbeda menawarkan berbagai set kemampuan perangkat opsional dan berbagai tingkat dukungan untuk kemampuan tersebut; tingkat variasi antara satu jenis perangkat input ini unik di antara perangkat yang didukung oleh WINDOWS.Gaming.Input API. Selain itu, sebagian besar perangkat yang akan Anda temui akan mendukung setidaknya beberapa kemampuan opsional atau variasi lainnya. Karena itu, penting untuk menentukan kemampuan setiap roda balap yang terhubung satu per satu dan untuk mendukung variasi penuh kemampuan yang masuk akal untuk permainan Anda.

Untuk informasi selengkapnya, lihat Menentukan kemampuan roda balap.

Paksa umpan balik

Beberapa roda balap menawarkan umpan balik kekuatan sejati—yaitu, mereka dapat menerapkan kekuatan aktual pada sumbu kontrol seperti roda kemudi mereka—bukan hanya getaran sederhana. Game menggunakan kemampuan ini untuk menciptakan rasa perendaman yang lebih besar (kerusakan kecelakaan yang disimulasikan, "nuansa jalan") dan untuk meningkatkan tantangan mengemudi dengan baik.

Untuk informasi selengkapnya, lihat Gambaran umum paksa umpan balik.

Navigasi antarmuka pengguna

Untuk meringankan beban mendukung perangkat input yang berbeda untuk navigasi antarmuka pengguna dan untuk mendorong konsistensi antara game dan perangkat, sebagian besar perangkat input fisik secara bersamaan bertindak sebagai perangkat input logis terpisah yang disebut pengontrol navigasi UI. Pengontrol navigasi UI menyediakan kosakata umum untuk perintah navigasi UI di seluruh perangkat input.

Karena fokus unik mereka pada kontrol analog dan tingkat variasi antara roda balap yang berbeda, biasanya dilengkapi dengan tombol D-pad, Tampilan, Menu, A, B, X, dan Y digital yang menyerupai tombol gamepad; tombol ini tidak dimaksudkan untuk mendukung perintah gameplay dan tidak dapat diakses dengan mudah sebagai tombol roda balap.

Sebagai pengontrol navigasi UI, roda balap memetakan serangkaian perintah navigasi yang diperlukan ke thumbstick kiri, tombol D-pad, Tampilan, Menu, A, dan B.

Perintah navigasi Input roda balap
Naik D-pad ke atas
Tidak berfungsi D-pad ke bawah
Left D-pad kiri
Right D-pad kanan
Tampilkan Tombol Tampilan
Menu Tombol Menu
Terima Tombol
Batalkan Tombol B

Selain itu, beberapa roda balap mungkin memetakan beberapa set perintah navigasi opsional ke input lain yang didukungnya, tetapi pemetaan perintah dapat bervariasi dari perangkat ke perangkat. Pertimbangkan untuk mendukung perintah ini juga, tetapi pastikan bahwa perintah ini tidak penting untuk menavigasi antarmuka game Anda.

Perintah navigasi Input roda balap
Halaman Atas Bervariasi
Halaman Bawah Bervariasi
Halaman Kiri Bervariasi
Halaman Kanan Bervariasi
Gulir Ke Atas Bervariasi
Gulir ke Bawah Bervariasi
Gulir Ke Kiri Bervariasi
Gulir Ke Kanan Bervariasi
Konteks 1 Tombol X (umumnya)
Konteks 2 Tombol Y (umumnya)
Konteks 3 Bervariasi
Konteks 4 Bervariasi

Mendeteksi dan melacak roda balap

Mendeteksi dan melacak roda balap bekerja dengan cara yang sama persis seperti halnya untuk gamepad, kecuali dengan kelas RacingWheel alih-alih kelas Gamepad . Lihat Gamepad dan getaran untuk informasi selengkapnya.

Membaca roda balap

Setelah mengidentifikasi roda balap yang Anda minati, Anda siap untuk mengumpulkan input dari mereka. Namun, tidak seperti beberapa jenis input lain yang mungkin biasa Anda gunakan, roda balap tidak mengkomunikasikan perubahan status dengan menaikkan peristiwa. Sebagai gantinya, Anda mengambil pembacaan rutin tentang status mereka saat ini dengan polling mereka.

Polling roda balap

Polling menangkap rekam jepret roda balap 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 roda balap dengan memanggil GetCurrentReading; fungsi ini mengembalikan RacingWheelReading yang berisi keadaan roda balap.

Contoh berikut melakukan polling roda balap untuk keadaannya saat ini.

auto racingwheel = myRacingWheels[0];

RacingWheelReading reading = racingwheel->GetCurrentReading();

Selain status roda balap, setiap pembacaan mencakup tanda waktu yang menunjukkan dengan tepat ketika status diambil. Tanda waktu berguna untuk berkaitan dengan waktu pembacaan sebelumnya atau waktu simulasi permainan.

Menentukan kemampuan roda balap

Banyak kontrol roda balap bersifat opsional atau mendukung variasi yang berbeda bahkan dalam kontrol yang diperlukan, jadi Anda harus menentukan kemampuan setiap roda balap satu per satu sebelum Anda dapat memproses input yang dikumpulkan di setiap pembacaan roda balap.

Kontrol opsional adalah handbrake, clutch, dan pattern shifter; Anda dapat menentukan apakah roda balap yang terhubung mendukung kontrol ini dengan membaca properti HasHandbrake, HasClutch, dan HasPatternShifter dari roda balap. Kontrol didukung jika nilai properti benar; jika tidak, kontrol tidak didukung.

if (racingwheel->HasHandbrake)
{
    // the handbrake is supported
}

if (racingwheel->HasClutch)
{
    // the clutch is supported
}

if (racingwheel->HasPatternShifter)
{
    // the pattern shifter is supported
}

Selain itu, kontrol yang dapat bervariasi adalah roda kemudi dan pergeser pola. Roda kemudi dapat bervariasi berdasarkan tingkat rotasi fisik yang dapat didukung roda aktual, sementara pergeser pola dapat bervariasi berdasarkan jumlah roda gigi maju yang berbeda yang didukungnya. Anda dapat menentukan sudut rotasi terbesar yang didukung roda aktual dengan membaca MaxWheelAngle properti roda balap; nilainya adalah sudut fisik maksimum yang didukung dalam derajat clock-wise (positif) yang juga didukung dalam arah counter-clock-wise (derajat negatif). Anda dapat menentukan roda gigi depan terbesar yang didukung pemindah pola dengan membaca MaxPatternShifterGear properti roda balap; nilainya adalah roda gigi maju tertinggi yang didukung, inklusif—yaitu, jika nilainya adalah 4, maka pergeser pola mendukung roda gigi terbalik, netral, pertama, kedua, ketiga, dan keempat.

auto maxWheelDegrees = racingwheel->MaxWheelAngle;
auto maxShifterGears = racingwheel->MaxPatternShifterGear;

Akhirnya, beberapa roda balap mendukung umpan balik paksa melalui roda kemudi. Anda dapat menentukan apakah roda balap yang terhubung mendukung umpan balik paksa dengan membaca properti WheelMotor dari roda balap. Umpan balik paksa didukung jika WheelMotor tidak null; jika tidak, umpan balik tidak didukung.

if (racingwheel->WheelMotor != nullptr)
{
    // force feedback is supported
}

Untuk informasi tentang cara menggunakan kemampuan umpan balik paksa roda balap yang mendukungnya, lihat Memaksa ringkasan umpan balik.

Membaca tombol

Masing-masing tombol roda balap—empat arah D-pad, tombol Roda Gigi Sebelumnya dan Roda Gigi Berikutnya, dan 16 tombol tambahan—menyediakan pembacaan digital yang menunjukkan apakah tombol tersebut ditekan (bawah) atau dilepaskan (ke atas). Untuk efisiensi, pembacaan tombol tidak direpresentasikan sebagai nilai boolean individual; sebaliknya mereka semua dikemas ke dalam satu ladang bit yang diwakili oleh enumerasi RacingWheelButtons .

Catatan

Roda balap dilengkapi dengan tombol tambahan yang digunakan untuk navigasi UI seperti tombol Tampilan dan Menu . Tombol-tombol ini bukan bagian dari RacingWheelButtons enumerasi dan hanya dapat dibaca dengan mengakses roda balap sebagai perangkat navigasi UI. Untuk informasi selengkapnya, lihat Perangkat Navigasi UI.

Nilai tombol dibaca dari Buttons properti struktur RacingWheelReading . Karena properti ini adalah bitfield, masking bitwise digunakan untuk mengisolasi nilai tombol yang Anda minati. Tombol ditekan (ke bawah) ketika bit yang sesuai diatur; jika tidak, itu dirilis (naik).

Contoh berikut menentukan apakah tombol Next Gear ditekan.

if (RacingWheelButtons::NextGear == (reading.Buttons & RacingWheelButtons::NextGear))
{
    // Next Gear is pressed
}

Contoh berikut menentukan apakah tombol Next Gear dirilis.

if (RacingWheelButtons::None == (reading.Buttons & RacingWheelButtons::NextGear))
{
    // Next Gear is released (not 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 kondisi ini, lihat Mendeteksi transisi tombol dan Mendeteksi pengaturan tombol yang kompleks.

Membaca roda

Roda kemudi adalah kontrol yang diperlukan yang menyediakan pembacaan analog antara -1.0 dan +1.0. Nilai -1.0 sesuai dengan posisi roda paling kiri; nilai +1.0 sesuai dengan posisi paling kanan. Nilai roda kemudi dibaca dari Wheel properti struktur RacingWheelReading .

float wheel = reading.Wheel;  // returns a value between -1.0 and +1.0.

Meskipun pembacaan roda sesuai dengan berbagai derajat rotasi fisik di roda aktual tergantung pada rentang rotasi yang didukung oleh roda balap fisik, Anda biasanya tidak ingin menskalakan pembacaan roda; roda yang mendukung derajat rotasi yang lebih besar hanya memberikan presisi yang lebih besar.

Membaca pembatasan dan rem

Pembatasan dan rem diperlukan kontrol yang masing-masing menyediakan pembacaan analog antara 0,0 (dilepaskan sepenuhnya) dan 1,0 (ditekan sepenuhnya) yang direpresentasikan sebagai nilai floating-point. Nilai kontrol pembatasan dibaca dari Throttle properti struct RacingWheelReading ; nilai kontrol rem dibaca dari Brake properti .

float throttle = reading.Throttle;  // returns a value between 0.0 and 1.0
float brake    = reading.Brake;     // returns a value between 0.0 and 1.0

Membaca handbrake dan kopling

Handbrake dan kopling adalah kontrol opsional yang masing-masing menyediakan pembacaan analog antara 0,0 (sepenuhnya dirilis) dan 1,0 (sepenuhnya terlibat) yang diwakili sebagai nilai floating-point. Nilai kontrol handbrake dibaca dari Handbrake properti struct RacingWheelReading; nilai kontrol kopling dibaca dari Clutch properti .

float handbrake = 0.0;
float clutch = 0.0;

if(racingwheel->HasHandbrake)
{
    handbrake = reading.Handbrake;  // returns a value between 0.0 and 1.0
}

if(racingwheel->HasClutch)
{
    clutch = reading.Clutch;        // returns a value between 0.0 and 1.0
}

Membaca pergeser pola

Pemindah pola adalah kontrol opsional yang menyediakan pembacaan digital antara -1 dan MaxPatternShifterGear yang diwakili sebagai nilai bilangan bulat yang ditandatangani. Nilai -1 atau 0 sesuai dengan roda gigi terbalik dan netral , masing-masing; nilai yang semakin positif sesuai dengan roda gigi penerusan yang lebih besar hingga MaxPatternShifterGear, inklusif. Nilai shifter pola dibaca dari properti PatternShifterGear dari struktur RacingWheelReading .

if (racingwheel->HasPatternShifter)
{
    gear = reading.PatternShifterGear;
}

Catatan

Pergeser pola, jika didukung, ada bersama tombol Roda Gigi Sebelumnya dan Roda Gigi Berikutnya yang diperlukan yang juga memengaruhi roda gigi mobil pemutar saat ini. Strategi sederhana untuk menyatukan input ini di mana keduanya hadir adalah mengabaikan pergeser pola (dan kopling) ketika pemutar memilih transmisi otomatis untuk mobil mereka, dan untuk mengabaikan tombol Roda Gigi Sebelumnya dan Berikutnya ketika pemain memilih transmisi manual untuk mobil mereka hanya jika roda balap mereka dilengkapi dengan kontrol shifter pola. Anda dapat menerapkan strategi unifikasi yang berbeda jika ini tidak cocok untuk game Anda.

Jalankan sampel InputInterfacing

Aplikasi sampel InputInterfacingUWP di GitHub menunjukkan cara menggunakan roda balap dan berbagai jenis perangkat input bersamaan; serta bagaimana perangkat input ini berpura-pura sebagai pengontrol navigasi UI.

Gambaran umum umpan balik paksa

Banyak roda balap memiliki kemampuan umpan balik yang memaksa untuk memberikan pengalaman mengemudi yang lebih imersif dan menantang. Roda balap yang mendukung umpan balik paksa biasanya dilengkapi dengan satu motor yang menerapkan kekuatan pada roda kemudi di sepanjang sumbu tunggal, sumbu rotasi roda. Umpan balik paksa didukung di aplikasi UWP Windows 10 atau Windows 11 dan Xbox One melalui namespace Windows.Gaming.Input.ForceFeedback .

Catatan

API umpan balik paksa mampu mendukung beberapa sumbu gaya, tetapi saat ini tidak ada roda balap yang mendukung sumbu umpan balik selain rotasi roda.

Menggunakan umpan balik paksa

Bagian ini menjelaskan dasar-dasar efek umpan balik gaya pemrograman untuk roda balap. Umpan balik diterapkan menggunakan efek, yang pertama kali dimuat ke perangkat umpan balik paksa dan kemudian dapat dimulai, dijeda, dilanjutkan, dan dihentikan dengan cara yang mirip dengan efek suara; namun, Anda harus terlebih dahulu menentukan kemampuan umpan balik dari roda balap.

Menentukan kemampuan umpan balik paksa

Anda dapat menentukan apakah roda balap yang terhubung mendukung umpan balik paksa dengan membaca properti WheelMotor dari roda balap. Umpan balik paksa tidak didukung jika WheelMotornull; jika tidak, umpan balik paksa didukung dan Anda dapat melanjutkan untuk menentukan kemampuan umpan balik tertentu dari motor, seperti sumbu yang dapat memengaruhinya.

if (racingwheel->WheelMotor != nullptr)
{
    auto axes = racingwheel->WheelMotor->SupportedAxes;

    if(ForceFeedbackEffectAxes::X == (axes & ForceFeedbackEffectAxes::X))
    {
        // Force can be applied through the X axis
    }

    if(ForceFeedbackEffectAxes::Y == (axes & ForceFeedbackEffectAxes::Y))
    {
        // Force can be applied through the Y axis
    }

    if(ForceFeedbackEffectAxes::Z == (axes & ForceFeedbackEffectAxes::Z))
    {
        // Force can be applied through the Z axis
    }
}

Memuat efek umpan balik paksa

Efek umpan balik paksa dimuat ke perangkat umpan balik di mana mereka "dimainkan" secara otonom atas perintah permainan Anda. Sejumlah efek dasar disediakan; efek kustom dapat dibuat melalui kelas yang mengimplementasikan antarmuka IForceFeedbackEffect .

Kelas efek Deskripsi efek
ConditionForceEffect Efek yang menerapkan kekuatan variabel sebagai respons terhadap sensor saat ini dalam perangkat.
ConstantForceEffect Efek yang menerapkan kekuatan konstan di sepanjang vektor.
PeriodicForceEffect Efek yang menerapkan kekuatan variabel yang ditentukan oleh bentuk gelombang, di sepanjang vektor.
RampForceEffect Efek yang menerapkan gaya yang meningkat/menurun secara linier di sepanjang vektor.
using FFLoadEffectResult = ForceFeedback::ForceFeedbackLoadEffectResult;

auto effect = ref new Windows.Gaming::Input::ForceFeedback::ConstantForceEffect();
auto time = TimeSpan(10000);

effect->SetParameters(Windows::Foundation::Numerics::float3(1.0f, 0.0f, 0.0f), time);

// Here, we assume 'racingwheel' is valid and supports force feedback

IAsyncOperation<FFLoadEffectResult>^ request
    = racingwheel->WheelMotor->LoadEffectAsync(effect);

auto loadEffectTask = Concurrency::create_task(request);

loadEffectTask.then([this](FFLoadEffectResult result)
{
    if (FFLoadEffectResult::Succeeded == result)
    {
        // effect successfully loaded
    }
    else
    {
        // effect failed to load
    }
}).wait();

Menggunakan efek umpan balik paksa

Setelah dimuat, semua efek dapat dimulai, dijeda, dilanjutkan, dan dihentikan secara sinkron dengan memanggil fungsi pada WheelMotor properti roda balap, atau secara individual dengan memanggil fungsi pada efek umpan balik itu sendiri. Biasanya, Anda harus memuat semua efek yang ingin Anda gunakan ke perangkat umpan balik sebelum gameplay dimulai dan kemudian menggunakan fungsi masing-masing SetParameters untuk memperbarui efek saat gameplay berlangsung.

if (ForceFeedbackEffectState::Running == effect->State)
{
    effect->Stop();
}
else
{
    effect->Start();
}

Terakhir, Anda dapat mengaktifkan, menonaktifkan, atau mengatur ulang seluruh sistem umpan balik paksa secara asinkron pada roda balap tertentu kapan pun Anda butuhkan.

Baca juga