केस स्टडी - Google I/O 2013 प्रयोग

थॉमस रेनॉल्ड्स
थॉमस रेनॉल्ड्स

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

कॉन्फ़्रेंस रजिस्ट्रेशन शुरू होने से पहले, Google I/O 2013 वेबसाइट पर डेवलपर की दिलचस्पी बढ़ाने के लिए, हमने टच इंटरैक्शन, जनरेटिव ऑडियो, और ज़्यादा गेम खोजने की खुशी पर फ़ोकस करते हुए मोबाइल-फ़र्स्ट एक्सपेरिमेंट और गेम की एक सीरीज़ डेवलप की है. कोड की क्षमता और खेलने की ताकत से प्रेरित इस इंटरैक्टिव अनुभव की शुरुआत, "I" और "O" की आसान आवाज़ों के साथ होती है. इस आवाज़ का इस्तेमाल तब किया जाता है, जब नए I/O लोगो पर टैप किया जाता है.

ऑर्गैनिक मोशन

हमने I और O ऐनिमेशन को एक अस्थिर, ऑर्गेनिक प्रभाव में लागू करने का फ़ैसला किया है जो अक्सर HTML5 इंटरैक्शन में नहीं देखा जाता. गेम को मज़ेदार और प्रतिक्रिया देने के लिए अलग-अलग विकल्प इस्तेमाल करने में थोड़ा समय लगा.

बाउंसी फ़िज़िक्स कोड का उदाहरण

इस इफ़ेक्ट को पूरा करने के लिए, हमने दो आकारों के किनारों को दिखाने वाले पॉइंट की सीरीज़ पर, भौतिकी के आसान सिम्युलेशन का इस्तेमाल किया. जब किसी भी आकार पर टैप किया जाता है, तो टैप की जगह से सभी बिंदुओं पर तेज़ी से टैप किया जाता है. वापस लगाए जाने से पहले, वे फैल जाते हैं और एक जगह से हट जाते हैं.

इंस्टैंशिएट करने पर, हर पॉइंट को एक तय क्रम में त्वरण की रकम और "बाउंसनेस" मिलता है, ताकि वे समान तरीके से ऐनिमेट न हों, जैसा कि इस कोड में देखा जा सकता है:

this.paperO_['vectors'] = [];

// Add an array of vector points and properties to the object.
for (var i = 0; i < this.paperO_['segments'].length; i++) {
  var point = this.paperO_['segments'][i]['point']['clone']();
  point = point['subtract'](this.oCenter);

  point['velocity'] = 0;
  point['acceleration'] = Math.random() * 5 + 10;
  point['bounce'] = Math.random() * 0.1 + 1.05;

  this.paperO_['vectors'].push(point);
}

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

for (var i = 0; i < path['vectors'].length; i++) {
  var point = path['vectors'][i];
  var vector;
  var distance;

  if (path === this.paperO_) {
    vector = point['add'](this.oCenter);
    vector = vector['subtract'](clickPoint);
    distance = Math.max(0, this.oRad - vector['length']);
  } else {
    vector = point['add'](this.iCenter);
    vector = vector['subtract'](clickPoint);
    distance = Math.max(0, this.iWidth - vector['length']);
  }

  point['length'] += Math.max(distance, 20);
  point['velocity'] += speed;
}

आखिर में, कोड में इस तरीके की मदद से, हर कण हर फ़्रेम पर धीमा हो जाता है और धीरे-धीरे संतुलन पर वापस आ जाता है:

for (var i = 0; i < path['segments'].length; i++) {
  var point = path['vectors'][i];
  var tempPoint = new paper['Point'](this.iX, this.iY);

  if (path === this.paperO_) {
    point['velocity'] = ((this.oRad - point['length']) /
      point['acceleration'] + point['velocity']) / point['bounce'];
  } else {
    point['velocity'] = ((tempPoint['getDistance'](this.iCenter) -
      point['length']) / point['acceleration'] + point['velocity']) /
      point['bounce'];
  }

  point['length'] = Math.max(0, point['length'] + point['velocity']);
}

ऑर्गैनिक मोशन डेमो

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

बचाव करना

होम मोड के मोशन से खुश होने के बाद, हम दो पुराने मोड के लिए इसी इफ़ेक्ट का इस्तेमाल करना चाहते थे: Eightbit और Ascii.

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

कैनवस "शेडर" कोड का उदाहरण

कैनवस पर मौजूद पिक्सल को getImageData तरीके का इस्तेमाल करके पढ़ा जा सकता है. दिखाए गए कलेक्शन में हर पिक्सल के लिए चार वैल्यू हैं. ये हर पिक्सल आरजीबीए वैल्यू को दिखाती हैं. ये पिक्सल, अरे जैसी विशाल संरचना में एक साथ जुड़े होते हैं. उदाहरण के लिए, 2x2 कैनवस के imageData कलेक्शन में 4 पिक्सल और 16 एंट्री होंगी.

हमारा कैनवस फ़ुल स्क्रीन मोड में है. इसलिए, अगर हम यह मान लेते हैं कि स्क्रीन 1024x768 (जैसे कि iPad पर) है, तो कलेक्शन में 31,45,728 एंट्री हैं. यह एक ऐनिमेशन है, इसलिए यह पूरी कैटगरी एक सेकंड में 60 बार अपडेट होती है. मॉडर्न JavaScript इंजन, लूपिंग को हैंडल कर सकते हैं और इतने डेटा पर कार्रवाई कर सकते हैं. इससे फ़्रेमरेट को एक जैसा रखा जा सकता है. (सलाह: उस डेटा को डेवलपर कंसोल में लॉग करने की कोशिश न करें. इससे आपके ब्राउज़र को क्रॉल नहीं किया जा सकेगा या उसे पूरी तरह से क्रैश कर दिया जाएगा.)

