HTML5 गेम के लिए आसान एसेट मैनेजमेंट

परिचय

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

इस लेख में, अपने HTML5 गेम के लिए एसेट मैनेजमेंट का आसान कॉम्पोनेंट बनाने का तरीका बताया गया है. एसेट मैनेजर के बिना, आपके गेम को डाउनलोड होने में लगने वाले समय और अलग-अलग समय पर लोड होने वाली इमेज को मैनेज करने में मुश्किल होगी. अपने HTML5 गेम के लिए, आसान ऐसेट मैनेजर का उदाहरण देखने के लिए यह लेख पढ़ें.

समस्या

HTML5 गेम में यह नहीं माना जा सकता कि इमेज या ऑडियो जैसी एसेट, प्लेयर की लोकल मशीन पर मौजूद होंगी. ऐसा इसलिए, क्योंकि HTML5 गेम को वेब ब्राउज़र में चलाया जाता है और उनकी एसेट, एचटीटीपी के ज़रिए डाउनलोड की जाती हैं. नेटवर्क की वजह से, ब्राउज़र को यह पता नहीं होता कि गेम की ऐसेट कब डाउनलोड होंगी और कब उपलब्ध होंगी.

वेब ब्राउज़र में प्रोग्राम के हिसाब से इमेज लोड करने का बुनियादी तरीका यह कोड है:

var image = new Image();
image.addEventListener("success", function(e) {
  // do stuff with the image
});
image.src = "/some/image.png";

अब कल्पना करें कि आपके पास सौ इमेज हैं, जिन्हें गेम शुरू होने पर लोड और दिखाया जाना है. आपको कैसे पता चलेगा कि सभी 100 इमेज तैयार हो गई हैं? क्या सभी आइटम लोड हो गए? गेम कब शुरू होना चाहिए?

समस्या का हल

एसेट मैनेजर को एसेट की सूची मैनेज करने दें. साथ ही, जब सब कुछ तैयार हो जाए, तब गेम को सूचना दें. ऐसेट मैनेजर, नेटवर्क पर ऐसेट लोड करने के लिए लॉजिक को सामान्य बनाता है. साथ ही, यह ऐसेट के स्टेटस की जांच करने का आसान तरीका भी उपलब्ध कराता है.

हमारे आसान ऐसेट मैनेजर के लिए ये ज़रूरी शर्तें हैं:

  • डाउनलोड की सूची बनाना
  • डाउनलोड शुरू करना
  • यह ट्रैक करना कि फ़ीड सफल रहा है या नहीं
  • सब कुछ पूरा हो जाने पर सिग्नल भेजता है
  • ऐसेट को आसानी से वापस पाना

कतार में शामिल किया जा रहा है

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

कन्स्ट्रक्टर और कतार में जोड़ने का कोड ऐसा दिखता है:

function AssetManager() {
  this.downloadQueue = [];
}

AssetManager.prototype.queueDownload = function(path) {
    this.downloadQueue.push(path);
}

डाउनलोड शुरू करना

डाउनलोड की जाने वाली सभी ऐसेट को सूची में जोड़ने के बाद, ऐसेट मैनेजर से सभी ऐसेट डाउनलोड करने के लिए कहा जा सकता है.

वेब ब्राउज़र, एक साथ कई फ़ाइलें डाउनलोड कर सकता है. आम तौर पर, हर होस्ट के लिए चार कनेक्शन तक डाउनलोड किए जा सकते हैं. ऐसेट को डाउनलोड करने की रफ़्तार बढ़ाने का एक तरीका यह है कि ऐसेट होस्ट करने के लिए, कई डोमेन नेम का इस्तेमाल किया जाए. उदाहरण के लिए, assets.example.com से सभी एसेट दिखाने के बजाय, assets1.example.com, assets2.example.com, assets3.example.com वगैरह का इस्तेमाल करें. भले ही, उनमें से हर डोमेन नेम एक ही वेब सर्वर का CNAME हो, लेकिन वेब ब्राउज़र उन्हें अलग-अलग सर्वर के तौर पर देखता है. साथ ही, एसेट डाउनलोड करने के लिए इस्तेमाल किए जाने वाले कनेक्शन की संख्या बढ़ा देता है. अपनी वेबसाइट की स्पीड बढ़ाने के सबसे सही तरीकों के बारे में जानने के लिए, अलग-अलग डोमेन में कॉम्पोनेंट को बांटना लेख पढ़ें. इस लेख में, इस तकनीक के बारे में ज़्यादा जानकारी दी गई है.

डाउनलोड शुरू करने के हमारे तरीके को downloadAll() कहा जाता है. हम इसे समय के साथ बेहतर बनाते रहेंगे. फ़िलहाल, डाउनलोड शुरू करने के लिए पहला लॉजिक यहां दिया गया है.

