Gamepad API'yi kullanarak web oyunlarınızı bir üst seviyeye nasıl taşıyacağınızı öğrenin.
Chrome'un çevrimdışı sayfasındaki sürpriz yumurta, tarihin en kötü saklanan sırlarından biri ([citation needed],
ancak bu iddia dramatik etki için ortaya atıldı). Boşluk tuşuna basarsanız veya mobil cihazlarda dinozora dokunursanız çevrimdışı sayfa, oynanabilir bir arcade oyununa dönüşür. Oyun oynamak istediğinizde internet bağlantınızı kesmeniz gerekmediğini biliyor olabilirsiniz. Chrome'da about://dino adresine giderek veya about://network-error/-106 adresine göz atarak oyuna erişebilirsiniz. Ancak her ay 270 milyon Chrome dinozor oyunu oynandığını biliyor muydunuz?
Bilmenizin daha faydalı olabileceği ve farkında olmayabileceğiniz bir diğer gerçek de arcade modunda oyunu oyun kumandasıyla oynayabileceğinizdir. Oyun kumandası desteği, bu makalenin yazıldığı tarihten yaklaşık bir yıl önce Reilly Grant tarafından bir kayıt ile eklenmiştir. Gördüğünüz gibi oyun, Chromium projesinin geri kalanı gibi tamamen açık kaynaklıdır. Bu yazıda, Gamepad API'yi nasıl kullanacağınızı göstereceğim.
Gamepad API'yi kullanma
Özellik algılama ve tarayıcı desteği
Gamepad API, hem masaüstü hem de mobil cihazlarda mükemmel bir tarayıcı desteğine sahiptir. Gamepad API'nin desteklenip desteklenmediğini aşağıdaki snippet'i kullanarak tespit edebilirsiniz:
if ('getGamepads' in navigator) {
// The API is supported!
}
Tarayıcının oyun kumandasını temsil etme şekli
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öğesininVRDisplay.displayIddeğeri (varsa).index: Gezgindeki oyun kumandasının dizini.connected: Oyun kumandasının sisteme hâlâ bağlı olup olmadığını gösterir.hand: Kumandanın hangi elde tutulduğunu veya büyük olasılıkla hangi elde tutulacağını tanımlayan bir enum.timestamp: Bu oyun kumandasına ait verilerin son güncellenme zamanı.mapping: Bu cihaz için kullanılan düğme ve eksen eşlemesi ("standard"veya"xr-standard").pose: WebVR kumandasıyla ilişkili duruş bilgilerini temsil eden birGamepadPosenesnesi.axes: Oyun kumandasının tüm eksenleri için-1.0-1.0aralığına doğrusal olarak normalleştirilmiş bir değer dizisi.buttons: Oyun kumandasının tüm düğmeleri için düğme durumları dizisi.
Düğmelerin dijital (basılı veya basılı değil) ya da analog (ör. %78 basılı) olabileceğini unutmayın. Bu nedenle düğmeler, aşağıdaki özelliklere sahip GamepadButton nesneleri olarak raporlanır:
pressed: Düğmenin basılı durumu (düğmeye basılırsatrue, basılmazsafalse).touched: Düğmenin dokunulmuş durumu. Düğme dokunmayı algılayabiliyorsa düğmeye dokunulduğunda bu özelliktrue, aksi takdirdefalseolur.value: Analog sensörü olan düğmelerde bu özellik, düğmenin basılma miktarını temsil eder ve0.0-1.0aralığına doğrusal olarak normalleştirilir.hapticActuators: Kumandada bulunan dokunsal geribildirim donanımını temsil edenGamepadHapticActuatornesnelerini içeren bir dizi.
Tarayıcınıza ve kullandığınız oyun kumandasına bağlı olarak karşılaşabileceğiniz bir diğer özellik de vibrationActuator özelliğidir. İki tür sarsıntı efektine izin verir:
- Dual-Rumble: Oyun kumandasının her iki tutma yerinde bulunan iki eksantrik dönen kütle aktüatörü tarafından oluşturulan dokunsal geribildirim efekti.
- Tetikleyici Titreşimi: Oyun kumandasının her bir tetikleyicisinde bulunan iki bağımsız motor tarafından oluşturulan dokunsal geribildirim efekti.
Doğrudan spesifikasyondan alınan aşağıdaki şematik genel bakış, genel bir oyun kumandasındaki düğmelerin ve eksenlerin eşlemesini ve düzenini göstermektedir.
Oyun kumandası bağlandığında bildirim gönderilir.
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ı bağladığında, oyun kumandasının ayrıntılarını içeren ve uygun şekilde adlandırılmış bir gamepad özelliğine sahip GamepadEvent tetiklenir.
Aşağıda, elimde bulunan bir Xbox 360 kumandasından bir örnek görebilirsiniz (evet, retro oyunları 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 gönderilir.
Oyun kumandası bağlantısının kesildiğine dair bildirimler, bağlantıların algılanmasına benzer şekilde gerçekleşir.
Bu kez uygulama gamepaddisconnected etkinliğini dinler. Aşağıdaki örnekte, Xbox 360 kumandasının fişini çektiğimde connected değerinin nasıl false olduğuna dikkat edin.
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ına erişmek için navigator.getGamepads() çağrısı yapılır. Bu çağrı, Gamepad öğe içeren bir dizi döndürür. Chrome'daki dizinin uzunluğu her zaman dört öğe olarak sabittir. Sıfır veya dörtten az oyun kumandası bağlıysa bir öğe yalnızca null olabilir. Dizideki tüm öğeleri kontrol ettiğinizden emin olun ve oyun kumandalarının yuvalarını "hatırladığını" ve her zaman ilk kullanılabilir yuvada bulunmayabileceğini unutmayın.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Bir veya daha fazla oyun kumandası bağlı olmasına rağmen navigator.getGamepads() hâlâ null öğe bildiriyorsa
her oyun kumandasını düğmelerinden birine basarak "uyandırmanız" gerekebilir. Ardından, aşağıdaki kodda gösterildiği gibi oyun döngünüzdeki oyun kumandası durumlarını sorgulayabilirsiniz.
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 aktüatörü
vibrationActuator özelliği, dokunsal geri bildirim 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. Dokunma efektleri, Gamepad.vibrationActuator.playEffect() çağrılarak oynatılabilir. Yalnızca 'dual-rumble' ve 'trigger-rumble' geçerli efekt türleridir.
Desteklenen sarsıntı 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.
}
Çift titreşim
Dual-rumble, standart bir oyun kumandasının her bir kolunda eksantrik dönen kütle titreşim motoru bulunan dokunma yapılandırmasını ifade eder. Bu yapılandırmada, her iki motor da tüm oyun kumandasını titretebilir. İki kütle eşit değildir. Böylece her birinin etkileri birleştirilerek daha karmaşık dokunma efektleri oluşturulabilir. Çift sarsıntı efektleri dört parametreyle tanımlanır:
duration: Titreşim efektinin süresini milisaniye cinsinden ayarlar.startDelay: Titreşim başlayana kadar gecikme süresini ayarlar.strongMagnitudeveweakMagnitude: Daha ağır ve daha hafif eksantrik dönen kütle motorları için titreşim yoğunluğu seviyelerini0.0-1.0aralığı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,
});
};
Tetikleyici titreşimi
Tetik titreşimi, oyun kumandasının her bir tetiğinde bulunan iki bağımsız motor tarafından oluşturulan dokunsal geribildirim efektidir.
// 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ı ile entegrasyon
Gamepad API spesifikasyonu, "gamepad" dizesiyle tanımlanan politikayla kontrol edilen bir özellik tanımlar. Varsayılan allowlist değeri "self". Bir dokümanın izin politikası, o dokümandaki herhangi bir içeriğin navigator.getGamepads() erişimine 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 ile gamepaddisconnected etkinlikleri tetiklenmez.
<iframe src="index.html" allow="gamepad"></iframe>
Demo
Aşağıdaki örnekte bir oyun kumandası test aracı demosu yerleştirilmiştir. Kaynak kodunu GitHub'da bulabilirsiniz. USB veya Bluetooth kullanarak bir oyun kumandası bağlayıp düğmelerinden birine basarak ya da eksenlerinden birini hareket ettirerek demoyu deneyin.
Bonus: web.dev'de Chrome Dinozor oyununu oynama
Bu sitede oyun kumandanızla Chrome dino oyununu oynayabilirsiniz. Kaynak kodunu GitHub'da bulabilirsiniz.
trex-runner.js dosyasındaki oyun kumandası yoklama uygulamasını inceleyin ve tuş basışlarını nasıl taklit ettiğine dikkat edin.
Chrome dinozor oyun kumandası demosunun çalışması için Chrome dinozor oyununu temel Chromium projesinden çıkardım (Arnelle Ballane'nin önceki bir çalışmasını güncelledim), bağımsız bir siteye yerleştirdim, eğilme ve titreşim efektleri ekleyerek mevcut oyun kumandası API'si uygulamasını genişlettim, tam ekran modu oluşturdum ve Mehul Satardekar koyu mod uygulamasına katkıda bulundu. İyi oyunlar!
Faydalı bağlantı
Onaylar
Bu belge, François Beaufort ve Joe Medley tarafından incelenmiştir. Gamepad API spesifikasyonu Steve Agoston, James Hollyer ve Matt Reynolds tarafından düzenlenmiştir. Eski spesifikasyon editörleri Brandon Jones, Scott Graham ve Ted Mielczarek'tir. Gamepad Extensions spesifikasyonu Brandon Jones tarafından düzenlenmiştir.