पॉइंटर लॉक और फ़र्स्ट पर्सन शूटर कंट्रोल

परिचय

Pointer Lock API, ब्राउज़र गेम में फ़र्स्ट-पर्सन शूटर कंट्रोल को सही तरीके से लागू करने में मदद करता है. उदाहरण के लिए, माउस की रिलेटिव मूवमेंट के बिना, प्लेयर का कर्सर स्क्रीन के दाएं किनारे पर जा सकता है और दाईं ओर की कोई भी आगे की मूवमेंट को अनदेखा कर दिया जाएगा - व्यू दाईं ओर पैन नहीं होता रहेगा और प्लेयर बुरे लोगों का पीछा नहीं कर पाएगा और अपनी मशीन गन से उन्हें स्ट्राफ़ नहीं कर पाएगा. खिलाड़ी को मार दिया जाएगा और वह परेशान हो जाएगा. पॉइंटर लॉक की सुविधा चालू होने पर, ऐसा नहीं होता.

पॉइंटर लॉक एपीआई की मदद से, आपके ऐप्लिकेशन को ये काम करने की अनुमति मिलती है:

  • माउस के रॉ डेटा का ऐक्सेस पाना. इसमें माउस की रिलेटिव गतिविधियां भी शामिल हैं
  • सभी माउस इवेंट को किसी खास एलिमेंट पर भेजना

पॉइंटर लॉक की सुविधा चालू करने पर, माउस कर्सर छिप जाता है. इससे, आपके पास ऐप्लिकेशन के हिसाब से पॉइंटर बनाने का विकल्प होता है. इसके अलावा, माउस कर्सर को छिपाकर भी रखा जा सकता है, ताकि उपयोगकर्ता माउस से फ़्रेम को मूव कर सके. माउस की रिलेटिव मूवमेंट, माउस पॉइंटर की पिछली फ़्रेम की पोज़िशन के डेल्टा को दिखाती है. भले ही, माउस की सटीक पोज़िशन कुछ भी हो. उदाहरण के लिए, अगर माउस पॉइंटर (640, 480) से (520, 490) पर चला गया, तो रिलेटिव मूवमेंट (-120, 10) था. माउस की रॉ पोज़िशन के डेल्टा दिखाने वाला इंटरैक्टिव उदाहरण नीचे देखें.

इस ट्यूटोरियल में दो विषयों के बारे में बताया गया है: पॉइंटर लॉक इवेंट को चालू और प्रोसेस करने के बारे में पूरी जानकारी और फ़र्स्ट-पर्सन शूटर कंट्रोल स्कीम को लागू करने के बारे में जानकारी. हां, इस लेख को पढ़ने के बाद, आपको पॉइंटर लॉक का इस्तेमाल करने और अपने ब्राउज़र गेम के लिए Quake-style कंट्रोल लागू करने का तरीका पता चल जाएगा!

ब्राउज़र के साथ काम करना

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 37.
  • Edge: 13.
  • Firefox: 50.
  • Safari: 10.1.

सोर्स

पॉइंटर लॉक की सुविधा के काम करने का तरीका

फ़ीचर का पता लगाना

यह पता लगाने के लिए कि उपयोगकर्ता के ब्राउज़र में पॉइंटर लॉक की सुविधा काम करती है या नहीं, आपको दस्तावेज़ ऑब्जेक्ट में pointerLockElement या वेंडर के प्रीफ़िक्स वाला वर्शन देखना होगा. कोड में:

var havePointerLock = 'pointerLockElement' in document ||
    'mozPointerLockElement' in document ||
    'webkitPointerLockElement' in document;

फ़िलहाल, पॉइंटर लॉक की सुविधा सिर्फ़ Firefox और Chrome में उपलब्ध है. Opera और IE पर, फ़िलहाल यह सुविधा काम नहीं करती.

सक्रिय कर रहा है

पॉइंटर लॉक को चालू करने की प्रोसेस दो चरणों में होती है. सबसे पहले, आपका ऐप्लिकेशन किसी खास एलिमेंट के लिए पॉइंटर लॉक चालू करने का अनुरोध करता है. इसके बाद, उपयोगकर्ता की अनुमति मिलने के तुरंत बाद, pointerlockchange इवेंट ट्रिगर होता है. उपयोगकर्ता, किसी भी समय Escape बटन दबाकर पॉइंटर लॉक की सुविधा को बंद कर सकता है. आपका ऐप्लिकेशन, प्रोग्राम के हिसाब से भी पॉइंटर लॉक से बाहर निकल सकता है. पॉइंटर लॉक रद्द होने पर, pointerlockchange इवेंट ट्रिगर होता है.

element.requestPointerLock = element.requestPointerLock ||
                 element.mozRequestPointerLock ||
                 element.webkitRequestPointerLock;
// Ask the browser to lock the pointer
element.requestPointerLock();