AssetManager.prototype.downloadAll = function() {
    for (var i = 0; i < this.downloadQueue.length; i++) {
        var path = this.downloadQueue[i];
        var img = new Image();
        var that = this;
        img.addEventListener("load", function() {
            // coming soon
        }, false);
        img.src = path;
    }
}

ऊपर दिए गए कोड में देखा जा सकता है कि downloadAll(), downloadQueue में मौजूद सभी आइटम को क्रम से चलाता है और एक नया Image ऑब्जेक्ट बनाता है. लोड इवेंट के लिए एक इवेंट लिसनर जोड़ा जाता है और इमेज का src सेट किया जाता है, जो असल डाउनलोड को ट्रिगर करता है.

इस तरीके से डाउनलोड शुरू किए जा सकते हैं.

यह ट्रैक करना कि फ़ीड सफल रहा है या नहीं

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

AssetManager.prototype.downloadAll = function(downloadCallback) {
  for (var i = 0; i < this.downloadQueue.length; i++) {
    var path = this.downloadQueue[i];
    var img = new Image();
    var that = this;
    img.addEventListener("load", function() {
        // coming soon
    }, false);
    img.addEventListener("error", function() {
        // coming soon
    }, false);
    img.src = path;
  }
}

हमारे एसेट मैनेजर को यह जानना होगा कि हमें कितनी सफलताएं मिलीं और कितनी बार हम असफल हुए. ऐसा न करने पर, उसे कभी नहीं पता चलेगा कि गेम कब शुरू हो सकता है.

सबसे पहले, हम कन्स्ट्रक्टर में ऑब्जेक्ट में काउंटर जोड़ेंगे, जो अब इस तरह दिखेगा:

function AssetManager() {
<span class="highlight">    this.successCount = 0;
    this.errorCount = 0;</span>
    this.downloadQueue = [];
}

इसके बाद, इवेंट लिसनर में काउंटर बढ़ाएं, जो अब इस तरह दिखते हैं:

img.addEventListener("load", function() {
    <span class="highlight">that.successCount += 1;</span>
}, false);
img.addEventListener("error", function() {
    <span class="highlight">that.errorCount += 1;</span>
}, false);

ऐसेट मैनेजर अब, सफलतापूर्वक लोड हुई और लोड न हुई ऐसेट, दोनों को ट्रैक कर रहा है.

'पूरा होने पर सिग्नल भेजें'

गेम में ऐसेट को डाउनलोड करने के लिए कतार में लगाने और ऐसेट मैनेजर से सभी ऐसेट डाउनलोड करने के लिए कहने के बाद, गेम को यह बताना होगा कि सभी ऐसेट डाउनलोड हो गई हैं. गेम में एसेट डाउनलोड हो गई हैं या नहीं, यह बार-बार पूछने के बजाय, एसेट मैनेजर गेम को इसकी सूचना दे सकता है.

ऐसेट मैनेजर को सबसे पहले यह पता होना चाहिए कि हर ऐसेट कब पूरी हो जाएगी. हम अब isDone तरीका जोड़ेंगे:

AssetManager.prototype.isDone = function() {
    return (this.downloadQueue.length == this.successCount + this.errorCount);
}

successCount + errorCount की तुलना downloadQueue के साइज़ से करके, ऐसेट मैनेजर को पता चलता है कि हर ऐसेट पूरी हो गई है या उसमें कोई गड़बड़ी हुई है.

हालांकि, यह जानना कि यह काम हो गया है, सिर्फ़ आधी लड़ाई है. एसेट मैनेजर को भी इस तरीके की जांच करनी होगी. हम इस जांच को अपने दोनों इवेंट हैंडलर में जोड़ देंगे, जैसा कि नीचे दिए गए कोड में दिखाया गया है:

img.addEventListener("load", function() {
    console.log(this.src + ' is loaded');
    that.successCount += 1;
    if (that.isDone()) {
        // ???
    }
}, false);
img.addEventListener("error", function() {
    that.errorCount += 1;
if (that.isDone()) {
        // ???
    }
}, false);

काउंटर बढ़ने के बाद, हम देखेंगे कि क्या यह हमारी सूची में मौजूद आखिरी एसेट है. अगर एसेट मैनेजर डाउनलोड हो गया है, तो हमें क्या करना चाहिए?

अगर ऐसेट मैनेजर सभी ऐसेट डाउनलोड कर लेता है, तो हम कॉलबैक का तरीका ज़रूर इस्तेमाल करेंगे! आइए, downloadAll() को बदलकर कॉलबैक के लिए पैरामीटर जोड़ें:

