केस स्टडी - 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 फ़्रैगमेंट शेडर जैसा है, जहां सीन के हर पिक्सल की जांच की जाती है और उसमें बदलाव किया जाता है. आइए, इस बारे में ज़्यादा जानें.

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

कैनवस के पिक्सल को 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 मोड का साइज़ बदलकर, संभावित आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) में नहीं किया गया, तो हमने इसे एक "रिस्पॉन्सिव" ईस्टर अंडे के तौर पर इस्तेमाल किया. दुर्घटना का आनंद लें!

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

यह बहुत ही अद्भुत है कि कई रेंडर चरणों और मास्क को मिलाकर आप क्या कर सकते हैं. हमने एक 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 ऐनिमेशन, Web Audio वगैरह) ने प्रोजेक्ट को तैयार करने में काफ़ी मज़ेदार बनाया.

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

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

ओपन सोर्स

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

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

डेवलपर:

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

डिज़ाइनर:

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

निर्माता:

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