// Ask the browser to release the pointer
document.exitPointerLock = document.exitPointerLock ||
               document.mozExitPointerLock ||
               document.webkitExitPointerLock;
document.exitPointerLock();

इसके लिए, ऊपर दिया गया कोड ही काफ़ी है. जब ब्राउज़र पॉइंटर को लॉक करेगा, तो एक बबल पॉप-अप होगा. इसमें उपयोगकर्ता को यह जानकारी दी जाएगी कि आपके ऐप्लिकेशन ने पॉइंटर को लॉक कर दिया है. साथ ही, उन्हें यह निर्देश भी दिया जाएगा कि वे 'Esc' बटन दबाकर, इसे रद्द कर सकते हैं.

Chrome में पॉइंटर लॉक की जानकारी देने वाला बार.
Chrome में पॉइंटर लॉक की जानकारी देने वाला बार.

इवेंट मैनेज करना

आपके ऐप्लिकेशन को दो इवेंट के लिए, लिसनर जोड़ने होंगे. पहला pointerlockchange है, जो पॉइंटर लॉक की स्थिति में बदलाव होने पर ट्रिगर होता है. दूसरा mousemove है, जो माउस के हिलने पर ट्रिगर होता है.

// Hook pointer lock state change events
document.addEventListener('pointerlockchange', changeCallback, false);
document.addEventListener('mozpointerlockchange', changeCallback, false);
document.addEventListener('webkitpointerlockchange', changeCallback, false);

// Hook mouse move events
document.addEventListener("mousemove", this.moveCallback, false);

आपको अपने pointerlockchange कॉलबैक में यह देखना होगा कि पॉइंटर अभी लॉक किया गया है या अनलॉक किया गया है. यह पता लगाना आसान है कि पॉइंटर लॉक चालू था या नहीं: देखें कि document.pointerLockElement, उस एलिमेंट से मेल खाता है या नहीं जिसके लिए पॉइंटर लॉक का अनुरोध किया गया था. अगर यह वैल्यू 'सही' है, तो इसका मतलब है कि आपके ऐप्लिकेशन ने पॉइंटर को लॉक कर दिया है. अगर यह वैल्यू 'गलत' है, तो इसका मतलब है कि उपयोगकर्ता या आपके कोड ने पॉइंटर को अनलॉक कर दिया है.

if (document.pointerLockElement === requestedElement ||
  document.mozPointerLockElement === requestedElement ||
  document.webkitPointerLockElement === requestedElement) {
  // Pointer was just locked
  // Enable the mousemove listener
  document.addEventListener("mousemove", this.moveCallback, false);
} else {
  // Pointer was just unlocked
  // Disable the mousemove listener
  document.removeEventListener("mousemove", this.moveCallback, false);
  this.unlockHook(this.element);
}

पॉइंटर लॉक चालू होने पर, clientX, clientY, screenX, और screenY की वैल्यू में कोई बदलाव नहीं होता. movementX और movementY को, पिछले इवेंट डिलीवर होने के बाद से, पिक्सल की उस संख्या के साथ अपडेट किया जाता है जो पॉइंटर ने मूव किया होगा. स्यूडो कोड में:

event.movementX = currentCursorPositionX - previousCursorPositionX;
event.movementY = currentCursorPositionY - previousCursorPositionY;

mousemove कॉलबैक में, इवेंट के movementX और movementY फ़ील्ड से माउस की गति का डेटा निकाला जा सकता है.

function moveCallback(e) {
  var movementX = e.movementX ||
      e.mozMovementX          ||
      e.webkitMovementX       ||
      0,
  movementY = e.movementY ||
      e.mozMovementY      ||
      e.webkitMovementY   ||
      0;
}

गड़बड़ियों का पता लगाना

अगर पॉइंटर लॉक में जाकर या उससे बाहर निकलने पर कोई गड़बड़ी होती है, तो pointerlockerror इवेंट ट्रिगर होता है. इस इवेंट में कोई डेटा अटैच नहीं है.

document.addEventListener('pointerlockerror', errorCallback, false);
document.addEventListener('mozpointerlockerror', errorCallback, false);
document.addEventListener('webkitpointerlockerror', errorCallback, false);

क्या फ़ुल-स्क्रीन मोड ज़रूरी है?

मूल रूप से, पॉइंटर लॉक को FullScreen API से जोड़ा गया था. इसका मतलब है कि किसी एलिमेंट पर कर्सर लॉक करने से पहले, उसे फ़ुलस्क्रीन मोड में होना चाहिए. अब ऐसा नहीं है. पॉइंटर लॉक का इस्तेमाल, आपके ऐप्लिकेशन के किसी भी एलिमेंट के लिए किया जा सकता है, चाहे वह फ़ुल स्क्रीन में हो या नहीं.

फ़र्स्ट-पर्सन शूटर गेम के कंट्रोल का उदाहरण