AssetManager.prototype.downloadAll = function(downloadCallback) {
    ...

हम अपने इवेंट लिसनर में downloadCallback मैथड को कॉल करेंगे:

img.addEventListener("load", function() {
    that.successCount += 1;
    if (that.isDone()) {
        downloadCallback();
    }
}, false);
img.addEventListener("error", function() {
    that.errorCount += 1;
    if (that.isDone()) {
        downloadCallback();
    }
}, false);

एसेट मैनेजर, आखिरी ज़रूरी शर्त के लिए तैयार है.

ऐसेट को आसानी से वापस पाना

गेम शुरू करने का सिग्नल मिलने के बाद, गेम इमेज रेंडर करना शुरू कर देगा. ऐसेट मैनेजर की ज़िम्मेदारी, ऐसेट को डाउनलोड और ट्रैक करने के साथ-साथ उन्हें गेम में उपलब्ध कराना भी होती है.

हमारी आखिरी ज़रूरी शर्त के मुताबिक, आपको getAsset का कोई तरीका इस्तेमाल करना होगा. इसलिए, हम इसे अभी जोड़ेंगे:

AssetManager.prototype.getAsset = function(path) {
    return this.cache[path];
}

इस कैश ऑब्जेक्ट को कंस्ट्रक्टर में शुरू किया जाता है, जो अब ऐसा दिखता है:

function AssetManager() {
    this.successCount = 0;
    this.errorCount = 0;
    this.cache = {};
    this.downloadQueue = [];
}

कैश मेमोरी, downloadAll() के आखिर में पॉप्युलेट होती है, जैसा कि यहां दिखाया गया है:

AssetManager.prototype.downloadAll = function(downloadCallback) {
  ...
      img.addEventListener("error", function() {
          that.errorCount += 1;
          if (that.isDone()) {
              downloadCallback();
          }
      }, false);
      img.src = path;
      <span class="highlight">this.cache[path] = img;</span>
  }
}

बोनस: बग ठीक करना

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

downloadAll() में यह कोड जोड़कर, इस स्थिति को मैनेज किया जा सकता है:

AssetManager.prototype.downloadAll = function(downloadCallback) {
    if (this.downloadQueue.length === 0) {
      downloadCallback();
  }
 ...

अगर कोई एसेट कतार में नहीं है, तो कॉलबैक तुरंत कॉल किया जाता है. गड़बड़ी ठीक कर दी गई है!

इस्तेमाल का उदाहरण

अपने HTML5 गेम में इस ऐसेट मैनेजर का इस्तेमाल करना काफ़ी आसान है. लाइब्रेरी का इस्तेमाल करने का सबसे बुनियादी तरीका यहां बताया गया है:

var ASSET_MANAGER = new AssetManager();

ASSET_MANAGER.queueDownload('img/earth.png');

ASSET_MANAGER.downloadAll(function() {
    var sprite = ASSET_MANAGER.getAsset('img/earth.png');
    ctx.drawImage(sprite, x - sprite.width/2, y - sprite.height/2);
});

ऊपर दिए गए कोड से पता चलता है कि:

  1. नया ऐसेट मैनेजर बनाता है
  2. डाउनलोड की जाने वाली ऐसेट की सूची बनाना
  3. downloadAll() से डाउनलोड शुरू करें
  4. कॉलबैक फ़ंक्शन को ट्रिगर करके, एसेट के तैयार होने का सिग्नल देना
  5. getAsset() की मदद से ऐसेट वापस पाना

जिन सेक्शन में सुधार की ज़रूरत है

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

  • यह बताना कि किस ऐसेट में गड़बड़ी हुई है
  • प्रोग्रेस दिखाने के लिए कॉलबैक
  • फ़ाइल सिस्टम एपीआई से ऐसेट हासिल करना

कृपया नीचे दी गई टिप्पणियों में, कोड में किए गए सुधारों, फ़ॉर्क, और लिंक पोस्ट करें.

पूरा सोर्स

इस एसेट मैनेजर और उस गेम का सोर्स, Apache लाइसेंस के तहत ओपन सोर्स है. इसे Bad Aliens के GitHub खाते में देखा जा सकता है. Bad Aliens गेम को HTML5 के साथ काम करने वाले ब्राउज़र में खेला जा सकता है. इस गेम के बारे में मैंने Google IO में बात की थी. इस बातचीत का टाइटल था, Super Browser 2 Turbo HD Remix: Introduction to HTML5 Game Development (स्लाइड, वीडियो).

खास जानकारी

ज़्यादातर गेम में किसी तरह का ऐसेट मैनेजर होता है. हालांकि, HTML5 गेम के लिए ऐसे ऐसेट मैनेजर की ज़रूरत होती है जो नेटवर्क पर ऐसेट लोड करता हो और गड़बड़ियों को मैनेज करता हो. इस लेख में, एक आसान एसेट मैनेजर के बारे में बताया गया है. इसे इस्तेमाल करना और अपने अगले HTML5 गेम के लिए अडैप्ट करना आसान होगा. इसका आनंद लें और कृपया नीचे टिप्पणी करके हमें बताएं कि आपकी इस सुविधा के बारे में क्या राय है. धन्यवाद!