Web oyunlarınızı bir üst seviyeye taşımak için Gamepad API'sini nasıl kullanacağınızı öğrenin.
Chrome'un çevrimdışı sayfası paskalya yumurtası, tarihteki en kötü saklanan sırlardan biridir ([citation needed]
, ancak bu kadar etkili olduğu iddia edilmiştir). Boşluk tuşuna basarsanız veya mobil cihazlarda dinozora dokunursanız çevrimdışı sayfa, oynanabilir bir arcade oyunu haline gelir. Oyun oynamak istediğinizde çevrimdışı olmanıza gerek olmadığının farkında olabilirsiniz: Chrome'da about://dino
bölümüne gidebilir ya da meraklıysanız about://network-error/-106
sitesine göz atabilirsiniz. Peki, her ay 270 milyon Chrome dinozor oyununun oynandığını biliyor muydunuz?
Muhtemelen bilmenizin daha yararlı olduğu, sizin de farkında olmayabileceğiniz bir diğer gerçek de, Arcade modunda oyunu oyun kumandasıyla oynayabileceğinizdir. Oyun kumandası desteği yaklaşık bir yıl önce bu yazı yazıldığında Reilly Grant tarafından yapılan bir taahhütte eklendi. Gördüğünüz gibi bu oyun, Chromium projesinin geri kalanı gibi tamamen açık kaynaklıdır. Bu yayında, Gamepad API'yi nasıl kullanacağınızı göstermek istiyorum.
Gamepad API'sini kullanma
Özellik algılama ve tarayıcı desteği
Gamepad API, hem masaüstü hem de mobil cihazlarda evrensel olarak mükemmel tarayıcı desteğine sahiptir. Oyun Kumandası API'sinin desteklenip desteklenmediğini aşağıdaki snippet'i kullanarak tespit edebilirsiniz:
if ('getGamepads' in navigator) {
// The API is supported!
}
Tarayıcı, oyun kumandasını nasıl temsil eder?
Tarayıcı, oyun kumandalarını Gamepad
nesneleri olarak temsil eder. Gamepad
aşağıdaki özelliklere sahiptir:
id
: Oyun kumandası için bir tanımlama dizesi. Bu dize, bağlı oyun kumandası cihazının markasını veya stilini tanımlar.displayId
: İlişkili birVRDisplay
içinVRDisplay.displayId
(varsa).index
: Gezinmedeki oyun kumandasının dizini.connected
: Oyun kumandasının sisteme hâlâ bağlı olup olmadığını gösterir.hand
: Kumandanın tutulduğu veya tutulma olasılığının en yüksek olduğu eli tanımlayan enum.timestamp
: Bu oyun kumandasına ilişkin verilerin en son güncellenme zamanı.mapping
: Bu cihaz için kullanılan düğme ve eksen eşlemesi ("standard"
veya"xr-standard"
).pose
: WebVR denetleyicisiyle ilişkili poz bilgilerini temsil eden birGamepadPose
nesnesi.axes
: Oyun kumandasının tüm eksenleri için-1.0
–1.0
aralığına doğrusal olarak normalleştirilmiş olan bir değer dizisi.buttons
: Oyun kumandasının tüm düğmeleri için düğme durumları dizisi.
Düğmelerin dijital (basılmış veya basılmamış) ya da analog (örneğin, %78'e basılmış) olabileceğini unutmayın. Bu nedenle düğmeler aşağıdaki özelliklere sahip GamepadButton
nesneleri olarak raporlanır:
pressed
: Düğmenin basılma durumu (düğmeye basılmışsatrue
ve basılı değilsefalse
).touched
: Düğmenin dokunulan durumu. Düğme, dokunmayı algılayabiliyorsa düğmeye dokunulduğunda bu özelliktrue
, aksi takdirdefalse
olur.value
: Analog sensör içeren düğmelerde bu özellik, düğmeye basılan süreyi0.0
–1.0
aralığında doğrusal olarak normalleştirilmiş olarak gösterir.hapticActuators
:GamepadHapticActuator
nesneleri içeren bir dizidir. Bu nesnelerin her biri, denetleyicide bulunan dokunsal geri bildirim donanımını temsil eder.
Tarayıcınıza ve sahip olduğunuz oyun kumandasına bağlı olarak karşılaşabileceğiniz diğer bir özellik de vibrationActuator
özelliğidir. İki tür titreşim efektine olanak tanır:
- Dual-Rumble: Oyun kumandasının her tutuşunda birer tane olmak üzere iki eksantrik dönen kütle etkinleştiricisinin oluşturduğu dokunsal geri bildirim efekti.
- Tetikleyici-Rumble: Her bir oyun kumandasının tetikleyicisinde birer motor bulunan iki bağımsız motor tarafından oluşturulan dokunsal geri bildirim efekti.
Doğrudan spesifikasyondan alınan aşağıdaki şematik genel bakış, genel bir oyun kumandasında düğmeler ve eksenlerin eşlemesini ve düzenlemesini göstermektedir.
Oyun kumandası bağlandığında bildirim
Bir oyun kumandasının ne zaman bağlandığını öğrenmek için window
nesnesinde tetiklenen gamepadconnected
etkinliğini dinleyin. Kullanıcı, USB veya Bluetooth kullanarak bir oyun kumandasını bağladığında, oyun kumandasının ayrıntılarını uygun şekilde adlandırılmış gamepad
özelliğinde içeren bir GamepadEvent
tetiklenir.
Aşağıdaki örnekte, benim bıraktığım bir Xbox 360 kumanda örneğini görebilirsiniz (evet, retro oyunlarını seviyorum).
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"}
*/
});
Oyun kumandasının bağlantısı kesildiğinde bildirim
Oyun kumandası bağlantı kopmaları hakkında bildirim alma, bağlantıların algılanma yöntemine benzer şekilde gerçekleşir.
Uygulama bu sefer gamepaddisconnected
etkinliğini dinler. Aşağıdaki örnekte, Xbox 360 kumandayı çıkardığımda connected
artık false
olarak gösterilmiştir.
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
*/
});
Oyun döngünüzdeki oyun kumandası
Bir oyun kumandasını tutmak, Gamepad
öğeli bir dizi döndüren navigator.getGamepads()
çağrısıyla başlar. Chrome'daki dizinin her zaman sabit uzunluğu dört öğedir. Dörtten az oyun kumandası bağlıysa öğe sadece null
olabilir. Dizideki tüm öğeleri her zaman kontrol ettiğinizden emin olun. Oyun kumandalarının slotlarını "hatırladığını" ve her zaman ilk müsait slotta bulunmayabileceğini unutmayın.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Bir veya birkaç oyun kumandası bağlı olmasına rağmen navigator.getGamepads()
hâlâ null
öğe bildiriyorsa düğmelerinden birine basarak her bir oyun kumandasını "uyandırmanız" gerekebilir. Daha sonra, aşağıdaki kodda gösterildiği gibi oyun döngünüzdeki oyun kumandası durumlarını yoklayabilirsiniz.
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();
Titreşim başlatıcı
vibrationActuator
özelliği, dokunsal geribildirim amacıyla kuvvet uygulayabilen motorların veya diğer aktüatörlerin yapılandırmasına karşılık gelen bir GamepadHapticActuator
nesnesi döndürür. Dokunsal efektleri, Gamepad.vibrationActuator.playEffect()
çağırarak oynatabilirsiniz. Yalnızca 'dual-rumble'
ve 'trigger-rumble'
efekt türleri kullanılabilir.
Desteklenen ses efektleri
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.
}
Dual rumble
Dual-rumble, standart oyun kumandasının her kolunda eksantrik dönen kütle titreşim motoruyla dokunsal bir yapılandırmayı tanımlar. Bu yapılandırmada her iki motor da tüm oyun kumandasını titreşebilir. Bu iki kütle eşit değildir. Böylece her birinin etkileri daha karmaşık dokunsal efektler oluşturmak üzere birleştirilebilir. Dual-rumble efektleri dört parametreyle tanımlanır:
duration
: Titreşim efektinin süresini milisaniye cinsinden ayarlar.startDelay
: Titreşim başlatılana kadar geçecek gecikme süresini ayarlar.strongMagnitude
veweakMagnitude
: Daha ağır ve daha hafif eksantrik dönen kütle motorları için titreşim yoğunluğu seviyelerini0.0
–1.0
aralığına normalleştirilmiş olarak ayarlayın.
// 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,
});
};
Takılmayı tetikle
Tetikleme tıkırtısı, her bir oyun kumandasının tetikleyicisinde birer motor bulunan iki bağımsız motor tarafından oluşturulan dokunsal geri bildirim etkisidir.
// 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,
});
};
İzin Politikasıyla Entegrasyon
Gamepad API spesifikasyonu, "gamepad"
dizesiyle tanımlanan politika kontrollü bir özelliği tanımlar. Varsayılan allowlist
değeri "self"
'dir. Bir dokümanın izin politikası, söz konusu dokümandaki herhangi bir içeriğin navigator.getGamepads()
ürününe erişmesine izin verilip verilmediğini belirler. Herhangi bir dokümanda devre dışı bırakılırsa dokümandaki hiçbir içeriğin navigator.getGamepads()
kullanmasına izin verilmez ve gamepadconnected
ve gamepaddisconnected
etkinlikleri etkinleşmez.
<iframe src="index.html" allow="gamepad"></iframe>
Demo
Aşağıdaki örneğe bir oyun kumandası test kullanıcısı demosu yerleştirilmiştir. Kaynak kodu Glitch'te mevcuttur. USB veya Bluetooth kullanarak bir oyun kumandası bağlayıp düğmelerinden birine basarak veya eksenini hareket ettirerek demoyu deneyin.
Bonus: web.dev'de Chrome Dinozor oyununu oynayın
Bu sitede oyun kumandanızla Chrome Dinozor'u oynayabilirsiniz. Kaynak kodu GitHub'da kullanılabilir.
trex-runner.js
'te oyun kumandası yoklama uygulamasına göz atın ve tuşlara basmaları nasıl taklit ettiğine dikkat edin.
Chrome dinozor oyun kumandası demosunun çalışması için Chrome dinozor oyununu temel Chromium projesinden söktüm (Arnelle Ballane tarafından yapılan önceki bir işlemi güncelleyerek), bunu bağımsız bir siteye yerleştirdim, oyun kısılması ve titreşim efektleri ekleyerek mevcut oyun kumandası API uygulamasını genişlettim, tam ekran modu oluşturdum ve Mehul Satardekar uygulamasına katkıda bulundum. İyi oyunlar!
Faydalı bağlantı
Bildirimler
Bu belge, François Beaufort ve Joe Medley tarafından incelendi. Gamepad API spesifikasyonu Steve Agoston, James Hollyer ve Matt Reynolds tarafından düzenlenmiştir. Eski teknik editörler ise Brandon Jones, Scott Graham ve Ted Mielczarek'tir. Oyun Kumandası Uzantıları spesifikasyonu Brandon Jones tarafından düzenlenmiştir. Laura Torrent Puig'in hero resmi.