Web oyunlarınızı bir üst seviyeye çıkarmak için Gamepad API'yi nasıl kullanacağınızı öğrenin.
Chrome'un çevrimdışı sayfası paskalya yumurtası, tarihin en kötü saklanan sırlarından biridir ([citation needed]
, ancak bu iddianın amacı dramatik etki yaratmaktır). 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 internete bağlı olmanız gerekmediğini biliyor olabilirsiniz: Chrome'da about://dino
'e gidebilir veya about://network-error/-106
'e göz atabilirsiniz. Ancak her ay 270 milyon Chrome dinozor oyunu oynandığını biliyor muydunuz?
Bilmenizin faydalı olabileceği ve farkında olmayabileceklerinizden biri de oyun salonu modunda oyunu gamepad ile oynayabilmenizdir. Gamepad desteği, bu makalenin yazıldığı tarih itibarıyla yaklaşık bir yıl önce Reilly Grant tarafından yapılan bir commit eklendi. Gördüğünüz gibi oyun, Chromium projesinin geri kalanı gibi tamamen açık kaynaktır. Bu gönderide, Gamepad API'nin nasıl kullanılacağını göstermek istiyorum.
Gamepad API'yi 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. Aşağıdaki snippet'i kullanarak Gamepad API'nin desteklenip desteklenmediğini algılayabilirsiniz:
if ('getGamepads' in navigator) {
// The API is supported!
}
Tarayıcı, oyun kumandasını nasıl temsil eder?
Tarayıcı, gamepad'leri Gamepad
nesnesi olarak temsil eder. Gamepad
aşağıdaki özelliklere sahiptir:
id
: Gamepad için bir tanımlayıcı dizesi. Bu dize, bağlı gamepad cihazının markasını veya tarzını tanımlar.displayId
: İlgiliVRDisplay
öğesininVRDisplay.displayId
(varsa).index
: Gezgindeki oyun kumandasının dizini.connected
: Gamepad'in sisteme bağlı olup olmadığını belirtir.hand
: Kumandanın hangi elde tutulduğunu veya büyük olasılıkla tutulacağını tanımlayan bir enum.timestamp
: Bu gamepad'in verilerinin en son güncellendiği zaman.mapping
: Bu cihazda kullanılan düğme ve eksen eşlemesidir ("standard"
veya"xr-standard"
).pose
: WebVR denetleyiciyle ilişkili duruş bilgilerini temsil eden birGamepadPose
nesnesi.axes
: Gamepad'in tüm eksenleri için-1.0
-1.0
aralığına göre doğrusal olarak normalleştirilmiş bir değer dizisi.buttons
: Oyun kumandasının tüm düğmelerinin düğme durumları dizisi.
Düğmelerin dijital (basılı veya basılı değil) ya da analog (ör. %78 oranında 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ılmışsatrue
, basılı değilsefalse
).touched
: Düğmenin dokunulduğu durum. Düğme dokunmayı algılayabiliyorsa bu özellik, düğmeye dokunuluyorsatrue
, aksi takdirdefalse
değerini alır.value
: Analog sensör içeren düğmeler için bu özellik, düğmeye basılan miktarı temsil eder ve0.0
-1.0
aralığında doğrusal olarak normalleştirilir.hapticActuators
: Her biri denetleyicide bulunan dokunma geri bildirimi donanımını temsil edenGamepadHapticActuator
öğeleri içeren bir dizi.
Tarayıcınız ve gamepad'inize bağlı olarak karşılaşabileceğiniz bir diğer şey de vibrationActuator
mülküdür. İki tür titreşim efekti sağlar:
- Çift titreşim: Oyun kolunun her bir tutacağında bulunan iki eksantrik dönen kütle aktüatörü tarafından oluşturulan dokunma geri bildirimi efekti.
- Tetikleyici titreşimi: İki bağımsız motor tarafından oluşturulan dokunma geri bildirimi efekti. Bu motorlardan biri gamepad'in tetikleyicilerinin her birinde bulunur.
Doğrudan spesifikasyondan alınan aşağıdaki şematik genel bakış, genel bir gamepad'deki düğmelerin ve eksenlerin haritalarını ve düzenini gösterir.
Oyun kumandası bağlandığında bildirim
Bir gamepad'in ne zaman bağlandığını öğrenmek için window
nesnesinde tetiklenen gamepadconnected
etkinliğini dinleyin. Kullanıcı bir gamepad bağladığında (USB veya Bluetooth kullanılarak yapılabilir), gamepad'in ayrıntılarını uygun şekilde adlandırılmış bir gamepad
mülkünde içeren bir GamepadEvent
tetiklenir.
Aşağıda, elimde bulunan bir Xbox 360 kumandasından alınmış bir örneği görebilirsiniz (Evet, retro oyunlara meraklıyım).
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"}
*/
});
Gamepad bağlantısı kesildiğinde bildirim
Gamepad bağlantılarının kesilmesi hakkında bildirim alma, bağlantıların algılanma şekline benzer şekilde gerçekleşir.
Bu kez uygulama gamepaddisconnected
etkinliğini dinler. Aşağıdaki örnekte, Xbox 360 kumandasının fişi çekildiğinde connected
değerinin false
olarak nasıl değiştiğine 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üsünüzdeki oyun kumandası
Gamepad'i kullanmaya başlamak 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 sabitlenmiştir. Sıfır veya dörtten az gamepad bağlıysa öğe yalnızca null
olabilir. Her zaman dizinin tüm öğelerini kontrol edin. Gamepad'lerin, slotlarını "hatırladığını" ve her zaman ilk kullanılabilir slotta bulunmayabileceğini unutmayın.
// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]
Bir veya daha fazla gamepad bağlıysa ancak navigator.getGamepads()
hâlâ null
öğe bildiriyorsa her gamepad'in düğmelerinden birine basarak gamepad'i "uyandırmanız" gerekebilir. Ardından, aşağıdaki kodda gösterildiği gibi oyun döngüsünüzde gamepad durumlarını anketleyebilirsiniz.
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
mülkü, dokunma geri bildirimi 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 etkileri Gamepad.vibrationActuator.playEffect()
çağrılarak oynatılabilir. Geçerli tek efekt türleri 'dual-rumble'
ve 'trigger-rumble'
'dir.
Desteklenen titreşim 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
Çift titreşim, standart bir gamepad'in her koluna eksantrik dönen kütle titreşim motoru yerleştirilmiş bir dokunma yapılandırmasını ifade eder. Bu yapılandırmada, her iki motor da gamepad'in tamamını titreştirebilir. İki kütle eşit değildir. Böylece her birinin etkileri birleştirilerek daha karmaşık dokunma etkileri oluşturulabilir. Çift titreşim efektleri dört parametreyle tanımlanır:
duration
: Titreşim efektinin süresini milisaniye cinsinden ayarlar.startDelay
: Titreşimin başlatılmasına kadar geçecek süreyi 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 göre 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,
});
};
Titreşimi tetikleme
Tetik titreşimi, gamepad'in tetikleyicilerinin her birinde bulunan bir motorla iki bağımsız motor tarafından üretilen dokunsal geri bildirim 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"
dizesi ile tanımlanan bir politika kontrollü özelliği tanımlar. Varsayılan allowlist
değeri "self"
'dur. Bir dokümanın izin politikası, söz konusu dokümandaki içeriklerin navigator.getGamepads()
'e erişip erişemeyeceğini belirler. Herhangi bir dokümanda devre dışı bırakılırsa dokümanda 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 gamepad test cihazı demosu yerleştirilmiştir. Kaynak koduna Glitch'ten ulaşabilirsiniz. USB veya Bluetooth kullanarak bir gamepad bağlayın ve düğmelerinden birine basarak veya eksenlerinden birini hareket ettirerek denemeyi deneyin.
Bonus: web.dev'de Chrome Dinozor'u oynayın
Bu sitede gamepad'inizle Chrome dinozor oyununu oynayabilirsiniz. Kaynak kodunu GitHub'da bulabilirsiniz.
trex-runner.js
bölümündeki gamepad anketi uygulamasına göz atın ve tuş basmalarını nasıl taklit ettiğini öğrenin.
Chrome dino gamepad demosunun çalışması için Chrome dinozor oyununu ana Chromium projesinden çıkardım (Arnelle Ballane tarafından yapılan önceki bir çalışmayı güncelledim), bağımsız bir siteye yerleştirdim, eğme ve titreşim efektleri ekleyerek mevcut gamepad API uygulamasını genişlettim, tam ekran modu oluşturdum ve Mehul Satardekar karanlık mod uygulamasıyla katkıda bulundu. İyi oyunlar dileriz.
Faydalı bağlantı
Teşekkür ederiz
Bu doküman 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. Oyun kumandası uzantıları spesifikasyonu Brandon Jones tarafından düzenlenmiştir. Laura Torrent Puig tarafından oluşturulan hero resim.