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

सेथ लैड

शुरुआती जानकारी

HTML5 ने ब्राउज़र में आधुनिक, रिस्पॉन्सिव, और असरदार वेब ऐप्लिकेशन बनाने के लिए कई उपयोगी एपीआई उपलब्ध कराए हैं. यह बढ़िया है, लेकिन आपको गेम बनाना और खेलना पसंद है! सौभाग्य से, HTML5 ने गेम डेवलपमेंट के नए युग की शुरुआत की है जो प्लगिन की आवश्यकता के बिना सीधे आपके ब्राउज़र पर गेमिंग डिलीवर करने के लिए कैनवस जैसे API और शक्तिशाली 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);
}

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

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

अच्छी बात यह है कि वेब ब्राउज़र, डाउनलोड के साथ-साथ फ़ाइलें अपलोड कर सकता है. आम तौर पर, हर होस्ट के लिए चार कनेक्शन हो सकते हैं. एसेट तेज़ी से डाउनलोड करने का एक तरीका यह है कि आप एसेट होस्टिंग के लिए कई तरह के डोमेन नेम का इस्तेमाल करें. उदाहरण के लिए, asset.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() बस डाउनलोडसूची की मदद से फिर से प्रोसेस करता है और एक नया इमेज ऑब्जेक्ट बनाता है. लोड इवेंट के लिए एक इवेंट लिसनर जोड़ दिया जाता है और इमेज का सोर्स सेट कर दिया जाता है, जो असल डाउनलोड को ट्रिगर करता है.

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

सफलता और विफलता को ट्रैक करना

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

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

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

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

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) {
    ...

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

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() की मदद से एसेट वापस पाएं

सुधार के क्षेत्र

इस बात में कोई शक नहीं है कि गेम बनाते समय, आपको इस आसान ऐसेट मैनेजर से आगे बढ़ने का मौका मिलेगा. हालांकि, उम्मीद है कि इससे आपको अच्छी शुरुआत मिलेगी. आने वाले समय में ये सुविधाएं मिल सकती हैं:

  • बताएं कि किस ऐसेट में कोई गड़बड़ी है
  • प्रोग्रेस दिखाने के लिए कॉलबैक
  • File System API से एसेट फ़ेच करना

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

पूरा स्रोत

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

खास जानकारी

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