अब हमने पॉइंटर लॉक चालू कर दिया है और हमें इवेंट मिल रहे हैं. अब इसका एक उदाहरण देखें. क्या आपको कभी यह जानना है कि Quake में कंट्रोल कैसे काम करते हैं? थोड़ा इंतज़ार करें, क्योंकि अब हम आपको कोड के ज़रिए इनके बारे में बताने जा रहे हैं!

फ़र्स्ट-पर्सन शूटर गेम के कंट्रोल, चार मुख्य मैकेनिक्स के आधार पर बनाए जाते हैं:

  • मौजूदा लुक वेक्टर के साथ आगे और पीछे जाना
  • मौजूदा स्ट्राफ़ वेक्टर के साथ बाईं और दाईं ओर जाना
  • व्यू को याव (बाईं और दाईं ओर) घुमाना
  • व्यू पिच को घुमाना (ऊपर और नीचे)

इस कंट्रोल स्कीम को लागू करने वाले गेम को सिर्फ़ तीन तरह के डेटा की ज़रूरत होती है: कैमरे की पोज़िशन, कैमरे का लुक वेक्टर, और एक अप वेक्टर. अप वेक्टर हमेशा (0, 1, 0) होता है. ऊपर बताए गए चारों तरीके, कैमरे की पोज़िशन और कैमरे के लुक वेक्टर में अलग-अलग तरीके से बदलाव करते हैं.

हलचल

सबसे पहले, मूवमेंट की जानकारी. नीचे दिए गए डेमो में, मूवमेंट को स्टैंडर्ड W, A, S, और D बटन पर मैप किया गया है. W और S बटन से कैमरे को आगे और पीछे ले जाया जा सकता है. वहीं, A और D बटन से कैमरे को बाईं और दाईं ओर घुमाया जा सकता है. कैमरे को आगे और पीछे ले जाना आसान है:

// Forward direction
var forwardDirection = vec3.create(cameraLookVector);
// Speed
var forwardSpeed = dt * cameraSpeed;
// Forward or backward depending on keys held
var forwardScale = 0.0;
forwardScale += keyState.W ? 1.0 : 0.0;
forwardScale -= keyState.S ? 1.0 : 0.0;
// Scale movement
vec3.scale(forwardDirection, forwardScale * forwardSpeed);
// Add scaled movement to camera position
vec3.add(cameraPosition, forwardDirection);

बाईं और दाईं ओर जाने के लिए, स्ट्राफ़ करने की दिशा तय करनी होगी. क्रॉस प्रॉडक्ट का इस्तेमाल करके, स्ट्रैफ़ की दिशा का हिसाब लगाया जा सकता है:

// Strafe direction
var strafeDirection = vec3.create();
vec3.cross(cameraLookVector, cameraUpVector, strafeDirection);

स्ट्रैफ़ की दिशा तय करने के बाद, स्ट्रैफ़ मूवमेंट को लागू करना, आगे या पीछे जाने जैसा ही होता है.

अगला चरण, व्यू को घुमाना है.

यॉ

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

// Extract camera look vector
var frontDirection = vec3.create();
vec3.subtract(this.lookAtPoint, this.eyePoint, frontDirection);
vec3.normalize(frontDirection);
var q = quat4.create();
// Construct quaternion
quat4.fromAngleAxis(deltaAngle, axis, q);
// Rotate camera look vector
quat4.multiplyVec3(q, frontDirection);
// Update camera look vector
this.lookAtPoint = vec3.create(this.eyePoint);
vec3.add(this.lookAtPoint, frontDirection);

पिच

कैमरे के व्यू में पिच या वर्टिकल रोटेशन लागू करने का तरीका एक जैसा है. हालांकि, अप वेक्टर के आस-पास रोटेशन के बजाय, आपको स्ट्राफ़ वेक्टर के आस-पास रोटेशन लागू करना होगा. पहला चरण, स्ट्राफ़ वेक्टर का हिसाब लगाना है. इसके बाद, कैमरे के लुक वेक्टर को उस अक्ष के चारों ओर घुमाएं.

खास जानकारी

Pointer Lock API की मदद से, माउस कर्सर को कंट्रोल किया जा सकता है. अगर वेब गेम बनाए जा रहे हैं, तो आपके गेम में खिलाड़ियों को फ़्रैग नहीं किया जाएगा. ऐसा इसलिए होगा, क्योंकि वे उत्साह में माउस को विंडो से बाहर ले जाते हैं और आपके गेम में माउस से जुड़े अपडेट नहीं मिलते. इसका इस्तेमाल करना आसान है:

  • पॉइंटर लॉक की स्थिति को ट्रैक करने के लिए, pointerlockchange इवेंट लिसनर जोड़ना
  • किसी खास एलिमेंट के लिए पॉइंटर लॉक का अनुरोध करना
  • अपडेट पाने के लिए, mousemove इवेंट लिसनर जोड़ना

बाहरी डेमो

रेफ़रंस