अपने गेमपैड से Chrome Dino गेम खेलें

अपने वेब गेम को बेहतर बनाने के लिए, Gamepad API का इस्तेमाल करने का तरीका जानें.

Chrome के ऑफ़लाइन पेज पर मौजूद ईस्टर एग, इतिहास में सबसे बुरी तरह से छिपाया गया राज है ([citation needed], हालांकि, यह दावा सिर्फ़ दिलचस्पी बढ़ाने के लिए किया गया है). स्पेस बटन दबाने या मोबाइल डिवाइसों पर डायनासोर पर टैप करने पर, ऑफ़लाइन पेज एक आर्केड गेम में बदल जाता है. शायद आपको पता हो कि जब आपको गेम खेलना हो, तब आपको असल में ऑफ़लाइन जाने की ज़रूरत नहीं है: Chrome में, about://dino पर जाएं या गेम के शौकीन के तौर पर, about://network-error/-106 पर ब्राउज़ करें. क्या आपको पता है कि हर महीने 27 करोड़ लोग Chrome डायनोसॉर गेम खेलते हैं?

Chrome का ऑफ़लाइन पेज, जिसमें Chrome Dino गेम है.
खेलने के लिए, स्पेस बटन दबाएं!

एक और अहम जानकारी यह है कि गेम के आर्केड मोड में, गेमपैड का इस्तेमाल करके गेम खेला जा सकता है. गेमपैड की सुविधा, करीब एक साल पहले जोड़ी गई थी. इस लेख को लिखने के समय, रेली ग्रांट ने commit किया था. जैसा कि आप देख सकते हैं, यह गेम, बाकी Chromium प्रोजेक्ट की तरह ही पूरी तरह से ओपन सोर्स है. इस पोस्ट में, हम आपको Gamepad API का इस्तेमाल करने का तरीका बताना चाहते हैं.

Gamepad API का इस्तेमाल करना

सुविधा की पहचान और ब्राउज़र के साथ काम करने की सुविधा

डेस्कटॉप और मोबाइल, दोनों पर Gamepad API का ब्राउज़र पर बेहतरीन तरीके से इस्तेमाल किया जा सकता है. इस स्निपेट का इस्तेमाल करके पता लगाया जा सकता है कि Gamepad API काम करता है या नहीं:

if ('getGamepads' in navigator) {
  // The API is supported!
}

ब्राउज़र, गेमपैड को कैसे दिखाता है

ब्राउज़र, गेमपैड को Gamepad ऑब्जेक्ट के तौर पर दिखाता है. Gamepad में ये प्रॉपर्टी होती हैं:

  • id: गेमपैड के लिए आइडेंटिफ़िकेशन स्ट्रिंग. इस स्ट्रिंग से, कनेक्ट किए गए गेमपैड डिवाइस के ब्रैंड या स्टाइल की पहचान की जाती है.
  • displayId: अगर लागू हो, तो इससे जुड़ी VRDisplay की VRDisplay.displayId.
  • index: नेविगेटर में गेमपैड का इंडेक्स.
  • connected: इससे पता चलता है कि गेमपैड अब भी सिस्टम से कनेक्ट है या नहीं.
  • hand: यह एक एनम है, जिसमें यह तय किया जाता है कि कंट्रोलर किस हाथ में पकड़ा जा रहा है या किस हाथ में पकड़े जाने की संभावना सबसे ज़्यादा है.
  • timestamp: इस गेमपैड का डेटा आखिरी बार कब अपडेट किया गया था.
  • mapping: इस डिवाइस के लिए इस्तेमाल किया जा रहा बटन और ऐक्सिस मैपिंग, "standard" या "xr-standard".
  • pose: WebVR कंट्रोलर से जुड़ी पोज़ की जानकारी दिखाने वाला GamepadPose ऑब्जेक्ट.
  • axes: गेमपैड के सभी ऐक्सिस की वैल्यू का कलेक्शन, जो -1.0 से 1.0 तक की रेंज में लीनियर तौर पर नॉर्मलाइज़ किया गया है.
  • buttons: गेमपैड के सभी बटन की स्थिति का कलेक्शन.