यहां बताया गया है कि हमारा Eightbit मोड, होम मोड कैनवस को कैसे पढ़ता है और ब्लॉकियर इफ़ेक्ट के लिए पिक्सल को उड़ा देता है:

var pixelData = pctx.getImageData(0, 0, sourceCanvas.width, sourceCanvas.height);

// tctx is the Target Context for the output Canvas element
tctx.clearRect(0, 0, targetCanvas.width + 1, targetCanvas.height + 1);

var size = ~~(this.width_ * 0.0625);

if (this.height_ * 6 < this.width_) {
 size /= 8;
}

var increment = Math.min(Math.round(size * 80) / 4, 980);

for (i = 0; i < pixelData.data.length; i += increment) {
  if (pixelData.data[i + 3] !== 0) {
    var r = pixelData.data[i];
    var g = pixelData.data[i + 1];
    var b = pixelData.data[i + 2];
    var pixel = Math.ceil(i / 4);
    var x = pixel % this.width_;
    var y = Math.floor(pixel / this.width_);

    var color = 'rgba(' + r + ', ' + g + ', ' + b + ', 1)';

    tctx.fillStyle = color;

    /**
     * The ~~ operator is a micro-optimization to round a number down
     * without using Math.floor. Math.floor has to look up the prototype
     * tree on every invocation, but ~~ is a direct bitwise operation.
     */
    tctx.fillRect(x - ~~(size / 2), y - ~~(size / 2), size, size);
  }
}

Eightbit शेडर डेमो

नीचे, हम Eightbit ओवरले को निकाल देते हैं और नीचे मूल ऐनिमेशन देखते हैं. "किल स्क्रीन" विकल्प आपको एक अजीब असर दिखाएगा, जिसके बारे में हमने गलत तरीके से सोर्स पिक्सल को सैंपल के तौर पर चुना है. जब Eightbit मोड का साइज़ नायाब आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) में बदला गया, तो हमने इसका इस्तेमाल "रिस्पॉन्सिव" ईस्टर एग के तौर पर किया. दुर्घटना की शुभकामनाएं!

कैनवस कंपोज़िटिंग

एक से ज़्यादा रेंडर चरणों और मास्क को मिलाकर, जो लक्ष्य हासिल किया जा सकता है वह एक शानदार है. हमने एक 2D मेटाबॉल बनाया है. इसमें, हर बॉल का अपना रेडियल ग्रेडिएंट होना चाहिए. साथ ही, उन ग्रेडिएंट को एक साथ मिला दिया जाना चाहिए जहां बॉल ओवरलैप होती हैं. (इसे नीचे दिए गए डेमो में देखा जा सकता है.)

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

कंपोज़िटिंग कोड का उदाहरण

हर काम को पूरा करने वाला कोड यहां दिया गया है:

// Loop through every ball and draw it and its gradient.
for (var i = 0; i < this.ballCount_; i++) {
  var target = this.world_.particles[i];

  // Set the size of the ball radial gradients.
  this.gradSize_ = target.radius * 4;

  this.gctx_.translate(target.pos.x - this.gradSize_,
    target.pos.y - this.gradSize_);

  var radGrad = this.gctx_.createRadialGradient(this.gradSize_,
    this.gradSize_, 0, this.gradSize_, this.gradSize_, this.gradSize_);

  radGrad.addColorStop(0, target['color'] + '1)');
  radGrad.addColorStop(1, target['color'] + '0)');

  this.gctx_.fillStyle = radGrad;
  this.gctx_.fillRect(0, 0, this.gradSize_ * 4, this.gradSize_ * 4);
};

इसके बाद, मास्किंग के लिए कैनवस सेट अप करें और ड्रॉ करें:

// Make the ball canvas the source of the mask.
this.pctx_.globalCompositeOperation = 'source-atop';

// Draw the ball canvas onto the gradient canvas to complete the mask.
this.pctx_.drawImage(this.gcanvas_, 0, 0);
this.ctx_.drawImage(this.paperCanvas_, 0, 0);

नतीजा

हमने अलग-अलग तरह की तकनीकों और टेक्नोलॉजी का इस्तेमाल किया (जैसे, कैनवस, SVG, सीएसएस ऐनिमेशन, JS ऐनिमेशन, वेब ऑडियो वगैरह). इससे यह प्रोजेक्ट डेवलप करने में बहुत आनंद आया.

आपको यहां जो दिखता है, उसके अलावा एक्सप्लोर करने के और भी तरीके हैं. I/O लोगो पर टैप करते रहें और सही क्रम से ज़्यादा छोटे-छोटे एक्सपेरिमेंट, गेम, ट्रिपी विज़ुअल, और कभी-कभी नाश्ते में मिलने वाली चीज़ें भी अनलॉक हो जाएंगी. हमारा सुझाव है कि बेहतरीन अनुभव के लिए, इसे अपने स्मार्टफ़ोन या टैबलेट पर आज़माएं.

शुरू करने के लिए यह रहा एक कॉम्बिनेशन: O-I-I-I-I-I-I-I-I. इसे अभी आज़माएं: google.com/io

ओपन सोर्स

हमने अपना कोड Apache 2.0 लाइसेंस ओपन सोर्स कर दिया है. यह आपको हमारे GitHub पर मिल सकता है: http://github.com/Instrument/google-io-2013.

क्रेडिट देखें

डेवलपर:

  • थॉमस रेनॉल्ड्स
  • ब्रायन हैफ़्टर
  • स्टेफ़नी हैचर
  • पॉल फ़ार्निंग

डिज़ाइनर:

  • डैन शेक्टर
  • सेज ब्राउन
  • काइल बेक

निर्माता:

  • एमी पास्कल
  • एंड्रिया नेल्सन