Pelajari cara menggunakan Gamepad API untuk meningkatkan kualitas game web Anda.
Fitur tersembunyi halaman offline Chrome adalah salah satu rahasia yang selalu disimpan dalam sejarah ([citation needed]
,
tetapi klaim yang dibuat untuk efek dramatis). Jika Anda menekan tombol spasi atau, di perangkat seluler
perangkat seluler, ketuk dinosaurus, halaman offline menjadi game arcade yang dapat dimainkan. Anda mungkin menyadari bahwa
Anda sebenarnya tidak perlu offline saat ingin bermain: di Chrome, Anda cukup bernavigasi
ke about://dino
, atau, bagi yang suka dengan Anda, buka about://network-error/-106
. Tapi tahukah Anda
bahwa ada
270 juta game dino Chrome dimainkan setiap bulan?
Fakta lain yang mungkin lebih berguna untuk diketahui dan yang mungkin tidak Anda sadari adalah mode arcade, Anda dapat memainkan game dengan {i>gamepad<i}. Dukungan {i>gamepad<i} ditambahkan sekitar satu tahun yang lalu ketika saat artikel ini ditulis dalam commit oleh Reilly Grant. Seperti yang Anda lihat, game ini, sama seperti game Project Chromium, sepenuhnya open source. Di beberapa postingan ini, saya ingin menunjukkan cara menggunakan Gamepad API.
Menggunakan Gamepad API
Deteksi fitur dan dukungan browser
Gamepad API memiliki dukungan browser yang hebat secara universal di kedua platform desktop dan seluler. Anda dapat mendeteksi apakah Gamepad API didukung menggunakan cuplikan berikut:
if ('getGamepads' in navigator) {
// The API is supported!
}
Cara browser menampilkan gamepad
Browser menampilkan gamepad sebagai Gamepad
objek terstruktur dalam jumlah besar. Gamepad
memiliki properti berikut:
id
: String identifikasi untuk gamepad. {i>String<i} ini mengidentifikasi merek atau gaya perangkat gamepad yang tersambung.displayId
:VRDisplay.displayId
dariVRDisplay
terkait (jika relevan).index
: Indeks gamepad di navigator.connected
: Menunjukkan apakah gamepad masih terhubung ke sistem.hand
: Enum yang menentukan tangan mana yang sedang memegang pengontrol, atau kemungkinan besar akan dipegang inc.timestamp
: Terakhir kali data untuk gamepad ini diperbarui.mapping
: Pemetaan tombol dan sumbu yang digunakan untuk perangkat ini, baik"standard"
maupun"xr-standard"
.pose
: ObjekGamepadPose
yang mewakili informasi pose yang terkait dengan pengontrol WebVR.axes
: Array nilai untuk semua sumbu gamepad, yang dinormalisasi secara linear ke rentang-1.0
–1.0
.buttons
: Array status tombol untuk semua tombol gamepad.
Perhatikan bahwa tombol dapat bersifat digital (ditekan atau tidak ditekan) atau analog (misalnya, 78% ditekan). Ini
itulah sebabnya tombol dilaporkan sebagai objek GamepadButton
, dengan atribut berikut:
pressed
: Status tombol ditekan (true
jika tombol ditekan, danfalse
jika tidak ditekan.touched
: Status tombol yang disentuh. Jika tombol tersebut dapat mendeteksi sentuhan, adalahtrue
jika tombol disentuh, danfalse
jika tidak.value
: Untuk tombol yang memiliki sensor analog, properti ini merepresentasikan jumlah ditekan, dinormalisasi secara linear ke rentang0.0
–1.0
.hapticActuators
: Array yang berisiGamepadHapticActuator
, yang masing-masing mewakili hardware respons haptik yang tersedia pada pengontrol.
Satu hal lain yang mungkin Anda temui, tergantung pada {i>browser<i} dan {i>gamepad<i} yang Anda miliki,
adalah properti vibrationActuator
. Hal ini memungkinkan adanya dua jenis efek rumble:
- Dual-Rumble: Efek respons haptik yang dihasilkan oleh dua aktuator massa yang berputar secara eksentrik, satu di setiap genggaman gamepad.
- Trigger-Rumble: Efek respons haptik yang dihasilkan oleh dua motor independen, dengan satu motor yang terletak di setiap pemicu gamepad.
Ikhtisar skematik berikut, diambil langsung dari spesifikasinya, menunjukkan pemetaan serta susunan tombol dan sumbu pada gamepad umum.
Notifikasi saat gamepad terhubung
Untuk mengetahui saat gamepad terhubung, proses peristiwa gamepadconnected
yang dipicu di
Objek window
. Ketika pengguna menghubungkan {i>gamepad<i},
yang bisa dilakukan menggunakan USB atau Bluetooth,
GamepadEvent
diaktifkan yang memiliki detail gamepad di properti gamepad
yang diberi nama dengan tepat.
Di bawah ini, Anda dapat melihat contoh dari {i>controller<i} Xbox 360
yang saya miliki (ya, saya suka
game retro).
window.addEventListener('gamepadconnected', (event) => {
console.log('✅ 🎮 A gamepad was connected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: true
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: GamepadHapticActuator {type: "dual-rumble"}
*/
});
Notifikasi saat gamepad terputus
Notifikasi tentang pemutusan gamepad dilakukan secara analog dengan cara mendeteksi koneksi.
Kali ini aplikasi akan memproses peristiwa gamepaddisconnected
. Perhatikan caranya dalam contoh berikut
connected
sekarang menjadi false
saat saya mencabut pengontrol Xbox 360.
window.addEventListener('gamepaddisconnected', (event) => {
console.log('❌ 🎮 A gamepad was disconnected:', event.gamepad);
/*
gamepad: Gamepad
axes: (4) [0, 0, 0, 0]
buttons: (17) [GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton, GamepadButton]
connected: false
id: "Xbox 360 Controller (STANDARD GAMEPAD Vendor: 045e Product: 028e)"
index: 0
mapping: "standard"
timestamp: 6563054.284999998
vibrationActuator: null
*/
});
Gamepad di game loop Anda
Mendapatkan gamepad dimulai dengan panggilan ke navigator.getGamepads()
, yang menampilkan array
dengan Gamepad
item. Array di Chrome selalu memiliki panjang tetap, yaitu empat item. Jika nol atau kurang
dari empat gamepad yang terhubung, suatu item mungkin hanya null
. Selalu pastikan untuk
memeriksa semua item
array dan perhatikan bahwa gamepad akan "mengingat" slot mereka dan mungkin tidak
selalu hadir di
slot pertama yang tersedia.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Jika satu atau beberapa gamepad terhubung, tetapi navigator.getGamepads()
masih melaporkan null
item,
Anda mungkin perlu "bangun" setiap gamepad dengan menekan tombolnya. Lalu, Anda dapat polling tentang gamepad
status dalam game loop seperti yang ditunjukkan pada kode berikut.
const pollGamepads = () => {
// Always call `navigator.getGamepads()` inside of
// the game loop, not outside.
const gamepads = navigator.getGamepads();
for (const gamepad of gamepads) {
// Disregard empty slots.
if (!gamepad) {
continue;
}
// Process the gamepad state.
console.log(gamepad);
}
// Call yourself upon the next animation frame.
// (Typically this happens every 60 times per second.)
window.requestAnimationFrame(pollGamepads);
};
// Kick off the initial game loop iteration.
pollGamepads();
Aktuator getaran
Properti vibrationActuator
menampilkan objek GamepadHapticActuator
, yang sesuai dengan
konfigurasi motor atau aktuator lain yang dapat
menerapkan gaya untuk tujuan sentuhan
masukan. Efek haptic dapat diputar dengan memanggil Gamepad.vibrationActuator.playEffect()
. Satu-satunya
jenis efek yang valid adalah 'dual-rumble'
dan 'trigger-rumble'
.
Efek gemuruh yang didukung
if (gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
// Trigger rumble supported.
} else if (gamepad.vibrationActuator.effects.includes('dual-rumble')) {
// Dual rumble supported.
} else {
// Rumble effects aren't supported.
}
Suara ganda
Dual-rumble menjelaskan konfigurasi haptic dengan motor getaran massa yang berputar secara eksentrik di setiap pegangan gamepad standar. Dalam konfigurasi ini, salah satu motor mampu bergetar di seluruh gamepad. Kedua massa tersebut tidak sama sehingga masing-masing efek dapat digabungkan untuk membuat efek haptik yang lebih kompleks. Efek dual-rumble adalah didefinisikan oleh empat parameter:
duration
: Menetapkan durasi efek getaran dalam milidetik.startDelay
: Menetapkan durasi penundaan hingga getaran dimulai.strongMagnitude
danweakMagnitude
: Menyetel tingkat intensitas getaran untuk yang lebih berat dan motor massa berputar eksentrik yang lebih ringan, dinormalisasi ke rentang0.0
–1.0
.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const dualRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
gamepad.vibrationActuator.playEffect('dual-rumble', {
// Start delay in ms.
startDelay: delay,
// Duration in ms.
duration: duration,
// The magnitude of the weak actuator (between 0 and 1).
weakMagnitude: weak,
// The magnitude of the strong actuator (between 0 and 1).
strongMagnitude: strong,
});
};
Pemicu error
Trigger rumble adalah efek respons haptik yang dihasilkan oleh dua motor independen, dengan satu motor yang terletak di setiap pemicu gamepad.
// This assumes a `Gamepad` as the value of the `gamepad` variable.
const triggerRumble = (gamepad, delay = 0, duration = 100, weak = 1.0, strong = 1.0) => {
if (!('vibrationActuator' in gamepad)) {
return;
}
// Feature detection.
if (!('effects' in gamepad.vibrationActuator) || !gamepad.vibrationActuator.effects.includes('trigger-rumble')) {
return;
}
gamepad.vibrationActuator.playEffect('trigger-rumble', {
// Duration in ms.
duration: duration,
// The left trigger (between 0 and 1).
leftTrigger: leftTrigger,
// The right trigger (between 0 and 1).
rightTrigger: rightTrigger,
});
};
Integrasi dengan Kebijakan Izin
Spesifikasi Gamepad API mendefinisikan
fitur yang dikontrol kebijakan yang diidentifikasi oleh
string "gamepad"
. allowlist
default-nya adalah "self"
. Kebijakan izin akses dokumen menentukan
apakah ada konten dalam dokumen tersebut yang diizinkan untuk mengakses navigator.getGamepads()
. Jika dinonaktifkan di
dokumen apa pun, tidak ada konten dalam dokumen yang akan diizinkan untuk menggunakan navigator.getGamepads()
, dan juga
peristiwa gamepadconnected
dan gamepaddisconnected
diaktifkan.
<iframe src="index.html" allow="gamepad"></iframe>
Demo
Demo penguji gamepad disematkan dalam contoh berikut. Kode sumber tersedia di Glitch. Coba demo dengan menghubungkan menggunakan USB atau Bluetooth dan menekan tombol atau menggerakkan salah satu sumbunya.
Bonus: mainkan Chrome dino di web.dev
Anda dapat memainkan Chrome dino dengan gamepad di perangkat ini
yang sangat penting. Kode sumbernya tersedia di GitHub.
Lihat implementasi polling gamepad di
trex-runner.js
dan perhatikan bagaimana emulasi penekanan tombol.
Agar demo gamepad dino Chrome berhasil, saya memiliki merobek game dino Chrome dari proyek Chromium inti (memperbarui upaya sebelumnya dengan Arnelle Ballane), menempatkannya di situs mandiri, memperluas implementasi API gamepad yang ada dengan menambahkan efek pengecilan volume dan getaran, sehingga membuat layar penuh mode gelap, dan Mehul Satardekar berkontribusi pada mode gelap terlepas dari implementasi layanan. Selamat bermain game!
Link penting
Ucapan terima kasih
Dokumen ini telah ditinjau oleh François Beaufort dan Joe Medley. Spesifikasi Gamepad API diedit oleh Steve Agoston, James Hollyer, dan Matt Reynolds. Editor spesifikasi sebelumnya adalah Brandon Jones, Scott Graham, dan Ted Mielczarek. Spesifikasi Gamepad Extensions diedit oleh Brandon Jones. Gambar pahlawan oleh Laura Torrent Puig.