ध्यान दें कि बटन डिजिटल (दबाया गया या नहीं दबाया गया) या एनालॉग (उदाहरण के लिए, 78% दबाया गया) हो सकते हैं. इसलिए, बटन को GamepadButton ऑब्जेक्ट के तौर पर रिपोर्ट किया जाता है. इनमें ये एट्रिब्यूट होते हैं:

  • pressed: बटन की दबाव वाली स्थिति (true अगर बटन दबाया गया है और false अगर बटन दबाया नहीं गया है.
  • touched: बटन को छूने पर उसकी स्थिति. अगर बटन को छूने पर उसकी स्थिति का पता चलता है, तो इस प्रॉपर्टी की वैल्यू true होती है. अगर बटन को छुआ नहीं जा रहा है, तो इसकी वैल्यू false होती है.
  • value: जिन बटन में एनालॉग सेंसर होता है उनके लिए, यह प्रॉपर्टी यह दिखाती है कि बटन को कितनी बार दबाया गया है. यह वैल्यू, 0.0 से 1.0 की रेंज में होती है.
  • hapticActuators: यह एक कलेक्शन है, जिसमें GamepadHapticActuator ऑब्जेक्ट शामिल होते हैं. हर ऑब्जेक्ट, कंट्रोलर पर उपलब्ध हैप्टिक फ़ीडबैक हार्डवेयर को दिखाता है.

आपके ब्राउज़र और गेमपैड के हिसाब से, आपको एक और चीज़ दिख सकती है. वह vibrationActuator प्रॉपर्टी है. इसमें दो तरह के रंबल इफ़ेक्ट इस्तेमाल किए जा सकते हैं:

  • ड्यूअल-रंबल: गेमपैड की हर ग्रिप में एक-एक एक्ससेंट्रिक रोटेटिंग मैस ऐक्चुएटर होता है. इनसे, गेमप्ले के दौरान होने वाली हर गतिविधि के हिसाब से, गेमपैड में हैप्टिक फ़ीडबैक इफ़ेक्ट जनरेट होता है.
  • ट्रिगर-रंबल: दो अलग-अलग मोटर से जनरेट होने वाला हैप्टिक फ़ीडबैक इफ़ेक्ट. गेमपैड के हर ट्रिगर में एक मोटर होती है.

यहां दी गई स्कीमैटिक खास जानकारी, स्पेसिफ़िकेशन से सीधे तौर पर ली गई है. इसमें, किसी सामान्य गेमपैड पर बटन और ऐक्सिस की मैपिंग और व्यवस्था को दिखाया गया है.

सामान्य गेमपैड के बटन और ऐक्सिस मैपिंग की स्कीमैटिक खास जानकारी.
स्टैंडर्ड गेमपैड लेआउट का विज़ुअल (सोर्स).

गेमपैड कनेक्ट होने पर सूचना पाना

गेमपैड के कनेक्ट होने का पता लगाने के लिए, window ऑब्जेक्ट पर ट्रिगर होने वाले gamepadconnected इवेंट को सुनें. जब उपयोगकर्ता किसी गेमपैड को कनेक्ट करता है, तो एक GamepadEvent ट्रिगर होता है. इसमें गेमपैड की जानकारी, सही नाम वाली gamepad प्रॉपर्टी में होती है. गेमपैड को यूएसबी या ब्लूटूथ से कनेक्ट किया जा सकता है. यहां Xbox 360 कंट्रोलर का एक उदाहरण दिया गया है. यह कंट्रोलर मेरे पास पहले से था (हां, मुझे पुराने गेम खेलने में दिलचस्पी है).

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"}
  */
});

गेमपैड के डिसकनेक्ट होने पर सूचना

गेमपैड के कनेक्ट होने का पता लगाने के तरीके से ही, उसके डिसकनेक्ट होने की सूचना मिलती है. इस बार ऐप्लिकेशन, gamepaddisconnected इवेंट को सुनता है. नीचे दिए गए उदाहरण में देखें कि Xbox 360 कंट्रोलर को अनप्लग करने पर, connected अब false हो गया है.

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
  */
});

आपके गेम लूप में गेमपैड

गेमपैड को ऐक्सेस करने के लिए, navigator.getGamepads() को कॉल किया जाता है. इससे Gamepad आइटम वाला कलेक्शन मिलता है. Chrome में मौजूद कलेक्शन में, हमेशा चार आइटम होते हैं. अगर कोई गेमपैड नहीं जुड़ा है या चार से कम गेमपैड जुड़े हैं, तो आइटम सिर्फ़ null हो सकता है. हमेशा ऐरे के सभी आइटम की जांच करना न भूलें. साथ ही, ध्यान रखें कि गेमपैड अपने स्लॉट को "याद रखते हैं" और हो सकता है कि वे हमेशा पहले उपलब्ध स्लॉट में मौजूद न हों.

// When no gamepads are connected:
navigator.getGamepads();
// (4) [null, null, null, null]

अगर एक या उससे ज़्यादा गेमपैड कनेक्ट हैं, लेकिन navigator.getGamepads() अब भी null आइटम की जानकारी दिखाता है, तो हो सकता है कि आपको हर गेमपैड के किसी बटन को दबाकर उसे "जागृत" करना पड़े. इसके बाद, गेम लूप में गेमपैड के स्टेटस को पोल किया जा सकता है, जैसा कि नीचे दिए गए कोड में दिखाया गया है.

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();

वाइब्रेशन ऐक्चुएटर

vibrationActuator प्रॉपर्टी, GamepadHapticActuator ऑब्जेक्ट दिखाती है. यह मोटर या अन्य ऐक्चुएटर के कॉन्फ़िगरेशन से जुड़ा होता है. ये ऐक्चुएटर, हैप्टिक फ़ीडबैक के लिए किसी चीज़ पर दबाव डाल सकते हैं. Gamepad.vibrationActuator.playEffect() को दबाकर, वाइब्रेशन इफ़ेक्ट चलाए जा सकते हैं. इफ़ेक्ट के लिए सिर्फ़ 'dual-rumble' और 'trigger-rumble' टाइप का इस्तेमाल किया जा सकता है.

काम करने वाले रंबल इफ़ेक्ट

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.
}

ड्यूअल रंबल

ड्यूअल-रंबल, स्टैंडर्ड गेमपैड के हर हैंडल में एक असामान्य घूमने वाले वाइब्रेशन मोटर के साथ, हैप्टिक कॉन्फ़िगरेशन के बारे में बताता है. इस कॉन्फ़िगरेशन में, दोनों मोटर पूरे गेमपैड को वाइब्रेट कर सकती हैं. दोनों मैस अलग-अलग होते हैं, ताकि हर मैस के असर को जोड़कर, ज़्यादा जटिल हैप्टिक असर बनाए जा सकें. ड्यूअल-रंबल इफ़ेक्ट को चार पैरामीटर से तय किया जाता है:

  • duration: वाइब्रेशन इफ़ेक्ट की अवधि को मिलीसेकंड में सेट करता है.
  • startDelay: वाइब्रेशन शुरू होने में लगने वाले समय को सेट करता है.
  • strongMagnitude और weakMagnitude: ज़्यादा और कम वज़न वाले एक्ससेंट्रिक रोटेट मैस मोटर के लिए, वाइब्रेशन की तीव्रता के लेवल सेट करें. इन लेवल को 0.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,
  });
};

ट्रिगर रंबल

ट्रिगर रंबल, दो अलग-अलग मोटर से जनरेट होने वाला हैप्टिक फ़ीडबैक इफ़ेक्ट है. गेमपैड के हर ट्रिगर में एक मोटर होती है.

// 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,
  });
};

अनुमतियों की नीति के साथ इंटिग्रेशन

Gamepad API स्पेसिफ़िकेशन में, नीति से कंट्रोल की जाने वाली सुविधा के बारे में बताया गया है. इस सुविधा की पहचान, "gamepad" स्ट्रिंग से की जाती है. इसका डिफ़ॉल्ट allowlist "self" होता है. दस्तावेज़ की अनुमतियों की नीति से यह तय होता है कि उस दस्तावेज़ के किसी कॉन्टेंट को navigator.getGamepads() को ऐक्सेस करने की अनुमति है या नहीं. अगर किसी दस्तावेज़ में यह सुविधा बंद है, तो उस दस्तावेज़ के किसी भी कॉन्टेंट को navigator.getGamepads() का इस्तेमाल करने की अनुमति नहीं होगी. साथ ही, gamepadconnected और gamepaddisconnected इवेंट ट्रिगर नहीं होंगे.

<iframe src="index.html" allow="gamepad"></iframe>

डेमो

यहां दिए गए उदाहरण में, गेमपैड टेस्टर का डेमो एम्बेड किया गया है. सोर्स कोड, Glitch पर उपलब्ध है. यूएसबी या ब्लूटूथ का इस्तेमाल करके गेमपैड को कनेक्ट करें और उसके किसी बटन को दबाएं या उसके किसी अक्ष को घुमाएं. ऐसा करने पर, आपको डेमो दिखेगा.

बोनस: web.dev पर Chrome डायनो गेम खेलना

इस साइट पर, गेमपैड की मदद से Chrome डायनो गेम खेला जा सकता है. सोर्स कोड GitHub पर उपलब्ध है. trex-runner.js में गेमपैड पोलिंग लागू करने का तरीका देखें और ध्यान दें कि यह बटन दबाने की कार्रवाई को कैसे एमुलेट कर रहा है.

Chrome डायनोसोर गेमपैड के डेमो को काम करने के लिए, मैंने Chrome डायनोसोर गेम को मुख्य Chromium प्रोजेक्ट से हटा दिया है. साथ ही, अर्नेल बेलन के पहले प्रयास को अपडेट किया है. इसके बाद, मैंने इसे एक अलग साइट पर डाल दिया है. साथ ही, डकिंग और वाइब्रेशन इफ़ेक्ट जोड़कर, गेमपैड एपीआई के मौजूदा वर्शन को बेहतर बनाया है. इसके बाद, मैंने फ़ुल स्क्रीन मोड बनाया है. साथ ही, मेहुल सतर्डेकर ने डार्क मोड को लागू करने में मदद की है. गेमिंग का आनंद लें!

आभार

इस दस्तावेज़ की समीक्षा फ़्रांकोइस बफ़ोर और जो मेडली ने की है. Gamepad API स्पेसिफ़िकेशन में बदलाव करने वाले लोगों में स्टीव अगस्टन, जेम्स होलीयर, और मैट रेनॉल्ड्स शामिल हैं. स्पेसिफ़िकेशन के पूर्व एडिटर, ब्रैंडन जोन्स, स्कॉट ग्राहम, और टेड मिएल्ज़ारेक हैं. गेमपैड एक्सटेंशन स्पेसिफ़िकेशन में बदलाव, ब्रैंडन जोन्स ने किया है. हीरो इमेज, लारा टोरेंट पुइग की है.